merged with upstream/master
1
TODO.txt
@ -71,6 +71,7 @@ Chat
|
||||
E [ ] add flags to allow distant chat from contact list only / everyone / noone / only signed ids.
|
||||
|
||||
Libretroshare
|
||||
E [ ] groups small packets in pqistreamer::handleoutgoing_locked(), and see if that removes some padding overhead
|
||||
E [ ] make sure at least one location is kept when removing old locations as it avoids lots of connection problems.
|
||||
M [ ] improve serialisation system. Lots of serialisation tasks (header, verifications, serialiser=>template, can be factored)
|
||||
M [ ] separate chat stuff from rsmsgs.h into rschat.h
|
||||
|
@ -1,5 +1,146 @@
|
||||
retroshare06 (0.6.0-1.XXXXXX~YYYYYY) YYYYYY; urgency=low
|
||||
|
||||
436f619 Gio Mon, 21 Dec 2015 17:34:53 +0100 getLocalAddresses collects loopback address too
|
||||
9d78bba Gio Mon, 21 Dec 2015 15:48:18 +0100 Guard getLocalAddresses debug
|
||||
9826c72 Gio Tue, 15 Dec 2015 16:37:27 +0100 added rs_inet_ntop crossplatform version of inet_ntop
|
||||
ca1a970 Gio Fri, 11 Dec 2015 11:44:26 +0100 Removed dead code
|
||||
1b2fa36 Gio Tue, 1 Dec 2015 23:38:44 +0100 Adapted getLocalAddresses() includes for windows
|
||||
5a541e7 Gio Mon, 26 Oct 2015 13:12:21 +0100 Removed unused getLocalInterfaces_ipv4
|
||||
77bcc99 Gio Mon, 26 Oct 2015 12:38:08 +0100 Added sockaddr_storage_dump(...), implemented sockaddr_storage_ipv6_iptostring(...)
|
||||
747a03a Gioacchino Mazzurco Mon, 9 Mar 2015 20:00:41 +0100 Substitute getpreferredinterface flawed logic with simpler getLocalAddresses still just one address used at moment
|
||||
f12b4a1 csoler Sun, 20 Dec 2015 20:53:11 -0500 Merge pull request #213 from csoler/v0.6-GxsDebug
|
||||
d4926cb csoler Sun, 20 Dec 2015 20:35:48 -0500 fixed a number of memory leaks in gxsnetservice. Used a class that auto-deletes retrieved items.
|
||||
ea137ad csoler Sun, 20 Dec 2015 19:07:04 -0500 fixed compilation on OSX pb in pqistreamer
|
||||
d50875b csoler Sat, 19 Dec 2015 21:38:55 -0500 Merge pull request #212 from csoler/v0.6-TrafficOptim
|
||||
141b799 csoler Sat, 19 Dec 2015 21:20:25 -0500 removed debug info
|
||||
124da6f csoler Sat, 19 Dec 2015 21:12:57 -0500 Merge pull request #210 from G10h4ck/pqicleaning
|
||||
d2e62b9 csoler Sat, 19 Dec 2015 19:18:53 -0500 Merge pull request #211 from csoler/v0.6-GxsDebug
|
||||
462f969 csoler Sat, 19 Dec 2015 19:15:48 -0500 merged with upstream/master
|
||||
ccc5f0f csoler Sat, 19 Dec 2015 19:04:49 -0500 improved debug info in rsgxsnetservice
|
||||
5fcaa36 csoler Sat, 19 Dec 2015 19:00:06 -0500 fixed some serialising bugs, and added proper notification of observer
|
||||
6910ad3 csoler Sat, 19 Dec 2015 17:38:52 -0500 added stats exchange system to gather number of posts in unsubscribed groups without the need to actually DL the messages (reduced bw a lot)
|
||||
b2c27a1 Gio Sat, 19 Dec 2015 22:10:07 +0100 Made pqiperson more readable evidence some strange code
|
||||
adfa94d electron128 Fri, 18 Dec 2015 19:05:18 +0100 added missing null check libresapi ApiPluginHandler
|
||||
b1b75a3 csoler Fri, 18 Dec 2015 08:07:00 -0500 fixed stupid bug causing cleanRejectedMessages() to be called continuously
|
||||
374aa65 csoler Thu, 17 Dec 2015 23:10:02 -0500 Merge pull request #209 from csoler/v0.6-GxsDebug
|
||||
e8b881b csoler Thu, 17 Dec 2015 23:08:02 -0500 added rejection list to gxsnetservice that is fed by calls from GenExchange system, to avoid infinitely re-downloading rejected messages due to bad reputation, bad signatures, missing ids, etc
|
||||
03896d7 defnax Fri, 18 Dec 2015 01:40:39 +0100 Added Sorting Menu entry.
|
||||
5b63762 electron128 Thu, 17 Dec 2015 18:59:30 +0100 removed useless code which caused lots of ChatId conversation warnings
|
||||
45fb453 csoler Thu, 17 Dec 2015 09:23:16 -0500 Merge pull request #208 from csoler/v0.6-GxsDebug
|
||||
55e66d0 csoler Thu, 17 Dec 2015 00:08:08 -0500 fixed mismatch between API versions causing signed groups created with old API to fail author signature checking
|
||||
dc034fe csoler Tue, 15 Dec 2015 23:17:35 -0500 removed debug info from GxsNetService
|
||||
0c4fd8e csoler Tue, 15 Dec 2015 18:13:40 -0500 added missing time-stamping of keys
|
||||
3617f9c csoler Tue, 15 Dec 2015 18:09:49 -0500 added NXS_NET_DEBUG_5 to print summary of incoming items
|
||||
92780b7 csoler Tue, 15 Dec 2015 18:01:03 -0500 added auto-request of missing GXS ids for group posts authors and group authors
|
||||
42bf996 defnax Tue, 15 Dec 2015 20:20:11 +0100 Sort lobby Parcipants by activity Set spacing between items
|
||||
f7ab3ad electron128 Tue, 15 Dec 2015 19:56:49 +0100 allow plugins to integrate into the JSON API
|
||||
8d886b8 csoler Tue, 15 Dec 2015 12:31:03 -0500 added regular timestamp-ing of GXS ids of group authors and group post authors for all subscribed groups
|
||||
3f132f2 csoler Mon, 14 Dec 2015 21:13:44 -0500 added missing timestamp at message creation time and group creation time
|
||||
e824a2f defnax Mon, 14 Dec 2015 16:32:00 +0100 update file extensions, patch by Agurer
|
||||
f702c94 csoler Sun, 13 Dec 2015 18:22:04 -0500 added a few methods to improve consistency between client and server sides, and force update of groups in some cases (such as database erased)
|
||||
96c2872 defnax Sun, 13 Dec 2015 18:20:56 +0100 Merge pull request #203 from realityfabric/master
|
||||
e003f56 realityfabric Sun, 13 Dec 2015 08:27:32 -0800 Made it so that sys/select.h is only included if the operating system is not Windows
|
||||
82d43eb csoler Sat, 12 Dec 2015 23:07:33 -0500 fixed a few bugs in packet packing in pqistreamer.
|
||||
ed7a261 csoler Sat, 12 Dec 2015 21:07:48 -0500 added check for NULL client update map in rsgxsnetservice::debugDump()
|
||||
ad1aafe csoler Sat, 12 Dec 2015 14:05:45 -0500 added missing mutex
|
||||
f6a84aa csoler Sat, 12 Dec 2015 11:52:48 -0500 added packet packing in pqistreamer. To be tested for improvement in bw
|
||||
534be72 csoler Fri, 11 Dec 2015 22:54:45 -0500 improved debug info in rsgxsnetservice.cc
|
||||
7be7233 csoler Fri, 11 Dec 2015 22:38:17 -0500 fixed a number of timing issues in rsgxsnetservice. To be tested.
|
||||
66d6f05 csoler Fri, 11 Dec 2015 19:01:20 -0500 added debugDump() method to display update timestamps of GXS groups on both sides
|
||||
16d815f csoler Fri, 11 Dec 2015 18:03:44 -0500 added protocol documentation in rsgxsnetservice.cc
|
||||
039db26 csoler Thu, 10 Dec 2015 22:25:09 -0500 improved debug info in rsgxsnetservice.cc
|
||||
c9af8e3 csoler Thu, 10 Dec 2015 22:08:28 -0500 improved debug info in rsgxsnetservice.cc
|
||||
3cb3662 csoler Thu, 10 Dec 2015 21:54:48 -0500 improved debug info in rsgxsnetservice.cc
|
||||
4f41605 csoler Thu, 10 Dec 2015 14:02:11 -0500 updated TODO list
|
||||
9db0524 csoler Thu, 10 Dec 2015 00:10:51 -0500 merged with upstream/master
|
||||
9843c1f csoler Thu, 10 Dec 2015 00:03:01 -0500 started updating debug info in gxsnetservice
|
||||
893f178 csoler Mon, 7 Dec 2015 23:09:44 -0500 changed GxsTunnel method for computing turtle hash, to avoid crashing old peers
|
||||
0957e70 csoler Mon, 7 Dec 2015 22:39:45 -0500 changed the method of computation for tunnel hashes in global router in order to avoid conflict with GxsTunnel service (breaks compatibility of distant message sending)
|
||||
4724007 defnax Mon, 7 Dec 2015 17:11:25 +0100 Changed Context Menu order issue: #187
|
||||
e2542a6 csoler Mon, 7 Dec 2015 10:02:04 -0500 added missing check after deserialisation of grouter item which caused a crash when receiving a malformed message data
|
||||
7cd880e electron128 Sat, 5 Dec 2015 17:00:57 +0100 removed member gxs_id from ChatId class, because ChatId now uses tunnel ids stored in distant_chat_id for distant chat. reverted naming confusion in in libresapi ChatHandler and fixed author of distant chat messages (distant chat is still unfinished)
|
||||
0ac76d6 csoler Sat, 5 Dec 2015 10:28:16 -0500 Merge pull request #188 from csoler/v0.6-SecuredTunnelService
|
||||
2a82ef5 csoler Fri, 4 Dec 2015 21:43:35 -0500 Merge pull request #186 from realityfabric/minor_edits
|
||||
9193d35 csoler Fri, 4 Dec 2015 21:24:51 -0500 merged with latest master before creating PR
|
||||
dcdf9df csoler Fri, 4 Dec 2015 14:14:13 -0500 merged
|
||||
88d3e98 csoler Fri, 4 Dec 2015 14:13:46 -0500 updated TODO list
|
||||
89693b1 csoler Fri, 4 Dec 2015 14:12:35 -0500 updated TODO list
|
||||
d2a9978 defnax Fri, 4 Dec 2015 19:56:56 +0100 Fixed Qt5 Fusion stylesheet on MessageComposer
|
||||
d32765c csoler Fri, 4 Dec 2015 10:53:14 -0500 updated TODO list
|
||||
318be3a csoler Fri, 4 Dec 2015 00:06:14 -0500 fixed a few bugs in distant chat: disabled history (for now), improved tunnel handling
|
||||
b198f1a csoler Thu, 3 Dec 2015 00:34:13 -0500 fixed some cleaning of remotely closed tunnels in GxsTunnelService
|
||||
9f56199 realityfabric Wed, 2 Dec 2015 06:18:17 -0800 fixed spelling errors in several files
|
||||
81b196d csoler Tue, 1 Dec 2015 23:40:35 -0500 added GUI to display authenticated tunnel info. Added counting of data sent/recvd.
|
||||
60d948b csoler Mon, 30 Nov 2015 21:52:15 -0500 added void GUI for authenticated tunnels
|
||||
266652f csoler Mon, 30 Nov 2015 21:02:12 -0500 put ifdefs around debug info in tunnel service
|
||||
12866cd csoler Mon, 30 Nov 2015 20:51:47 -0500 fixed a few bugs in new distant chat
|
||||
81ab43b csoler Mon, 30 Nov 2015 00:02:44 -0500 fixed GUI update of avatars and status for distant chat. Updated backend for new model. Fixed a few bugs in serialisation
|
||||
4b38b66 defnax Sun, 29 Nov 2015 17:28:05 +0100 update todo
|
||||
6951d73 csoler Sat, 28 Nov 2015 18:02:57 -0500 debugging of GxsTunnel service - fixed transport layer
|
||||
a29f15a csoler Sat, 28 Nov 2015 14:55:56 -0500 fixed compilation, added missing methods for new distant chat
|
||||
923efda defnax Sat, 28 Nov 2015 18:13:35 +0100 update todo list
|
||||
6ca49a2 csoler Fri, 27 Nov 2015 23:37:39 -0500 fixed serialisation methods for GxsTunnel service
|
||||
950f407 csoler Fri, 27 Nov 2015 14:16:57 -0500 updated todo
|
||||
a2e0f41 csoler Thu, 26 Nov 2015 20:40:06 -0500 updated GUI for new distant chat
|
||||
874f304 csoler Thu, 26 Nov 2015 14:48:30 -0500 Merge pull request #167 from G10h4ck/pqicleaning
|
||||
26f4523 csoler Wed, 25 Nov 2015 17:34:13 -0500 fixed compilation
|
||||
2f31dcf csoler Wed, 25 Nov 2015 09:27:56 -0500 Merge pull request #182 from ericthefish/master
|
||||
e8173bd Ivan Lucas Wed, 25 Nov 2015 10:33:28 +0000 Improve some of the wording of labels and information
|
||||
b552408 csoler Tue, 24 Nov 2015 21:57:59 -0500 added service part and item queues to GXS tunnel service
|
||||
397729b defnax Tue, 24 Nov 2015 19:41:13 +0100 Added to count downloads/uploads items Enabled to get copy the DHT label values via mouse Added counting on DHT Window & added context menu for DHT Tree, to copy IP addresses to clipboard
|
||||
36c68e7 csoler Tue, 24 Nov 2015 09:31:29 -0500 Merge pull request #181 from dali99/patch-1
|
||||
8eadba6 Daniel L.Olsen Tue, 24 Nov 2015 14:43:09 +0100 Fixed a small spelling error
|
||||
19f1a82 csoler Mon, 23 Nov 2015 22:31:31 -0500 fixed compilation
|
||||
85a9e4c csoler Mon, 23 Nov 2015 22:19:18 -0500 coding phase done. Needs testing/debugging
|
||||
5c0f1da csoler Sun, 22 Nov 2015 23:19:46 -0500 saving ongoing work. Implementation almoast finished.
|
||||
8df9d4b csoler Sun, 22 Nov 2015 11:36:14 -0500 added some doc for tunnel service. Fixed a few function prototypes
|
||||
b247056 csoler Sat, 21 Nov 2015 15:08:43 -0500 Merge pull request #179 from sirjenster/osx
|
||||
c89ff9f defnax Sat, 21 Nov 2015 13:47:50 +0100 Added nickname column to pending packets & context menu action to view details Fixed ui layout.
|
||||
2e76cc6 defnax Sat, 21 Nov 2015 12:32:55 +0100 Fixed DHT icon
|
||||
4b84767 electron128 Sat, 21 Nov 2015 11:57:50 +0100 hide network mode selection in quick start wizard if node is a hidden node
|
||||
1f9cb27 Jenster Fri, 20 Nov 2015 20:40:00 -0800 other_osx_patch
|
||||
699299a Jenster Fri, 20 Nov 2015 08:10:59 -0800 latest OSX patches
|
||||
47328a4 defnax Thu, 19 Nov 2015 19:11:02 +0100 Merge branch 'master' of https://github.com/RetroShare/RetroShare
|
||||
4dacd9a defnax Thu, 19 Nov 2015 19:08:47 +0100 Added Ban/Unban Context menu actions for People list.
|
||||
df6abc8 csoler Thu, 19 Nov 2015 10:54:38 -0500 merged before commit
|
||||
fa4308e csoler Thu, 19 Nov 2015 10:52:53 -0500 updated TODO list
|
||||
5404cda defnax Thu, 19 Nov 2015 12:05:52 +0100 Added Forum reply with plaintext quote (by anmo)
|
||||
cb97ce6 csoler Wed, 18 Nov 2015 23:56:35 -0500 half-way through GxsTunnel service
|
||||
e3d12b8 defnax Wed, 18 Nov 2015 21:24:38 +0100 Disabled Fontmetrics on RemoteDirModel Columns, it causes unusable very small column height.
|
||||
7bcbc70 csoler Tue, 17 Nov 2015 18:12:46 -0500 added interface file for gxs tunnel service
|
||||
cb8b814 csoler Tue, 17 Nov 2015 18:11:00 -0500 added gxs tunnel service, based on distant chat code. Does not compile yet
|
||||
701f1ce defnax Tue, 17 Nov 2015 17:33:25 +0100 Fixed counting thx to sehraf
|
||||
01f3db7 defnax Tue, 17 Nov 2015 15:58:22 +0100 Added to count identity items on People
|
||||
17dc7c7 csoler Mon, 16 Nov 2015 23:56:37 -0500 Merge pull request #68 from chozabu/systray_tweaks
|
||||
0751876 csoler Mon, 16 Nov 2015 14:06:45 -0500 changed MAX_CACHE_SIZE to not use the default (fixes previous commit that was wrong)
|
||||
b44d08a csoler Sat, 14 Nov 2015 21:18:26 -0500 changed GXS id cache size to 5000 instead of 100. Should help a lot GXS id handling
|
||||
e0e3621 csoler Sat, 14 Nov 2015 21:16:30 -0500 added missing wily for ubuntu packages
|
||||
8238c82 electron128 Sun, 8 Nov 2015 10:34:31 +0100 fix integer size issue in ContentTypes.cpp which can lead to an infinite loop
|
||||
0a21d92 electron128 Sun, 8 Nov 2015 10:23:45 +0100 Merge pull request #176 from hunbernd/feature/webui-download-enhancements
|
||||
3991b6f csoler Sun, 8 Nov 2015 01:38:37 -0500 Merge pull request #175 from sembrestels/patch-1
|
||||
0ef9b22 hunbernd Sun, 8 Nov 2015 01:52:23 +0100 Some fixes: * using ContentTypes to resolve static files too * added some default content types, in the case of mime.types file not present * resolve extensions with upper case letters in them
|
||||
c6ad0d4 defnax Sun, 8 Nov 2015 01:07:59 +0100 Merge pull request #122 from PhenomRetroShare/Fix_PrioritySpeedMenuForDownloadFiles
|
||||
b847eea hunbernd Sat, 7 Nov 2015 00:33:37 +0100 Webui: Added video support into MediaPlayerWidget
|
||||
37353e5 Sem Sat, 7 Nov 2015 19:41:55 +0100 Adding libsqlcipher-dev package
|
||||
88e1dc0 hunbernd Fri, 6 Nov 2015 22:51:52 +0100 Webui: added links on file names Browsers can play partial files with built-in player, or save files to disk.
|
||||
ce40760 hunbernd Fri, 6 Nov 2015 22:05:35 +0100 Added support for all common content-types into MHDFilestreamerHandler File extension --> content-type associations are read from mime.types file.
|
||||
413cee3 electron128 Fri, 6 Nov 2015 19:50:59 +0100 set buffer size for reading config signatures to the size of the computed signature. This fixes the load of the configuration for locations created after 8e6c7cd.
|
||||
c41f98c defnax Fri, 6 Nov 2015 01:58:30 +0100 Merge pull request #86 from PhenomRetroShare/Fix_Win7_32bCompilationFromScratch
|
||||
af35af1 csoler Thu, 5 Nov 2015 10:06:43 -0500 Merge pull request #174 from AsamK/hide_debug
|
||||
0e2417d AsamK Wed, 9 Sep 2015 16:18:47 +0200 Hide debug messages from p3historymgr
|
||||
75d462e csoler Thu, 5 Nov 2015 03:22:47 -0500 Merge pull request #173 from mr-alice/master
|
||||
93368aa mr-alice Wed, 4 Nov 2015 21:08:31 -0500 show or hide ID chooser in message box depending on destination of message
|
||||
3a2b5f1 defnax Wed, 4 Nov 2015 23:47:12 +0100 calculate correct icon size for the status icon
|
||||
bdc70c6 hunbernd Wed, 4 Nov 2015 22:02:02 +0100 Allow arbitrary name in fstream url after hash. /fstream/fileshash/name Useful for creating file links that contains the original file name.
|
||||
c4563db defnax Wed, 4 Nov 2015 17:06:44 +0100 Merge branch 'master' of https://github.com/RetroShare/RetroShare
|
||||
2a998c1 defnax Wed, 4 Nov 2015 17:05:39 +0100 Added new higher resolution bullet icons with better quality
|
||||
f9e61dd csoler Sat, 31 Oct 2015 13:32:19 -0400 Merge pull request #169 from AsamK/add_missing_return
|
||||
f06d150 AsamK Sat, 31 Oct 2015 15:13:47 +0100 Add missing return
|
||||
|
||||
-- Cyril Soler <csoler@users.sourceforge.net> Fri, 30 Oct 2015 20:00:00 +0100
|
||||
|
||||
retroshare06 (0.6.0-1.20151030.3c70c5cc~trusty) trusty; urgency=low
|
||||
|
||||
2a5fe4d csoler 30 Oct 2015 21:12:47 -0400 merge before push
|
||||
1bc2892 csoler 30 Oct 2015 21:11:44 -0400 removed some debug info
|
||||
6554362 defnax 30 Oct 2015 15:51:13 +0100 Fixed Layout
|
||||
@ -1851,7 +1992,7 @@ retroshare (0.5.4-0.6685~precise) precise; urgency=low
|
||||
|
||||
|
||||
* Bug fixes
|
||||
- Added missing location from cert when addign new friend
|
||||
- Added missing location from cert when adding new friend
|
||||
- Added missing IndicateConfigChanged to p3PeerMgrIMPL::setDynDNS
|
||||
- Fixed crash when closing the main window without the setting "Minimize to Tray Icon"
|
||||
- Renamed the setting "Do not Minimize to Tray Icon" to "Minimize to Tray
|
||||
@ -2925,7 +3066,7 @@ retroshare (0.5.3-0.4953~natty) natty; urgency=low
|
||||
- Fixed Download toaster (utf8 in file name, use QDesktopServices vs RsUrlHandler for collections, fixed
|
||||
crash after opening a collection) (Patch from AsamK).
|
||||
- fixed utf8 chars in certificate links (Patch from AsamK)
|
||||
- removed cache adding strategy to DL queue that was O(n^2). Now addign cache at the end of the queue
|
||||
- removed cache adding strategy to DL queue that was O(n^2). Now adding cache at the end of the queue
|
||||
- Fixed bug when the user clicks on a link without http:// in a QTextBrowser. This link was
|
||||
oppened directly in RetroShare.
|
||||
- Attempted fix for maintaining External Port in Manual Forwarded Mode.
|
||||
|
@ -32,7 +32,9 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#ifndef WIN32
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
/***
|
||||
* #define UDP_ENABLE_BROADCAST 1
|
||||
|
41
libresapi/src/api/ApiPluginHandler.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
#include "ApiPluginHandler.h"
|
||||
|
||||
namespace resource_api
|
||||
{
|
||||
|
||||
ApiPluginHandler::ApiPluginHandler(StateTokenServer* statetokenserver, const RsPlugInInterfaces& ifaces)
|
||||
{
|
||||
for(int i = 0; i < ifaces.mPluginHandler->nbPlugins(); i++)
|
||||
{
|
||||
RsPlugin* plugin = ifaces.mPluginHandler->plugin(i);
|
||||
// if plugin is not loaded, pointer is null
|
||||
if(plugin == 0)
|
||||
continue;
|
||||
std::string entrypoint;
|
||||
ResourceRouter* child = plugin->new_resource_api_handler(ifaces, statetokenserver, entrypoint);
|
||||
if(child != 0)
|
||||
{
|
||||
mChildren.push_back(child);
|
||||
if(isNameUsed(entrypoint))
|
||||
{
|
||||
std::cerr << "Cannot add plugin api entry point with name=" << entrypoint << ", becaus ethis name is already in use!" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Added libresapi plugin with entrypoint " << entrypoint << std::endl;
|
||||
addResourceHandler(entrypoint, child, &ResourceRouter::handleRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ApiPluginHandler::~ApiPluginHandler()
|
||||
{
|
||||
for(std::vector<ResourceRouter*>::iterator vit = mChildren.begin(); vit != mChildren.end(); ++vit)
|
||||
{
|
||||
delete *vit;
|
||||
}
|
||||
mChildren.clear();
|
||||
}
|
||||
|
||||
} // namespace resource_api
|
20
libresapi/src/api/ApiPluginHandler.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "ResourceRouter.h"
|
||||
#include <retroshare/rsplugin.h>
|
||||
|
||||
namespace resource_api
|
||||
{
|
||||
|
||||
// forwards all incoming requests to retroshare plugins
|
||||
class ApiPluginHandler: public ResourceRouter
|
||||
{
|
||||
public:
|
||||
ApiPluginHandler(StateTokenServer* statetokenserver, const RsPlugInInterfaces& ifaces);
|
||||
virtual ~ApiPluginHandler();
|
||||
|
||||
private:
|
||||
std::vector<ResourceRouter*> mChildren;
|
||||
};
|
||||
|
||||
} // namespace resource_api
|
@ -13,6 +13,8 @@
|
||||
#include "JsonStream.h"
|
||||
#include "StateTokenServer.h" // for the state token serialisers
|
||||
|
||||
#include "ApiPluginHandler.h"
|
||||
|
||||
/*
|
||||
data types in json http://json.org/
|
||||
string (utf-8 unicode)
|
||||
@ -226,10 +228,11 @@ public:
|
||||
mPeersHandler(sts, ifaces.mNotify, ifaces.mPeers, ifaces.mMsgs),
|
||||
mIdentityHandler(ifaces.mIdentity),
|
||||
mForumHandler(ifaces.mGxsForums),
|
||||
mServiceControlHandler(rsServiceControl), // TODO: don't use global variable here
|
||||
mServiceControlHandler(ifaces.mServiceControl),
|
||||
mFileSearchHandler(sts, ifaces.mNotify, ifaces.mTurtle, ifaces.mFiles),
|
||||
mTransfersHandler(sts, ifaces.mFiles),
|
||||
mChatHandler(sts, ifaces.mNotify, ifaces.mMsgs, ifaces.mPeers, ifaces.mIdentity, &mPeersHandler)
|
||||
mChatHandler(sts, ifaces.mNotify, ifaces.mMsgs, ifaces.mPeers, ifaces.mIdentity, &mPeersHandler),
|
||||
mApiPluginHandler(sts, ifaces)
|
||||
{
|
||||
// the dynamic cast is to not confuse the addResourceHandler template like this:
|
||||
// addResourceHandler(derived class, parent class)
|
||||
@ -249,6 +252,8 @@ public:
|
||||
&TransfersHandler::handleRequest);
|
||||
router.addResourceHandler("chat", dynamic_cast<ResourceRouter*>(&mChatHandler),
|
||||
&ChatHandler::handleRequest);
|
||||
router.addResourceHandler("apiplugin", dynamic_cast<ResourceRouter*>(&mApiPluginHandler),
|
||||
&ChatHandler::handleRequest);
|
||||
}
|
||||
|
||||
PeersHandler mPeersHandler;
|
||||
@ -258,6 +263,7 @@ public:
|
||||
FileSearchHandler mFileSearchHandler;
|
||||
TransfersHandler mTransfersHandler;
|
||||
ChatHandler mChatHandler;
|
||||
ApiPluginHandler mApiPluginHandler;
|
||||
};
|
||||
|
||||
ApiServer::ApiServer():
|
||||
|
@ -91,7 +91,7 @@ StreamBase& operator << (StreamBase& left, ChatHandler::ChatInfo& info)
|
||||
left << makeKeyValueReference("remote_author_id", info.remote_author_id)
|
||||
<< makeKeyValueReference("remote_author_name", info.remote_author_name)
|
||||
<< makeKeyValueReference("is_broadcast", info.is_broadcast)
|
||||
<< makeKeyValueReference("is_gxs_id", info.is_gxs_id)
|
||||
<< makeKeyValueReference("is_distant_chat_id", info.is_distant_chat_id)
|
||||
<< makeKeyValueReference("is_lobby", info.is_lobby)
|
||||
<< makeKeyValueReference("is_peer", info.is_peer);
|
||||
return left;
|
||||
@ -173,17 +173,14 @@ void ChatHandler::tick()
|
||||
}
|
||||
}
|
||||
|
||||
ChatId id = ChatId::makeBroadcastId();
|
||||
{
|
||||
Lobby l;
|
||||
l.id = id.toLobbyId();
|
||||
l.name = "BroadCast";
|
||||
l.topic = "Retroshare broadcast chat: messages are sent to all connected friends.";
|
||||
l.subscribed = true;
|
||||
l.auto_subscribe = false;
|
||||
l.is_private = false;
|
||||
l.is_broadcast = true;
|
||||
l.gxs_id = id.toGxsId();
|
||||
lobbies.push_back(l);
|
||||
}
|
||||
|
||||
@ -225,12 +222,20 @@ void ChatHandler::tick()
|
||||
author_id = msg.broadcast_peer_id.toStdString();
|
||||
author_name = mRsPeers->getPeerName(msg.broadcast_peer_id);
|
||||
}
|
||||
else if(msg.chat_id.isGxsId())
|
||||
else if(msg.chat_id.isDistantChatId())
|
||||
{
|
||||
author_id = msg.chat_id.toGxsId().toStdString();
|
||||
RsIdentityDetails details;
|
||||
if(!gxs_id_failed && mRsIdentity->getIdDetails(msg.chat_id.toGxsId(), details))
|
||||
DistantChatPeerInfo dcpinfo ;
|
||||
|
||||
if(!rsMsgs->getDistantChatStatus(msg.chat_id.toDistantChatId(),dcpinfo))
|
||||
{
|
||||
std::cerr << "(EE) cannot get info for distant chat peer " << msg.chat_id.toDistantChatId() << std::endl;
|
||||
continue ;
|
||||
}
|
||||
|
||||
RsIdentityDetails details;
|
||||
if(!gxs_id_failed && mRsIdentity->getIdDetails(msg.incoming? dcpinfo.to_id: dcpinfo.own_id, details))
|
||||
{
|
||||
author_id = details.mId.toStdString();
|
||||
author_name = details.mNickname;
|
||||
}
|
||||
else
|
||||
@ -278,7 +283,7 @@ void ChatHandler::tick()
|
||||
{
|
||||
ChatInfo info;
|
||||
info.is_broadcast = msg.chat_id.isBroadcast();
|
||||
info.is_gxs_id = msg.chat_id.isGxsId();
|
||||
info.is_distant_chat_id = msg.chat_id.isDistantChatId();
|
||||
info.is_lobby = msg.chat_id.isLobbyId();
|
||||
info.is_peer = msg.chat_id.isPeerId();
|
||||
if(msg.chat_id.isLobbyId())
|
||||
@ -289,12 +294,15 @@ void ChatHandler::tick()
|
||||
info.remote_author_name = vit->name;
|
||||
}
|
||||
}
|
||||
else if(msg.chat_id.isGxsId())
|
||||
else if(msg.chat_id.isDistantChatId())
|
||||
{
|
||||
RsIdentityDetails details;
|
||||
if(!gxs_id_failed && mRsIdentity->getIdDetails(msg.chat_id.toGxsId(), details))
|
||||
DistantChatPeerInfo dcpinfo ;
|
||||
|
||||
if(!gxs_id_failed && rsMsgs->getDistantChatStatus(msg.chat_id.toDistantChatId(),dcpinfo)
|
||||
&& mRsIdentity->getIdDetails(msg.incoming? dcpinfo.to_id: dcpinfo.own_id, details))
|
||||
{
|
||||
info.remote_author_id = msg.chat_id.toGxsId().toStdString();
|
||||
info.remote_author_id = details.mId.toStdString();
|
||||
info.remote_author_name = details.mNickname;
|
||||
}
|
||||
else
|
||||
|
@ -84,7 +84,7 @@ public:
|
||||
class ChatInfo{
|
||||
public:
|
||||
bool is_broadcast;
|
||||
bool is_gxs_id;
|
||||
bool is_distant_chat_id;
|
||||
bool is_lobby;
|
||||
bool is_peer;
|
||||
std::string remote_author_id;
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <retroshare/rsdisc.h>
|
||||
#include <retroshare/rsdht.h>
|
||||
#include <retroshare/rsnotify.h>
|
||||
#include <retroshare/rsservicecontrol.h>
|
||||
|
||||
#include <retroshare/rsidentity.h>
|
||||
#include <retroshare/rsgxscircles.h>
|
||||
@ -28,6 +29,8 @@ bool getPluginInterfaces(RsPlugInInterfaces& interfaces)
|
||||
interfaces.mDisc = rsDisc;
|
||||
interfaces.mDht = rsDht;
|
||||
interfaces.mNotify = rsNotify;
|
||||
interfaces.mServiceControl = rsServiceControl;
|
||||
interfaces.mPluginHandler = rsPlugins;
|
||||
|
||||
// gxs
|
||||
interfaces.mGxsDir = "";
|
||||
|
@ -55,4 +55,17 @@ ResponseTask* ResourceRouter::handleRequest(Request& req, Response& resp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ResourceRouter::isNameUsed(std::string name)
|
||||
{
|
||||
std::vector<std::pair<std::string, HandlerBase*> >::iterator vit;
|
||||
for(vit = mHandlers.begin(); vit != mHandlers.end(); vit++)
|
||||
{
|
||||
if(vit->first == name)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace resource_api
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "ApiTypes.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace resource_api
|
||||
{
|
||||
@ -20,6 +21,8 @@ public:
|
||||
void addResourceHandler(std::string name, T* instance, ResponseTask* (T::*callback)(Request& req, Response& resp));
|
||||
template <class T>
|
||||
void addResourceHandler(std::string name, T* instance, void (T::*callback)(Request& req, Response& resp));
|
||||
|
||||
bool isNameUsed(std::string name);
|
||||
private:
|
||||
class HandlerBase
|
||||
{
|
||||
@ -61,6 +64,10 @@ private:
|
||||
template <class T>
|
||||
void ResourceRouter::addResourceHandler(std::string name, T* instance, ResponseTask* (T::*callback)(Request& req, Response& resp))
|
||||
{
|
||||
if(isNameUsed(name))
|
||||
{
|
||||
std::cerr << "ResourceRouter::addResourceHandler ERROR: name=" << name << " alerady in use. Not adding new Handler!" << std::endl;
|
||||
}
|
||||
Handler<T>* handler = new Handler<T>();
|
||||
handler->instance = instance;
|
||||
handler->method = callback;
|
||||
@ -69,6 +76,10 @@ void ResourceRouter::addResourceHandler(std::string name, T* instance, ResponseT
|
||||
template <class T>
|
||||
void ResourceRouter::addResourceHandler(std::string name, T* instance, void (T::*callback)(Request& req, Response& resp))
|
||||
{
|
||||
if(isNameUsed(name))
|
||||
{
|
||||
std::cerr << "ResourceRouter::addResourceHandler ERROR: name=" << name << " alerady in use. Not adding new Handler!" << std::endl;
|
||||
}
|
||||
InstantResponseHandler<T>* handler = new InstantResponseHandler<T>();
|
||||
handler->instance = instance;
|
||||
handler->method = callback;
|
||||
|
@ -65,7 +65,8 @@ SOURCES += \
|
||||
api/ChatHandler.cpp \
|
||||
api/LivereloadHandler.cpp \
|
||||
api/TmpBlobStore.cpp \
|
||||
util/ContentTypes.cpp
|
||||
util/ContentTypes.cpp \
|
||||
api/ApiPluginHandler.cpp
|
||||
|
||||
HEADERS += \
|
||||
api/ApiServer.h \
|
||||
@ -89,4 +90,5 @@ HEADERS += \
|
||||
api/ChatHandler.h \
|
||||
api/LivereloadHandler.h \
|
||||
api/TmpBlobStore.h \
|
||||
util/ContentTypes.h
|
||||
util/ContentTypes.h \
|
||||
api/ApiPluginHandler.h
|
||||
|
@ -25,35 +25,38 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <turtle/turtleclientservice.h>
|
||||
#include <chat/rschatitems.h>
|
||||
#include <retroshare/rsmsgs.h>
|
||||
#include <retroshare/rsgxstunnel.h>
|
||||
|
||||
class RsGixs ;
|
||||
|
||||
static const uint32_t DISTANT_CHAT_AES_KEY_SIZE = 16 ;
|
||||
|
||||
class DistantChatService: public RsTurtleClientService
|
||||
class DistantChatService: public RsGxsTunnelService::RsGxsTunnelClientService
|
||||
{
|
||||
public:
|
||||
DistantChatService(RsGixs *pids)
|
||||
: mGixs(pids), mDistantChatMtx("distant chat")
|
||||
// So, public interface only uses DistandChatPeerId, but internally, this is converted into a RsGxsTunnelService::RsGxsTunnelId
|
||||
|
||||
|
||||
DistantChatService() : mDistantChatMtx("distant chat")
|
||||
{
|
||||
mTurtle = NULL ;
|
||||
mGxsTunnels = NULL ;
|
||||
}
|
||||
|
||||
void flush() ;
|
||||
// Overloaded methods from RsGxsTunnelClientService
|
||||
|
||||
virtual void connectToTurtleRouter(p3turtle *) ;
|
||||
virtual void connectToGxsTunnelService(RsGxsTunnelService *tunnel_service) ;
|
||||
|
||||
// Creates the invite if the public key of the distant peer is available.
|
||||
// Om success, stores the invite in the map above, so that we can respond to tunnel requests.
|
||||
//
|
||||
bool initiateDistantChatConnexion(const RsGxsId& to_gxs_id,const RsGxsId &from_gxs_id, uint32_t &error_code) ;
|
||||
bool closeDistantChatConnexion(const RsGxsId& pid) ;
|
||||
virtual bool getDistantChatStatus(const RsGxsId &gxs_id,uint32_t &status, RsGxsId *from_gxs_id=NULL) ;
|
||||
bool initiateDistantChatConnexion(const RsGxsId& to_gxs_id, const RsGxsId &from_gxs_id, DistantChatPeerId& dcpid, uint32_t &error_code) ;
|
||||
bool closeDistantChatConnexion(const DistantChatPeerId &tunnel_id) ;
|
||||
|
||||
// derived in p3ChatService
|
||||
virtual bool getDistantChatStatus(const DistantChatPeerId &tunnel_id, DistantChatPeerInfo& cinfo) ;
|
||||
|
||||
// derived in p3ChatService, so as to pass down some info
|
||||
virtual void handleIncomingItem(RsItem *) = 0;
|
||||
virtual bool handleRecvChatMsgItem(RsChatMsgItem *ci)=0 ;
|
||||
|
||||
@ -62,78 +65,25 @@ public:
|
||||
void handleRecvChatStatusItem(RsChatStatusItem *cs) ;
|
||||
|
||||
private:
|
||||
class DistantChatPeerInfo
|
||||
struct DistantChatContact
|
||||
{
|
||||
public:
|
||||
DistantChatPeerInfo() : last_contact(0), last_keep_alive_sent(0), status(0), direction(0)
|
||||
{
|
||||
memset(aes_key, 0, DISTANT_CHAT_AES_KEY_SIZE);
|
||||
}
|
||||
|
||||
time_t last_contact ; // used to keep track of working connexion
|
||||
time_t last_keep_alive_sent ; // last time we sent a keep alive packet.
|
||||
|
||||
unsigned char aes_key[DISTANT_CHAT_AES_KEY_SIZE] ;
|
||||
|
||||
uint32_t status ; // info: do we have a tunnel ?
|
||||
RsPeerId virtual_peer_id; // given by the turtle router. Identifies the tunnel.
|
||||
RsGxsId own_gxs_id ; // gxs id we're using to talk.
|
||||
RsTurtleGenericTunnelItem::Direction direction ; // specifiec wether we are client(managing the tunnel) or server.
|
||||
RsGxsId from_id ;
|
||||
RsGxsId to_id ;
|
||||
};
|
||||
|
||||
class DistantChatDHInfo
|
||||
{
|
||||
public:
|
||||
DistantChatDHInfo() : dh(0), direction(0), status(0) {}
|
||||
|
||||
DH *dh ;
|
||||
RsGxsId gxs_id ;
|
||||
RsTurtleGenericTunnelItem::Direction direction ;
|
||||
uint32_t status ;
|
||||
TurtleFileHash hash ;
|
||||
};
|
||||
|
||||
// This maps contains the current peers to talk to with distant chat.
|
||||
//
|
||||
std::map<RsGxsId, DistantChatPeerInfo> _distant_chat_contacts ; // current peers we can talk to
|
||||
std::map<RsPeerId,DistantChatDHInfo> _distant_chat_virtual_peer_ids ; // current virtual peers. Used to figure out tunnels, etc.
|
||||
std::map<DistantChatPeerId, DistantChatContact> mDistantChatContacts ; // current peers we can talk to
|
||||
|
||||
// List of items to be sent asap. Used to store items that we cannot pass directly to
|
||||
// sendTurtleData(), because of Mutex protection.
|
||||
// Overloaded from RsGxsTunnelClientService
|
||||
|
||||
std::list<RsChatItem*> pendingDistantChatItems ;
|
||||
virtual void notifyTunnelStatus(const RsGxsTunnelService::RsGxsTunnelId& tunnel_id,uint32_t tunnel_status) ;
|
||||
virtual void receiveData(const RsGxsTunnelService::RsGxsTunnelId& id,unsigned char *data,uint32_t data_size) ;
|
||||
|
||||
// Overloaded from RsTurtleClientService
|
||||
// Utility functions.
|
||||
|
||||
virtual bool handleTunnelRequest(const RsFileHash &hash,const RsPeerId& peer_id) ;
|
||||
virtual void receiveTurtleData(RsTurtleGenericTunnelItem *item,const RsFileHash& hash,const RsPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction) ;
|
||||
void addVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&,RsTurtleGenericTunnelItem::Direction dir) ;
|
||||
void removeVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&) ;
|
||||
void markDistantChatAsClosed(const RsGxsId &gxs_id) ;
|
||||
void startClientDistantChatConnection(const RsGxsId &to_gxs_id,const RsGxsId& from_gxs_id) ;
|
||||
void locked_restartDHSession(const RsPeerId &virtual_peer_id, const RsGxsId &own_gxs_id) ;
|
||||
void markDistantChatAsClosed(const DistantChatPeerId& dcpid) ;
|
||||
|
||||
//bool getHashFromVirtualPeerId(const TurtleVirtualPeerId& pid,RsFileHash& hash) ;
|
||||
|
||||
static TurtleFileHash hashFromGxsId(const RsGxsId& destination) ;
|
||||
static RsGxsId gxsIdFromHash(const TurtleFileHash& sum) ;
|
||||
|
||||
void handleRecvDHPublicKey(RsChatDHPublicKeyItem *item) ;
|
||||
bool locked_sendDHPublicKey(const DH *dh, const RsGxsId &own_gxs_id, const RsPeerId &virtual_peer_id) ;
|
||||
bool locked_initDHSessionKey(DH *&dh);
|
||||
DistantChatPeerId virtualPeerIdFromHash(const TurtleFileHash& hash ) ; // ... and to a hash for p3turtle
|
||||
|
||||
|
||||
// Utility functions
|
||||
|
||||
void sendTurtleData(RsChatItem *) ;
|
||||
void sendEncryptedTurtleData(const uint8_t *buff,uint32_t rssize,const RsGxsId &gxs_id) ;
|
||||
bool handleEncryptedData(const uint8_t *data_bytes,uint32_t data_size,const TurtleFileHash& hash,const RsPeerId& virtual_peer_id) ;
|
||||
|
||||
static TurtleFileHash hashFromVirtualPeerId(const DistantChatPeerId& peerId) ; // converts IDs so that we can talk to RsPeerId from outside
|
||||
|
||||
p3turtle *mTurtle ;
|
||||
RsGixs *mGixs ;
|
||||
RsGxsTunnelService *mGxsTunnels ;
|
||||
|
||||
RsMutex mDistantChatMtx ;
|
||||
};
|
||||
|
@ -1288,7 +1288,7 @@ void DistributedChatService::handleRecvLobbyInvite(RsChatLobbyInviteItem *item)
|
||||
else
|
||||
std::cerr << " : Match!" << std::endl;
|
||||
|
||||
std::cerr << " Addign new friend " << item->PeerId() << " to lobby." << std::endl;
|
||||
std::cerr << " Adding new friend " << item->PeerId() << " to lobby." << std::endl;
|
||||
#endif
|
||||
|
||||
it->second.participating_friends.insert(item->PeerId()) ;
|
||||
|
@ -54,7 +54,7 @@ static const uint32_t MAX_AVATAR_JPEG_SIZE = 32767; // Maximum size
|
||||
// Images are 96x96, which makes approx. 27000 bytes uncompressed.
|
||||
|
||||
p3ChatService::p3ChatService(p3ServiceControl *sc,p3IdService *pids, p3LinkMgr *lm, p3HistoryMgr *historyMgr)
|
||||
:DistantChatService(pids),DistributedChatService(getServiceInfo().mServiceType,sc,historyMgr,pids), mChatMtx("p3ChatService"),mServiceCtrl(sc), mLinkMgr(lm) , mHistoryMgr(historyMgr)
|
||||
: DistributedChatService(getServiceInfo().mServiceType,sc,historyMgr,pids), mChatMtx("p3ChatService"),mServiceCtrl(sc), mLinkMgr(lm) , mHistoryMgr(historyMgr)
|
||||
{
|
||||
_serializer = new RsChatSerialiser() ;
|
||||
|
||||
@ -86,7 +86,7 @@ int p3ChatService::tick()
|
||||
receiveChatQueue();
|
||||
|
||||
DistributedChatService::flush() ;
|
||||
DistantChatService::flush() ;
|
||||
//DistantChatService::flush() ;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -217,24 +217,25 @@ void p3ChatService::sendStatusString(const ChatId& id , const std::string& statu
|
||||
sendLobbyStatusString(id.toLobbyId(),status_string) ;
|
||||
else if(id.isBroadcast())
|
||||
sendGroupChatStatusString(status_string);
|
||||
else if(id.isPeerId() || id.isGxsId())
|
||||
{
|
||||
RsChatStatusItem *cs = new RsChatStatusItem ;
|
||||
else if(id.isPeerId() || id.isDistantChatId())
|
||||
{
|
||||
RsChatStatusItem *cs = new RsChatStatusItem ;
|
||||
|
||||
cs->status_string = status_string ;
|
||||
cs->flags = RS_CHAT_FLAG_PRIVATE ;
|
||||
RsPeerId vpid;
|
||||
if(id.isGxsId())
|
||||
vpid = RsPeerId(id.toGxsId());
|
||||
else
|
||||
vpid = id.toPeerId();
|
||||
cs->PeerId(vpid);
|
||||
cs->status_string = status_string ;
|
||||
cs->flags = RS_CHAT_FLAG_PRIVATE ;
|
||||
RsPeerId vpid;
|
||||
if(id.isDistantChatId())
|
||||
vpid = RsPeerId(id.toDistantChatId());
|
||||
else
|
||||
vpid = id.toPeerId();
|
||||
|
||||
cs->PeerId(vpid);
|
||||
|
||||
#ifdef CHAT_DEBUG
|
||||
std::cerr << "sending chat status packet:" << std::endl ;
|
||||
cs->print(std::cerr) ;
|
||||
std::cerr << "sending chat status packet:" << std::endl ;
|
||||
cs->print(std::cerr) ;
|
||||
#endif
|
||||
sendChatItem(cs);
|
||||
sendChatItem(cs);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -284,12 +285,14 @@ void p3ChatService::checkSizeAndSendMessage(RsChatMsgItem *msg)
|
||||
|
||||
bool p3ChatService::isOnline(const RsPeerId& pid)
|
||||
{
|
||||
// check if the id is a tunnel id or a peer id.
|
||||
uint32_t status ;
|
||||
if(getDistantChatStatus(RsGxsId(pid),status))
|
||||
return status == RS_DISTANT_CHAT_STATUS_CAN_TALK ;
|
||||
// check if the id is a tunnel id or a peer id.
|
||||
|
||||
DistantChatPeerInfo dcpinfo;
|
||||
|
||||
if(getDistantChatStatus(DistantChatPeerId(pid),dcpinfo))
|
||||
return dcpinfo.status == RS_DISTANT_CHAT_STATUS_CAN_TALK ;
|
||||
else
|
||||
return mServiceCtrl->isPeerConnected(getServiceInfo().mServiceType, pid);
|
||||
return mServiceCtrl->isPeerConnected(getServiceInfo().mServiceType, pid);
|
||||
}
|
||||
|
||||
bool p3ChatService::sendChat(ChatId destination, std::string msg)
|
||||
@ -301,7 +304,7 @@ bool p3ChatService::sendChat(ChatId destination, std::string msg)
|
||||
sendPublicChat(msg);
|
||||
return true;
|
||||
}
|
||||
else if(destination.isPeerId()==false && destination.isGxsId()==false)
|
||||
else if(destination.isPeerId()==false && destination.isDistantChatId()==false)
|
||||
{
|
||||
std::cerr << "p3ChatService::sendChat() Error: chat id type not handled. Is it empty?" << std::endl;
|
||||
return false;
|
||||
@ -313,8 +316,8 @@ bool p3ChatService::sendChat(ChatId destination, std::string msg)
|
||||
#endif
|
||||
|
||||
RsPeerId vpid;
|
||||
if(destination.isGxsId())
|
||||
vpid = RsPeerId(destination.toGxsId()); // convert to virtual peer id
|
||||
if(destination.isDistantChatId())
|
||||
vpid = RsPeerId(destination.toDistantChatId()); // convert to virtual peer id
|
||||
else
|
||||
vpid = destination.toPeerId();
|
||||
|
||||
@ -378,7 +381,12 @@ bool p3ChatService::sendChat(ChatId destination, std::string msg)
|
||||
#endif
|
||||
|
||||
RsServer::notify()->notifyChatMessage(message);
|
||||
mHistoryMgr->addMessage(message);
|
||||
|
||||
// cyril: history is temporarily diabled for distant chat, since we need to store the full tunnel ID, but then
|
||||
// at loading time, the ID is not known so that chat window shows 00000000 as a peer.
|
||||
|
||||
if(!message.chat_id.isDistantChatId())
|
||||
mHistoryMgr->addMessage(message);
|
||||
|
||||
checkSizeAndSendMessage(ci);
|
||||
|
||||
@ -497,11 +505,11 @@ void p3ChatService::handleIncomingItem(RsItem *item)
|
||||
return ; // don't delete! It's handled by handleRecvChatMsgItem in some specific cases only.
|
||||
}
|
||||
|
||||
if(DistantChatService::handleRecvItem(dynamic_cast<RsChatItem*>(item)))
|
||||
{
|
||||
delete item ;
|
||||
return ;
|
||||
}
|
||||
// if(DistantChatService::handleRecvItem(dynamic_cast<RsChatItem*>(item)))
|
||||
// {
|
||||
// delete item ;
|
||||
// return ;
|
||||
// }
|
||||
|
||||
if(DistributedChatService::handleRecvItem(dynamic_cast<RsChatItem*>(item)))
|
||||
{
|
||||
@ -749,7 +757,13 @@ bool p3ChatService::handleRecvChatMsgItem(RsChatMsgItem *ci)
|
||||
cm.incoming = true;
|
||||
cm.online = true;
|
||||
RsServer::notify()->notifyChatMessage(cm);
|
||||
mHistoryMgr->addMessage(cm);
|
||||
|
||||
// cyril: history is temporarily diabled for distant chat, since we need to store the full tunnel ID, but then
|
||||
// at loading time, the ID is not known so that chat window shows 00000000 as a peer.
|
||||
|
||||
if(!cm.chat_id.isDistantChatId())
|
||||
mHistoryMgr->addMessage(cm);
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
@ -766,7 +780,7 @@ void p3ChatService::handleRecvChatStatusItem(RsChatStatusItem *cs)
|
||||
std::cerr << "Received status string \"" << cs->status_string << "\"" << std::endl ;
|
||||
#endif
|
||||
|
||||
uint32_t status;
|
||||
DistantChatPeerInfo dcpinfo;
|
||||
|
||||
if(cs->flags & RS_CHAT_FLAG_REQUEST_CUSTOM_STATE) // no state here just a request.
|
||||
sendCustomState(cs->PeerId()) ;
|
||||
@ -782,9 +796,9 @@ void p3ChatService::handleRecvChatStatusItem(RsChatStatusItem *cs)
|
||||
#endif
|
||||
sendCustomStateRequest(cs->PeerId()) ;
|
||||
}
|
||||
else if(DistantChatService::getDistantChatStatus(RsGxsId(cs->PeerId()), status))
|
||||
else if(DistantChatService::getDistantChatStatus(DistantChatPeerId(cs->PeerId()), dcpinfo))
|
||||
{
|
||||
RsServer::notify()->notifyChatStatus(ChatId(RsGxsId(cs->PeerId())), cs->status_string) ;
|
||||
RsServer::notify()->notifyChatStatus(ChatId(DistantChatPeerId(cs->PeerId())), cs->status_string) ;
|
||||
}
|
||||
else if(cs->flags & RS_CHAT_FLAG_PRIVATE)
|
||||
{
|
||||
@ -816,9 +830,9 @@ void p3ChatService::initChatMessage(RsChatMsgItem *c, ChatMessage &m)
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t status;
|
||||
if(DistantChatService::getDistantChatStatus(RsGxsId(c->PeerId()), status))
|
||||
m.chat_id = ChatId(RsGxsId(c->PeerId()));
|
||||
DistantChatPeerInfo dcpinfo;
|
||||
if(DistantChatService::getDistantChatStatus(DistantChatPeerId(c->PeerId()), dcpinfo))
|
||||
m.chat_id = ChatId(DistantChatPeerId(c->PeerId()));
|
||||
|
||||
if (c -> chatFlags & RS_CHAT_FLAG_PRIVATE)
|
||||
m.chatflags |= RS_CHAT_PRIVATE;
|
||||
|
@ -51,18 +51,6 @@ std::ostream& RsChatMsgItem::print(std::ostream &out, uint16_t indent)
|
||||
printRsItemEnd(out, "RsChatMsgItem", indent);
|
||||
return out;
|
||||
}
|
||||
std::ostream& RsChatDHPublicKeyItem::print(std::ostream &out, uint16_t indent)
|
||||
{
|
||||
printRsItemBase(out, "RsChatDHPublicKeyItem", indent);
|
||||
uint16_t int_Indent = indent + 2;
|
||||
|
||||
printIndent(out, int_Indent);
|
||||
out << " Signature Key ID: " << signature.keyId << std::endl ;
|
||||
out << " Public Key ID: " << gxs_key.keyId << std::endl ;
|
||||
|
||||
printRsItemEnd(out, "RsChatMsgItem", indent);
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& RsChatLobbyListItem::print(std::ostream &out, uint16_t indent)
|
||||
{
|
||||
@ -277,7 +265,6 @@ RsItem *RsChatSerialiser::deserialise(void *data, uint32_t *pktsize)
|
||||
case RS_PKT_SUBTYPE_CHAT_LOBBY_LIST_REQUEST: return new RsChatLobbyListRequestItem(data,*pktsize) ;
|
||||
case RS_PKT_SUBTYPE_CHAT_LOBBY_LIST: return new RsChatLobbyListItem(data,*pktsize) ;
|
||||
case RS_PKT_SUBTYPE_CHAT_LOBBY_CONFIG: return new RsChatLobbyConfigItem(data,*pktsize) ;
|
||||
case RS_PKT_SUBTYPE_DISTANT_CHAT_DH_PUBLIC_KEY: return new RsChatDHPublicKeyItem(data,*pktsize) ;
|
||||
default:
|
||||
std::cerr << "Unknown packet type in chat!" << std::endl ;
|
||||
return NULL ;
|
||||
@ -437,17 +424,6 @@ uint32_t RsChatLobbyConfigItem::serial_size()
|
||||
return s;
|
||||
}
|
||||
|
||||
uint32_t RsChatDHPublicKeyItem::serial_size()
|
||||
{
|
||||
uint32_t s = 8 ; // header
|
||||
s += 4 ; // BN size
|
||||
s += BN_num_bytes(public_key) ; // public_key
|
||||
s += signature.TlvSize() ; // signature
|
||||
s += gxs_key.TlvSize() ; // gxs_key
|
||||
|
||||
return s ;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
RsChatAvatarItem::~RsChatAvatarItem()
|
||||
@ -459,41 +435,6 @@ RsChatAvatarItem::~RsChatAvatarItem()
|
||||
}
|
||||
}
|
||||
|
||||
bool RsChatDHPublicKeyItem::serialise(void *data,uint32_t& pktsize)
|
||||
{
|
||||
uint32_t tlvsize = serial_size() ;
|
||||
uint32_t offset = 0;
|
||||
|
||||
if (pktsize < tlvsize)
|
||||
return false; /* not enough space */
|
||||
|
||||
pktsize = tlvsize;
|
||||
|
||||
bool ok = true;
|
||||
|
||||
ok &= setRsItemHeader(data, tlvsize, PacketId(), tlvsize);
|
||||
|
||||
/* skip the header */
|
||||
offset += 8;
|
||||
|
||||
uint32_t s = BN_num_bytes(public_key) ;
|
||||
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, s);
|
||||
|
||||
BN_bn2bin(public_key,&((unsigned char *)data)[offset]) ;
|
||||
offset += s ;
|
||||
|
||||
ok &= signature.SetTlv(data, tlvsize, &offset);
|
||||
ok &= gxs_key.SetTlv(data, tlvsize, &offset);
|
||||
|
||||
if (offset != tlvsize)
|
||||
{
|
||||
ok = false;
|
||||
std::cerr << "RsChatDHPublicKeyItem::serialiseItem() Size Error! offset=" << offset << ", tlvsize=" << tlvsize << std::endl;
|
||||
}
|
||||
return ok ;
|
||||
}
|
||||
|
||||
/* serialise the data to the buffer */
|
||||
bool RsChatMsgItem::serialise(void *data, uint32_t& pktsize)
|
||||
{
|
||||
@ -995,28 +936,6 @@ bool RsChatLobbyConfigItem::serialise(void *data, uint32_t& pktsize)
|
||||
return ok;
|
||||
}
|
||||
|
||||
RsChatDHPublicKeyItem::RsChatDHPublicKeyItem(void *data,uint32_t /*size*/)
|
||||
: RsChatItem(RS_PKT_SUBTYPE_DISTANT_CHAT_DH_PUBLIC_KEY)
|
||||
{
|
||||
uint32_t offset = 8; // skip the header
|
||||
uint32_t rssize = getRsItemSize(data);
|
||||
bool ok = true ;
|
||||
|
||||
uint32_t s=0 ;
|
||||
/* get mandatory parts first */
|
||||
ok &= getRawUInt32(data, rssize, &offset, &s);
|
||||
|
||||
public_key = BN_bin2bn(&((unsigned char *)data)[offset],s,NULL) ;
|
||||
offset += s ;
|
||||
|
||||
ok &= signature.GetTlv(data, rssize, &offset) ;
|
||||
ok &= gxs_key.GetTlv(data, rssize, &offset) ;
|
||||
|
||||
if (offset != rssize)
|
||||
std::cerr << "RsChatDHPublicKeyItem::() Size error while deserializing." << std::endl ;
|
||||
if (!ok)
|
||||
std::cerr << "RsChatDHPublicKeyItem::() Unknown error while deserializing." << std::endl ;
|
||||
}
|
||||
RsChatMsgItem::RsChatMsgItem(void *data,uint32_t /*size*/,uint8_t subtype)
|
||||
: RsChatItem(subtype)
|
||||
{
|
||||
|
@ -316,6 +316,7 @@ bool p3GRouter::registerKey(const RsGxsId& authentication_key,const GRouterServi
|
||||
grouter_debug() << " Auth GXS Id : " << authentication_key << std::endl;
|
||||
grouter_debug() << " Client id : " << std::hex << client_id << std::dec << std::endl;
|
||||
grouter_debug() << " Description : " << info.description_string << std::endl;
|
||||
grouter_debug() << " Hash : " << hash << std::endl;
|
||||
#endif
|
||||
|
||||
return true ;
|
||||
@ -510,6 +511,12 @@ void p3GRouter::receiveTurtleData(RsTurtleGenericTunnelItem *gitem,const RsFileH
|
||||
|
||||
RsItem *itm = RsGRouterSerialiser().deserialise(item->data_bytes,&item->data_size) ;
|
||||
|
||||
if(itm == NULL)
|
||||
{
|
||||
std::cerr << "(EE) p3GRouter::receiveTurtleData(): cannot de-serialise data. Somthing wrong in the format. Item data (size="<< item->data_size << "): " << RsUtil::BinToHex((char*)item->data_bytes,item->data_size) << std::endl;
|
||||
return ;
|
||||
}
|
||||
|
||||
itm->PeerId(virtual_peer_id) ;
|
||||
|
||||
// At this point we can have either a transaction chunk, or a transaction ACK.
|
||||
@ -1674,9 +1681,13 @@ bool p3GRouter::locked_getClientAndServiceId(const TurtleFileHash& hash, const R
|
||||
{
|
||||
client = NULL ;
|
||||
service_id = 0;
|
||||
|
||||
RsGxsId gxs_id ;
|
||||
makeGxsIdAndClientId(hash,gxs_id,service_id) ;
|
||||
|
||||
if(!locked_getGxsIdAndClientId(hash,gxs_id,service_id))
|
||||
{
|
||||
std::cerr << " p3GRouter::ERROR: locked_getGxsIdAndClientId(): no key registered for hash " << hash << std::endl;
|
||||
return false ;
|
||||
}
|
||||
|
||||
if(gxs_id != destination_key)
|
||||
{
|
||||
@ -2013,15 +2024,25 @@ Sha1CheckSum p3GRouter::makeTunnelHash(const RsGxsId& destination,const GRouterS
|
||||
bytes[18] = (client >> 8) & 0xff ;
|
||||
bytes[19] = client & 0xff ;
|
||||
|
||||
return Sha1CheckSum(bytes) ;
|
||||
return RsDirUtil::sha1sum(bytes,20) ;
|
||||
}
|
||||
void p3GRouter::makeGxsIdAndClientId(const TurtleFileHash& sum,RsGxsId& gxs_id,GRouterServiceId& client_id)
|
||||
bool p3GRouter::locked_getGxsIdAndClientId(const TurtleFileHash& sum,RsGxsId& gxs_id,GRouterServiceId& client_id)
|
||||
{
|
||||
assert( gxs_id.SIZE_IN_BYTES == 16) ;
|
||||
assert(Sha1CheckSum::SIZE_IN_BYTES == 20) ;
|
||||
|
||||
gxs_id = RsGxsId(sum.toByteArray());// takes the first 16 bytes
|
||||
client_id = sum.toByteArray()[19] + (sum.toByteArray()[18] << 8) ;
|
||||
//gxs_id = RsGxsId(sum.toByteArray());// takes the first 16 bytes
|
||||
//client_id = sum.toByteArray()[19] + (sum.toByteArray()[18] << 8) ;
|
||||
|
||||
std::map<Sha1CheckSum, GRouterPublishedKeyInfo>::const_iterator it = _owned_key_ids.find(sum);
|
||||
|
||||
if(it == _owned_key_ids.end())
|
||||
return false ;
|
||||
|
||||
gxs_id = it->second.authentication_key ;
|
||||
client_id = it->second.service_id ;
|
||||
|
||||
return true ;
|
||||
}
|
||||
bool p3GRouter::loadList(std::list<RsItem*>& items)
|
||||
{
|
||||
|
@ -269,8 +269,8 @@ private:
|
||||
bool decryptDataItem(RsGRouterGenericDataItem *item) ;
|
||||
|
||||
static Sha1CheckSum makeTunnelHash(const RsGxsId& destination,const GRouterServiceId& client);
|
||||
static void makeGxsIdAndClientId(const TurtleFileHash &sum,RsGxsId& gxs_id,GRouterServiceId& client_id);
|
||||
|
||||
bool locked_getGxsIdAndClientId(const TurtleFileHash &sum,RsGxsId& gxs_id,GRouterServiceId& client_id);
|
||||
bool locked_sendTransactionData(const RsPeerId& pid,const RsGRouterTransactionItem& item);
|
||||
|
||||
void locked_collectAvailableFriends(const GRouterKeyId &gxs_id,std::list<RsPeerId>& friend_peers, const std::set<RsPeerId>& incoming_routes,bool is_origin);
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "gxssecurity.h"
|
||||
#include "pqi/authgpg.h"
|
||||
#include "util/rsdir.h"
|
||||
#include "util/rsmemory.h"
|
||||
//#include "retroshare/rspeers.h"
|
||||
|
||||
/****
|
||||
@ -607,117 +608,114 @@ bool GxsSecurity::decrypt(uint8_t *& out, uint32_t & outlen, const uint8_t *in,
|
||||
bool GxsSecurity::validateNxsGrp(const RsNxsGrp& grp, const RsTlvKeySignature& sign, const RsTlvSecurityKey& key)
|
||||
{
|
||||
#ifdef GXS_SECURITY_DEBUG
|
||||
std::cerr << "GxsSecurity::validateNxsGrp()";
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "RsNxsGrp :";
|
||||
std::cerr << std::endl;
|
||||
grp.print(std::cerr, 10);
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "GxsSecurity::validateNxsGrp()";
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "RsNxsGrp :";
|
||||
std::cerr << std::endl;
|
||||
grp.print(std::cerr, 10);
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
RsGxsGrpMetaData& grpMeta = *(grp.metaData);
|
||||
RsGxsGrpMetaData& grpMeta = *(grp.metaData);
|
||||
|
||||
/********************* check signature *******************/
|
||||
/********************* check signature *******************/
|
||||
|
||||
/* check signature timeperiod */
|
||||
if ((grpMeta.mPublishTs < key.startTS) || (key.endTS != 0 && grpMeta.mPublishTs > key.endTS))
|
||||
{
|
||||
/* check signature timeperiod */
|
||||
if ((grpMeta.mPublishTs < key.startTS) || (key.endTS != 0 && grpMeta.mPublishTs > key.endTS))
|
||||
{
|
||||
#ifdef GXS_SECURITY_DEBUG
|
||||
std::cerr << " GxsSecurity::validateNxsMsg() TS out of range";
|
||||
std::cerr << std::endl;
|
||||
std::cerr << " GxsSecurity::validateNxsMsg() TS out of range";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* decode key */
|
||||
const unsigned char *keyptr = (const unsigned char *) key.keyData.bin_data;
|
||||
long keylen = key.keyData.bin_len;
|
||||
unsigned int siglen = sign.signData.bin_len;
|
||||
unsigned char *sigbuf = (unsigned char *) sign.signData.bin_data;
|
||||
/* decode key */
|
||||
const unsigned char *keyptr = (const unsigned char *) key.keyData.bin_data;
|
||||
long keylen = key.keyData.bin_len;
|
||||
unsigned int siglen = sign.signData.bin_len;
|
||||
unsigned char *sigbuf = (unsigned char *) sign.signData.bin_data;
|
||||
|
||||
#ifdef DISTRIB_DEBUG
|
||||
std::cerr << "GxsSecurity::validateNxsMsg() Decode Key";
|
||||
std::cerr << " keylen: " << keylen << " siglen: " << siglen;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "GxsSecurity::validateNxsMsg() Decode Key";
|
||||
std::cerr << " keylen: " << keylen << " siglen: " << siglen;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
/* extract admin key */
|
||||
RSA *rsakey = (key.keyFlags & RSTLV_KEY_TYPE_FULL)? d2i_RSAPrivateKey(NULL, &(keyptr), keylen): d2i_RSAPublicKey(NULL, &(keyptr), keylen);
|
||||
/* extract admin key */
|
||||
RSA *rsakey = (key.keyFlags & RSTLV_KEY_TYPE_FULL)? d2i_RSAPrivateKey(NULL, &(keyptr), keylen): d2i_RSAPublicKey(NULL, &(keyptr), keylen);
|
||||
|
||||
if (!rsakey)
|
||||
{
|
||||
#ifdef GXS_SECURITY_DEBUG
|
||||
std::cerr << "GxsSecurity::validateNxsGrp()";
|
||||
std::cerr << " Invalid RSA Key";
|
||||
std::cerr << std::endl;
|
||||
|
||||
key.print(std::cerr, 10);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
RsTlvKeySignatureSet signSet = grpMeta.signSet;
|
||||
grpMeta.signSet.TlvClear();
|
||||
|
||||
uint32_t metaDataLen = grpMeta.serial_size();
|
||||
uint32_t allGrpDataLen = metaDataLen + grp.grp.bin_len;
|
||||
char* metaData = new char[metaDataLen];
|
||||
char* allGrpData = new char[allGrpDataLen]; // msgData + metaData
|
||||
|
||||
grpMeta.serialise(metaData, metaDataLen);
|
||||
|
||||
// copy msg data and meta in allmsgData buffer
|
||||
memcpy(allGrpData, grp.grp.bin_data, grp.grp.bin_len);
|
||||
memcpy(allGrpData+(grp.grp.bin_len), metaData, metaDataLen);
|
||||
|
||||
delete[] metaData ;
|
||||
|
||||
EVP_PKEY *signKey = EVP_PKEY_new();
|
||||
EVP_PKEY_assign_RSA(signKey, rsakey);
|
||||
|
||||
/* calc and check signature */
|
||||
EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
|
||||
|
||||
EVP_VerifyInit(mdctx, EVP_sha1());
|
||||
EVP_VerifyUpdate(mdctx, allGrpData, allGrpDataLen);
|
||||
int signOk = EVP_VerifyFinal(mdctx, sigbuf, siglen, signKey);
|
||||
EVP_MD_CTX_destroy(mdctx);
|
||||
|
||||
if(signOk != 1) // try previous API. This is a hack to accept groups previously signed with old APIs.
|
||||
if (!rsakey)
|
||||
{
|
||||
#ifdef GXS_SECURITY_DEBUG
|
||||
std::cerr << "GxsSecurity::validateNxsGrp()";
|
||||
std::cerr << " Invalid RSA Key";
|
||||
std::cerr << std::endl;
|
||||
|
||||
key.print(std::cerr, 10);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<uint32_t> api_versions_to_check ;
|
||||
api_versions_to_check.push_back(RS_GXS_GRP_META_DATA_VERSION_ID_0002) ; // put newest first, for debug info purpose
|
||||
api_versions_to_check.push_back(RS_GXS_GRP_META_DATA_VERSION_ID_0001) ;
|
||||
|
||||
RsTlvKeySignatureSet signSet = grpMeta.signSet;
|
||||
grpMeta.signSet.TlvClear();
|
||||
|
||||
int signOk =0;
|
||||
EVP_PKEY *signKey = EVP_PKEY_new();
|
||||
EVP_PKEY_assign_RSA(signKey, rsakey);
|
||||
|
||||
|
||||
for(uint32_t i=0;i<api_versions_to_check.size() && 0==signOk;++i)
|
||||
{
|
||||
uint32_t metaDataLen = grpMeta.serial_size(api_versions_to_check[i]);
|
||||
uint32_t allGrpDataLen = metaDataLen + grp.grp.bin_len;
|
||||
|
||||
RsTemporaryMemory metaData(metaDataLen) ;
|
||||
RsTemporaryMemory allGrpData(allGrpDataLen) ;// msgData + metaData
|
||||
|
||||
grpMeta.serialise(metaData, metaDataLen,api_versions_to_check[i]);
|
||||
|
||||
// copy msg data and meta in allmsgData buffer
|
||||
memcpy(allGrpData, grp.grp.bin_data, grp.grp.bin_len);
|
||||
memcpy(allGrpData+(grp.grp.bin_len), metaData, metaDataLen);
|
||||
|
||||
/* calc and check signature */
|
||||
EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
|
||||
|
||||
EVP_VerifyInit(mdctx, EVP_sha1());
|
||||
EVP_VerifyUpdate(mdctx, allGrpData, allGrpDataLen-4); // that means ommit the last
|
||||
EVP_VerifyUpdate(mdctx, allGrpData, allGrpDataLen);
|
||||
signOk = EVP_VerifyFinal(mdctx, sigbuf, siglen, signKey);
|
||||
EVP_MD_CTX_destroy(mdctx);
|
||||
|
||||
if(signOk)
|
||||
std::cerr << "(WW) GXS group with old API found. Signature still checks!" << std::endl;
|
||||
if(i>0)
|
||||
std::cerr << "(WW) Checking group signature with old api version " << i+1 << " : tag " << std::hex << api_versions_to_check[i] << std::dec << " result: " << signOk << std::endl;
|
||||
}
|
||||
|
||||
delete[] allGrpData ;
|
||||
/* clean up */
|
||||
EVP_PKEY_free(signKey);
|
||||
|
||||
/* clean up */
|
||||
EVP_PKEY_free(signKey);
|
||||
// restore data
|
||||
|
||||
grpMeta.signSet = signSet;
|
||||
grpMeta.signSet = signSet;
|
||||
|
||||
if (signOk == 1)
|
||||
{
|
||||
if (signOk == 1)
|
||||
{
|
||||
#ifdef GXS_SECURITY_DEBUG
|
||||
std::cerr << "GxsSecurity::validateNxsGrp() Signature OK";
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "GxsSecurity::validateNxsGrp() Signature OK";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef GXS_SECURITY_DEBUG
|
||||
std::cerr << "GxsSecurity::validateNxsGrp() Signature invalid";
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "GxsSecurity::validateNxsGrp() Signature invalid";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -63,8 +63,8 @@ static const uint32_t INDEX_AUTHEN_ADMIN = 0x00000040; // admin key
|
||||
|
||||
//#define GEN_EXCH_DEBUG 1
|
||||
|
||||
#define MSG_CLEANUP_PERIOD 60*5 // 5 minutes
|
||||
#define INTEGRITY_CHECK_PERIOD 60*30 // 30 minutes
|
||||
#define MSG_CLEANUP_PERIOD 60*5 // 5 minutes
|
||||
#define INTEGRITY_CHECK_PERIOD 60*30 // 30 minutes
|
||||
|
||||
RsGenExchange::RsGenExchange(RsGeneralDataService *gds, RsNetworkExchangeService *ns,
|
||||
RsSerialType *serviceSerialiser, uint16_t servType, RsGixs* gixs,
|
||||
@ -78,10 +78,10 @@ RsGenExchange::RsGenExchange(RsGeneralDataService *gds, RsNetworkExchangeService
|
||||
mAuthenPolicy(authenPolicy),
|
||||
MESSAGE_STORE_PERIOD(messageStorePeriod),
|
||||
mCleaning(false),
|
||||
mLastClean(time(NULL)),
|
||||
mLastClean((int)time(NULL) - (int)(RSRandom::random_u32() % MSG_CLEANUP_PERIOD)), // this helps unsynchronising the checks for the different services
|
||||
mMsgCleanUp(NULL),
|
||||
mChecking(false),
|
||||
mLastCheck(time(NULL)),
|
||||
mLastCheck((int)time(NULL) - (int)(RSRandom::random_u32() % INTEGRITY_CHECK_PERIOD)), // this helps unsynchronising the checks for the different services
|
||||
mIntegrityCheck(NULL),
|
||||
CREATE_FAIL(0),
|
||||
CREATE_SUCCESS(1),
|
||||
@ -253,7 +253,7 @@ void RsGenExchange::tick()
|
||||
}
|
||||
else
|
||||
{
|
||||
mIntegrityCheck = new RsGxsIntegrityCheck(mDataStore);
|
||||
mIntegrityCheck = new RsGxsIntegrityCheck(mDataStore,mGixs);
|
||||
mIntegrityCheck->start();
|
||||
mChecking = true;
|
||||
}
|
||||
@ -411,12 +411,12 @@ uint8_t RsGenExchange::createGroup(RsNxsGrp *grp, RsTlvSecurityKeySet& privateKe
|
||||
// group is self signing
|
||||
// for the creation of group signature
|
||||
// only public admin and publish keys are present in meta
|
||||
uint32_t metaDataLen = meta->serial_size();
|
||||
uint32_t metaDataLen = meta->serial_size(RS_GXS_GRP_META_DATA_CURRENT_API_VERSION);
|
||||
uint32_t allGrpDataLen = metaDataLen + grp->grp.bin_len;
|
||||
char* metaData = new char[metaDataLen];
|
||||
char* allGrpData = new char[allGrpDataLen]; // msgData + metaData
|
||||
|
||||
meta->serialise(metaData, metaDataLen);
|
||||
meta->serialise(metaData, metaDataLen,RS_GXS_GRP_META_DATA_CURRENT_API_VERSION);
|
||||
|
||||
// copy msg data and meta in allMsgData buffer
|
||||
memcpy(allGrpData, grp->grp.bin_data, grp->grp.bin_len);
|
||||
@ -500,13 +500,11 @@ int RsGenExchange::createGroupSignatures(RsTlvKeySignatureSet& signSet, RsTlvBin
|
||||
authorKey, sign))
|
||||
{
|
||||
id_ret = SIGN_SUCCESS;
|
||||
mGixs->timeStampKey(grpMeta.mAuthorId) ;
|
||||
signSet.keySignSet[INDEX_AUTHEN_IDENTITY] = sign;
|
||||
}
|
||||
else
|
||||
{
|
||||
id_ret = SIGN_FAIL;
|
||||
}
|
||||
|
||||
signSet.keySignSet[INDEX_AUTHEN_IDENTITY] = sign;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -662,23 +660,20 @@ int RsGenExchange::createMsgSignatures(RsTlvKeySignatureSet& signSet, RsTlvBinar
|
||||
bool haveKey = mGixs->havePrivateKey(msgMeta.mAuthorId);
|
||||
|
||||
if(haveKey)
|
||||
{
|
||||
RsTlvSecurityKey authorKey;
|
||||
mGixs->getPrivateKey(msgMeta.mAuthorId, authorKey);
|
||||
RsTlvKeySignature sign;
|
||||
{
|
||||
RsTlvSecurityKey authorKey;
|
||||
mGixs->getPrivateKey(msgMeta.mAuthorId, authorKey);
|
||||
RsTlvKeySignature sign;
|
||||
|
||||
if(GxsSecurity::getSignature((char*)msgData.bin_data, msgData.bin_len,
|
||||
authorKey, sign))
|
||||
{
|
||||
id_ret = SIGN_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
id_ret = SIGN_FAIL;
|
||||
}
|
||||
|
||||
signSet.keySignSet[INDEX_AUTHEN_IDENTITY] = sign;
|
||||
}
|
||||
if(GxsSecurity::getSignature((char*)msgData.bin_data, msgData.bin_len, authorKey, sign))
|
||||
{
|
||||
id_ret = SIGN_SUCCESS;
|
||||
mGixs->timeStampKey(msgMeta.mAuthorId) ;
|
||||
signSet.keySignSet[INDEX_AUTHEN_IDENTITY] = sign;
|
||||
}
|
||||
else
|
||||
id_ret = SIGN_FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
mGixs->requestPrivateKey(msgMeta.mAuthorId);
|
||||
@ -971,77 +966,88 @@ int RsGenExchange::validateMsg(RsNxsMsg *msg, const uint32_t& grpFlag, const uin
|
||||
|
||||
int RsGenExchange::validateGrp(RsNxsGrp* grp)
|
||||
{
|
||||
|
||||
bool needIdentitySign = false, idValidate = false;
|
||||
RsGxsGrpMetaData& metaData = *(grp->metaData);
|
||||
bool needIdentitySign = false, idValidate = false;
|
||||
RsGxsGrpMetaData& metaData = *(grp->metaData);
|
||||
|
||||
uint8_t author_flag = GXS_SERV::GRP_OPTION_AUTHEN_AUTHOR_SIGN;
|
||||
|
||||
PrivacyBitPos pos = GRP_OPTION_BITS;
|
||||
|
||||
#ifdef GEN_EXCH_DEBUG
|
||||
std::cerr << "Validating group " << grp->grpId << ", authorId = " << metaData.mAuthorId << std::endl;
|
||||
#endif
|
||||
// Check required permissions, and allow them to sign it - if they want too - as well!
|
||||
if ((!metaData.mAuthorId.isNull()) || checkAuthenFlag(pos, author_flag))
|
||||
{
|
||||
needIdentitySign = true;
|
||||
needIdentitySign = true;
|
||||
#ifdef GEN_EXCH_DEBUG
|
||||
std::cerr << "Needs Identity sign! (Service Flags)";
|
||||
std::cerr << std::endl;
|
||||
std::cerr << " Needs Identity sign! (Service Flags). Identity signing key is " << metaData.mAuthorId << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
if(needIdentitySign)
|
||||
{
|
||||
if(mGixs)
|
||||
{
|
||||
bool haveKey = mGixs->haveKey(metaData.mAuthorId);
|
||||
if(needIdentitySign)
|
||||
{
|
||||
if(mGixs)
|
||||
{
|
||||
bool haveKey = mGixs->haveKey(metaData.mAuthorId);
|
||||
|
||||
if(haveKey)
|
||||
{
|
||||
|
||||
RsTlvSecurityKey authorKey;
|
||||
bool auth_key_fetched = mGixs->getKey(metaData.mAuthorId, authorKey) ;
|
||||
|
||||
if (auth_key_fetched)
|
||||
{
|
||||
|
||||
RsTlvKeySignature sign = metaData.signSet.keySignSet[INDEX_AUTHEN_IDENTITY];
|
||||
idValidate = GxsSecurity::validateNxsGrp(*grp, sign, authorKey);
|
||||
|
||||
mGixs->timeStampKey(metaData.mAuthorId) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "RsGenExchange::validateGrp()";
|
||||
std::cerr << " ERROR Cannot Retrieve AUTHOR KEY for Group Sign Validation";
|
||||
std::cerr << std::endl;
|
||||
idValidate = false;
|
||||
}
|
||||
|
||||
}else
|
||||
{
|
||||
std::list<RsPeerId> peers;
|
||||
peers.push_back(grp->PeerId());
|
||||
mGixs->requestKey(metaData.mAuthorId, peers);
|
||||
return VALIDATE_FAIL_TRY_LATER;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(haveKey)
|
||||
{
|
||||
#ifdef GEN_EXCH_DEBUG
|
||||
std::cerr << "Gixs not enabled while request identity signature validation!" << std::endl;
|
||||
std::cerr << " have ID key in cache: yes" << std::endl;
|
||||
#endif
|
||||
idValidate = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
idValidate = true;
|
||||
}
|
||||
|
||||
if(idValidate)
|
||||
return VALIDATE_SUCCESS;
|
||||
else
|
||||
return VALIDATE_FAIL;
|
||||
RsTlvSecurityKey authorKey;
|
||||
bool auth_key_fetched = mGixs->getKey(metaData.mAuthorId, authorKey) ;
|
||||
|
||||
if (auth_key_fetched)
|
||||
{
|
||||
|
||||
RsTlvKeySignature sign = metaData.signSet.keySignSet[INDEX_AUTHEN_IDENTITY];
|
||||
idValidate = GxsSecurity::validateNxsGrp(*grp, sign, authorKey);
|
||||
|
||||
#ifdef GEN_EXCH_DEBUG
|
||||
std::cerr << " key ID validation result: " << idValidate << std::endl;
|
||||
#endif
|
||||
mGixs->timeStampKey(metaData.mAuthorId) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "RsGenExchange::validateGrp()";
|
||||
std::cerr << " ERROR Cannot Retrieve AUTHOR KEY for Group Sign Validation";
|
||||
std::cerr << std::endl;
|
||||
idValidate = false;
|
||||
}
|
||||
|
||||
}else
|
||||
{
|
||||
#ifdef GEN_EXCH_DEBUG
|
||||
std::cerr << " have key in cache: no. Return VALIDATE_LATER" << std::endl;
|
||||
std::cerr << " requesting key " << metaData.mAuthorId << " to origin peer " << grp->PeerId() << std::endl;
|
||||
#endif
|
||||
std::list<RsPeerId> peers;
|
||||
peers.push_back(grp->PeerId());
|
||||
mGixs->requestKey(metaData.mAuthorId, peers);
|
||||
return VALIDATE_FAIL_TRY_LATER;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef GEN_EXCH_DEBUG
|
||||
std::cerr << " (EE) Gixs not enabled while request identity signature validation!" << std::endl;
|
||||
#endif
|
||||
idValidate = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
idValidate = true;
|
||||
}
|
||||
|
||||
if(idValidate)
|
||||
return VALIDATE_SUCCESS;
|
||||
else
|
||||
return VALIDATE_FAIL;
|
||||
|
||||
}
|
||||
|
||||
@ -1531,6 +1537,9 @@ void RsGenExchange::notifyNewMessages(std::vector<RsNxsMsg *>& messages)
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef GEN_EXCH_DEBUG
|
||||
std::cerr << " message is already in pending validation list. dropping." << std::endl;
|
||||
#endif
|
||||
delete msg;
|
||||
}
|
||||
}
|
||||
@ -2338,9 +2347,9 @@ void RsGenExchange::publishGrps()
|
||||
if(create == CREATE_SUCCESS)
|
||||
{
|
||||
|
||||
uint32_t mdSize = grp->metaData->serial_size();
|
||||
uint32_t mdSize = grp->metaData->serial_size(RS_GXS_GRP_META_DATA_CURRENT_API_VERSION);
|
||||
char* metaData = new char[mdSize];
|
||||
serialOk = grp->metaData->serialise(metaData, mdSize);
|
||||
serialOk = grp->metaData->serialise(metaData, mdSize,RS_GXS_GRP_META_DATA_CURRENT_API_VERSION);
|
||||
grp->meta.setBinData(metaData, mdSize);
|
||||
delete[] metaData;
|
||||
|
||||
@ -2651,6 +2660,16 @@ void RsGenExchange::processRecvdMessages()
|
||||
if(grpMeta->mSignFlags & GXS_SERV::FLAG_AUTHOR_AUTHENTICATION_TRACK_MESSAGES)
|
||||
mTrackingClues.push_back(std::make_pair(msg->msgId,msg->PeerId())) ;
|
||||
}
|
||||
|
||||
if(validateReturn == VALIDATE_FAIL)
|
||||
{
|
||||
// In this case, we notify the network exchange service not to DL the message again, at least not yet.
|
||||
|
||||
#ifdef GEN_EXCH_DEBUG
|
||||
std::cerr << "Notifying the network service to not download this message again." << std::endl;
|
||||
#endif
|
||||
mNetService->rejectMessage(msg->msgId) ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2757,6 +2776,9 @@ void RsGenExchange::processRecvdGroups()
|
||||
|
||||
if(deserialOk)
|
||||
{
|
||||
#ifdef GEN_EXCH_DEBUG
|
||||
std::cerr << " processing validation for group " << meta->mGroupId << ", attempts number " << gpsi.mAttempts << std::endl;
|
||||
#endif
|
||||
grp->metaData = meta;
|
||||
uint8_t ret = validateGrp(grp);
|
||||
|
||||
@ -2771,7 +2793,7 @@ void RsGenExchange::processRecvdGroups()
|
||||
// group has been validated. Let's notify the global router for the clue
|
||||
|
||||
#ifdef GEN_EXCH_DEBUG
|
||||
std::cerr << "Group routage info: Identity=" << meta->mAuthorId << " from " << grp->PeerId() << std::endl;
|
||||
std::cerr << " Group routage info: Identity=" << meta->mAuthorId << " from " << grp->PeerId() << std::endl;
|
||||
#endif
|
||||
|
||||
if(!meta->mAuthorId.isNull())
|
||||
@ -2798,7 +2820,7 @@ void RsGenExchange::processRecvdGroups()
|
||||
else if(ret == VALIDATE_FAIL)
|
||||
{
|
||||
#ifdef GEN_EXCH_DEBUG
|
||||
std::cerr << "failed to validate incoming meta, grpId: " << grp->grpId << ": wrong signature" << std::endl;
|
||||
std::cerr << " failed to validate incoming meta, grpId: " << grp->grpId << ": wrong signature" << std::endl;
|
||||
#endif
|
||||
delete grp;
|
||||
erase = true;
|
||||
@ -2807,13 +2829,16 @@ void RsGenExchange::processRecvdGroups()
|
||||
{
|
||||
|
||||
#ifdef GEN_EXCH_DEBUG
|
||||
std::cerr << "failed to validate incoming grp, trying again. grpId: " << grp->grpId << std::endl;
|
||||
std::cerr << " failed to validate incoming grp, trying again. grpId: " << grp->grpId << std::endl;
|
||||
#endif
|
||||
|
||||
if(gpsi.mAttempts == VALIDATE_MAX_ATTEMPTS)
|
||||
{
|
||||
delete grp;
|
||||
erase = true;
|
||||
#ifdef GEN_EXCH_DEBUG
|
||||
std::cerr << " max attempts " << VALIDATE_MAX_ATTEMPTS << " reached. Will delete group " << grp->grpId << std::endl;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -28,17 +28,12 @@
|
||||
#include "serialiser/rsbaseserial.h"
|
||||
#include "serialiser/rstlvbase.h"
|
||||
|
||||
static const uint32_t RS_GXS_GRP_META_DATA_VERSION_ID_0001 = 0x0000 ; // change this, and keep old values if the content changes
|
||||
static const uint32_t RS_GXS_GRP_META_DATA_VERSION_ID_0002 = 0xaf01 ; // current API
|
||||
|
||||
static const uint32_t RS_GXS_MSG_META_DATA_VERSION_ID_0001 = 0x0000 ; // current API
|
||||
|
||||
RsGxsGrpMetaData::RsGxsGrpMetaData()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
uint32_t RsGxsGrpMetaData::serial_size()
|
||||
uint32_t RsGxsGrpMetaData::serial_size(uint32_t api_version)
|
||||
{
|
||||
uint32_t s = 8; // header size
|
||||
|
||||
@ -55,7 +50,11 @@ uint32_t RsGxsGrpMetaData::serial_size()
|
||||
s += mCircleId.serial_size();
|
||||
s += 4; // mAuthenFlag
|
||||
s += mParentGrpId.serial_size(); // mParentGroupId
|
||||
s += 4; // mSignFlag
|
||||
|
||||
if(api_version == RS_GXS_GRP_META_DATA_VERSION_ID_0002)
|
||||
s += 4; // mSignFlag
|
||||
else if(api_version != RS_GXS_GRP_META_DATA_VERSION_ID_0001)
|
||||
std::cerr << "(EE) wrong/unknown API version " << api_version << " requested in RsGxsGrpMetaData::serial_size()" << std::endl;
|
||||
|
||||
return s;
|
||||
}
|
||||
@ -97,10 +96,9 @@ void RsGxsGrpMetaData::clear(){
|
||||
mHash.clear() ;
|
||||
}
|
||||
|
||||
bool RsGxsGrpMetaData::serialise(void *data, uint32_t &pktsize)
|
||||
bool RsGxsGrpMetaData::serialise(void *data, uint32_t &pktsize,uint32_t api_version)
|
||||
{
|
||||
|
||||
uint32_t tlvsize = serial_size() ;
|
||||
uint32_t tlvsize = serial_size(api_version) ;
|
||||
uint32_t offset = 0;
|
||||
|
||||
if (pktsize < tlvsize)
|
||||
@ -110,7 +108,7 @@ bool RsGxsGrpMetaData::serialise(void *data, uint32_t &pktsize)
|
||||
|
||||
bool ok = true;
|
||||
|
||||
ok &= setRsItemHeader(data, tlvsize, RS_GXS_GRP_META_DATA_VERSION_ID_0002, tlvsize);
|
||||
ok &= setRsItemHeader(data, tlvsize, api_version, tlvsize);
|
||||
|
||||
#ifdef GXS_DEBUG
|
||||
std::cerr << "RsGxsGrpMetaData serialise()" << std::endl;
|
||||
@ -136,7 +134,8 @@ bool RsGxsGrpMetaData::serialise(void *data, uint32_t &pktsize)
|
||||
ok &= signSet.SetTlv(data, tlvsize, &offset);
|
||||
ok &= keys.SetTlv(data, tlvsize, &offset);
|
||||
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, mSignFlags); // new in API v2. Was previously missing. Kept in the end for backward compatibility
|
||||
if(api_version == RS_GXS_GRP_META_DATA_VERSION_ID_0002)
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, mSignFlags); // new in API v2. Was previously missing. Kept in the end for backward compatibility
|
||||
|
||||
return ok;
|
||||
}
|
||||
@ -265,7 +264,7 @@ bool RsGxsMsgMetaData::serialise(void *data, uint32_t *size)
|
||||
|
||||
bool ok = true;
|
||||
|
||||
ok &= setRsItemHeader(data, tlvsize, RS_GXS_MSG_META_DATA_VERSION_ID_0001, tlvsize);
|
||||
ok &= setRsItemHeader(data, tlvsize, RS_GXS_MSG_META_DATA_VERSION_ID_0002, tlvsize);
|
||||
|
||||
#ifdef GXS_DEBUG
|
||||
std::cerr << "RsGxsGrpMetaData serialise()" << std::endl;
|
||||
|
@ -37,6 +37,13 @@
|
||||
class RsGroupMetaData;
|
||||
class RsMsgMetaData;
|
||||
|
||||
static const uint32_t RS_GXS_GRP_META_DATA_VERSION_ID_0001 = 0x0000 ; // change this, and keep old values if the content changes
|
||||
static const uint32_t RS_GXS_GRP_META_DATA_VERSION_ID_0002 = 0xaf01 ; // current API
|
||||
|
||||
static const uint32_t RS_GXS_MSG_META_DATA_VERSION_ID_0002 = 0x0000 ; // current API
|
||||
|
||||
static const uint32_t RS_GXS_GRP_META_DATA_CURRENT_API_VERSION = RS_GXS_GRP_META_DATA_VERSION_ID_0002;
|
||||
|
||||
class RsGxsGrpMetaData
|
||||
{
|
||||
public:
|
||||
@ -44,8 +51,8 @@ public:
|
||||
|
||||
RsGxsGrpMetaData();
|
||||
bool deserialise(void *data, uint32_t &pktsize);
|
||||
bool serialise(void* data, uint32_t &pktsize);
|
||||
uint32_t serial_size();
|
||||
bool serialise(void* data, uint32_t &pktsize, uint32_t api_version);
|
||||
uint32_t serial_size(uint32_t api_version);
|
||||
void clear();
|
||||
void operator =(const RsGroupMetaData& rMeta);
|
||||
|
||||
|
@ -1552,7 +1552,7 @@ bool RsGxsDataAccess::getGroupStatistic(GroupStatisticRequest *req)
|
||||
req->mGroupStatistic.mNumChildMsgsNew = 0;
|
||||
req->mGroupStatistic.mNumChildMsgsUnread = 0;
|
||||
|
||||
for(int i = 0; i < msgMetaV.size(); ++i)
|
||||
for(uint32_t i = 0; i < msgMetaV.size(); ++i)
|
||||
{
|
||||
RsGxsMsgMetaData* m = msgMetaV[i];
|
||||
req->mGroupStatistic.mTotalSizeOfMsgs += m->mMsgSize + m->serial_size();
|
||||
@ -1603,7 +1603,7 @@ bool RsGxsDataAccess::getServiceStatistic(ServiceStatisticRequest *req)
|
||||
for(; mit != grpMeta.end(); ++mit)
|
||||
{
|
||||
RsGxsGrpMetaData* m = mit->second;
|
||||
req->mServiceStatistic.mSizeOfGrps += m->mGrpSize + m->serial_size();
|
||||
req->mServiceStatistic.mSizeOfGrps += m->mGrpSize + m->serial_size(RS_GXS_GRP_META_DATA_CURRENT_API_VERSION);
|
||||
|
||||
if (IS_GROUP_SUBSCRIBED(m->mSubscribeFlags))
|
||||
{
|
||||
|
@ -54,7 +54,8 @@ class RsGroupNetworkStatsRecord
|
||||
RsGroupNetworkStatsRecord() { max_visible_count= 0 ; }
|
||||
|
||||
std::set<RsPeerId> suppliers ;
|
||||
uint32_t max_visible_count ;
|
||||
uint32_t max_visible_count ;
|
||||
time_t update_TS ;
|
||||
};
|
||||
|
||||
/*!
|
||||
@ -151,6 +152,8 @@ public:
|
||||
*/
|
||||
virtual void subscribeStatusChanged(const RsGxsGroupId& id,bool subscribed) ;
|
||||
|
||||
virtual void rejectMessage(const RsGxsMessageId& msg_id) ;
|
||||
|
||||
/* p3Config methods */
|
||||
public:
|
||||
|
||||
@ -317,6 +320,12 @@ private:
|
||||
*/
|
||||
void handleRecvSyncGroup(RsNxsSyncGrp* item);
|
||||
|
||||
/*!
|
||||
* Handles an nxs item for group statistics
|
||||
* @param item contaims update time stamp and number of messages
|
||||
*/
|
||||
void handleRecvSyncGrpStatistics(RsNxsSyncGrpStats *grs);
|
||||
|
||||
/*!
|
||||
* Handles an nxs item for msgs synchronisation
|
||||
* @param item contaims msg sync info
|
||||
@ -357,6 +366,7 @@ private:
|
||||
void locked_pushGrpRespFromList(std::list<RsNxsItem*>& respList, const RsPeerId& peer, const uint32_t& transN);
|
||||
void locked_pushMsgRespFromList(std::list<RsNxsItem*>& itemL, const RsPeerId& sslId, const uint32_t& transN);
|
||||
void syncWithPeers();
|
||||
void syncGrpStatistics();
|
||||
void addGroupItemToList(NxsTransaction*& tr,
|
||||
const RsGxsGroupId& grpId, uint32_t& transN,
|
||||
std::list<RsNxsItem*>& reqList);
|
||||
@ -368,6 +378,7 @@ private:
|
||||
void locked_doMsgUpdateWork(const RsNxsTransac* nxsTrans, const RsGxsGroupId& grpId);
|
||||
|
||||
void updateServerSyncTS();
|
||||
void updateClientSyncTS();
|
||||
|
||||
bool locked_CanReceiveUpdate(const RsNxsSyncGrp* item);
|
||||
bool locked_CanReceiveUpdate(const RsNxsSyncMsg* item);
|
||||
@ -437,6 +448,7 @@ private:
|
||||
|
||||
void locked_stampPeerGroupUpdateTime(const RsPeerId& pid,const RsGxsGroupId& grpId,time_t tm,uint32_t n_messages) ;
|
||||
|
||||
void cleanRejectedMessages();
|
||||
private:
|
||||
|
||||
|
||||
@ -475,6 +487,7 @@ private:
|
||||
|
||||
uint32_t mSyncTs;
|
||||
uint32_t mLastKeyPublishTs;
|
||||
uint32_t mLastCleanRejectedMessages;
|
||||
|
||||
const uint32_t mSYNC_PERIOD;
|
||||
int mUpdateCounter ;
|
||||
@ -512,6 +525,9 @@ private:
|
||||
RsGxsServerGrpUpdateItem* mGrpServerUpdateItem;
|
||||
RsServiceInfo mServiceInfo;
|
||||
|
||||
std::map<RsGxsMessageId,time_t> mRejectedMessages;
|
||||
|
||||
void debugDump();
|
||||
};
|
||||
|
||||
#endif // RSGXSNETSERVICE_H
|
||||
|
@ -27,8 +27,13 @@
|
||||
|
||||
#include "rsgxsutil.h"
|
||||
#include "retroshare/rsgxsflags.h"
|
||||
#include "retroshare/rspeers.h"
|
||||
#include "pqi/pqihash.h"
|
||||
#include "gxs/rsgixs.h"
|
||||
|
||||
static const uint32_t MAX_GXS_IDS_REQUESTS_NET = 10 ; // max number of requests from cache/net (avoids killing the system!)
|
||||
|
||||
//#define GXSUTIL_DEBUG 1
|
||||
|
||||
RsGxsMessageCleanUp::RsGxsMessageCleanUp(RsGeneralDataService* const dataService, uint32_t messageStorePeriod, uint32_t chunkSize)
|
||||
: mDs(dataService), MESSAGE_STORE_PERIOD(messageStorePeriod), CHUNK_SIZE(chunkSize)
|
||||
@ -106,9 +111,8 @@ bool RsGxsMessageCleanUp::clean()
|
||||
return mGrpMeta.empty();
|
||||
}
|
||||
|
||||
RsGxsIntegrityCheck::RsGxsIntegrityCheck(
|
||||
RsGeneralDataService* const dataService) :
|
||||
mDs(dataService), mDone(false), mIntegrityMutex("integrity")
|
||||
RsGxsIntegrityCheck::RsGxsIntegrityCheck(RsGeneralDataService* const dataService, RsGixs *gixs) :
|
||||
mDs(dataService), mDone(false), mIntegrityMutex("integrity"),mGixs(gixs)
|
||||
{ }
|
||||
|
||||
void RsGxsIntegrityCheck::run()
|
||||
@ -118,122 +122,206 @@ void RsGxsIntegrityCheck::run()
|
||||
|
||||
bool RsGxsIntegrityCheck::check()
|
||||
{
|
||||
// first take out all the groups
|
||||
std::map<RsGxsGroupId, RsNxsGrp*> grp;
|
||||
mDs->retrieveNxsGrps(grp, true, true);
|
||||
std::vector<RsGxsGroupId> grpsToDel;
|
||||
GxsMsgReq msgIds;
|
||||
GxsMsgReq grps;
|
||||
|
||||
// first take out all the groups
|
||||
std::map<RsGxsGroupId, RsNxsGrp*> grp;
|
||||
mDs->retrieveNxsGrps(grp, true, true);
|
||||
std::vector<RsGxsGroupId> grpsToDel;
|
||||
GxsMsgReq msgIds;
|
||||
GxsMsgReq grps;
|
||||
std::set<RsGxsId> used_gxs_ids ;
|
||||
std::set<RsGxsGroupId> subscribed_groups ;
|
||||
|
||||
// compute hash and compare to stored value, if it fails then simply add it
|
||||
// to list
|
||||
std::map<RsGxsGroupId, RsNxsGrp*>::iterator git = grp.begin();
|
||||
for(; git != grp.end(); ++git)
|
||||
{
|
||||
RsNxsGrp* grp = git->second;
|
||||
RsFileHash currHash;
|
||||
pqihash pHash;
|
||||
pHash.addData(grp->grp.bin_data, grp->grp.bin_len);
|
||||
pHash.Complete(currHash);
|
||||
// compute hash and compare to stored value, if it fails then simply add it
|
||||
// to list
|
||||
std::map<RsGxsGroupId, RsNxsGrp*>::iterator git = grp.begin();
|
||||
for(; git != grp.end(); ++git)
|
||||
{
|
||||
RsNxsGrp* grp = git->second;
|
||||
RsFileHash currHash;
|
||||
pqihash pHash;
|
||||
pHash.addData(grp->grp.bin_data, grp->grp.bin_len);
|
||||
pHash.Complete(currHash);
|
||||
|
||||
if(currHash == grp->metaData->mHash)
|
||||
{
|
||||
// get all message ids of group
|
||||
if (mDs->retrieveMsgIds(grp->grpId, msgIds[grp->grpId]) == 1)
|
||||
{
|
||||
// store the group for retrieveNxsMsgs
|
||||
grps[grp->grpId];
|
||||
}
|
||||
else
|
||||
{
|
||||
msgIds.erase(msgIds.find(grp->grpId));
|
||||
// grpsToDel.push_back(grp->grpId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
grpsToDel.push_back(grp->grpId);
|
||||
}
|
||||
delete grp;
|
||||
}
|
||||
if(currHash == grp->metaData->mHash)
|
||||
{
|
||||
// get all message ids of group
|
||||
if (mDs->retrieveMsgIds(grp->grpId, msgIds[grp->grpId]) == 1)
|
||||
{
|
||||
// store the group for retrieveNxsMsgs
|
||||
grps[grp->grpId];
|
||||
|
||||
mDs->removeGroups(grpsToDel);
|
||||
if(grp->metaData->mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_SUBSCRIBED)
|
||||
{
|
||||
subscribed_groups.insert(git->first) ;
|
||||
|
||||
// now messages
|
||||
GxsMsgReq msgsToDel;
|
||||
GxsMsgResult msgs;
|
||||
if(!grp->metaData->mAuthorId.isNull())
|
||||
{
|
||||
#ifdef GXSUTIL_DEBUG
|
||||
std::cerr << "TimeStamping group authors' key ID " << grp->metaData->mAuthorId << " in group ID " << grp->grpId << std::endl;
|
||||
#endif
|
||||
|
||||
mDs->retrieveNxsMsgs(grps, msgs, false, true);
|
||||
used_gxs_ids.insert(grp->metaData->mAuthorId) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
msgIds.erase(msgIds.find(grp->grpId));
|
||||
// grpsToDel.push_back(grp->grpId);
|
||||
}
|
||||
|
||||
// check msg ids and messages
|
||||
GxsMsgReq::iterator msgIdsIt;
|
||||
for (msgIdsIt = msgIds.begin(); msgIdsIt != msgIds.end(); ++msgIdsIt)
|
||||
{
|
||||
const RsGxsGroupId& grpId = msgIdsIt->first;
|
||||
std::vector<RsGxsMessageId> &msgIdV = msgIdsIt->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
grpsToDel.push_back(grp->grpId);
|
||||
}
|
||||
delete grp;
|
||||
}
|
||||
|
||||
std::vector<RsGxsMessageId>::iterator msgIdIt;
|
||||
for (msgIdIt = msgIdV.begin(); msgIdIt != msgIdV.end(); ++msgIdIt)
|
||||
{
|
||||
const RsGxsMessageId& msgId = *msgIdIt;
|
||||
std::vector<RsNxsMsg*> &nxsMsgV = msgs[grpId];
|
||||
mDs->removeGroups(grpsToDel);
|
||||
|
||||
std::vector<RsNxsMsg*>::iterator nxsMsgIt;
|
||||
for (nxsMsgIt = nxsMsgV.begin(); nxsMsgIt != nxsMsgV.end(); ++nxsMsgIt)
|
||||
{
|
||||
RsNxsMsg *nxsMsg = *nxsMsgIt;
|
||||
if (nxsMsg && msgId == nxsMsg->msgId)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// now messages
|
||||
GxsMsgReq msgsToDel;
|
||||
GxsMsgResult msgs;
|
||||
|
||||
if (nxsMsgIt == nxsMsgV.end())
|
||||
{
|
||||
msgsToDel[grpId].push_back(msgId);
|
||||
}
|
||||
}
|
||||
}
|
||||
mDs->retrieveNxsMsgs(grps, msgs, false, true);
|
||||
|
||||
GxsMsgResult::iterator mit = msgs.begin();
|
||||
// check msg ids and messages
|
||||
GxsMsgReq::iterator msgIdsIt;
|
||||
for (msgIdsIt = msgIds.begin(); msgIdsIt != msgIds.end(); ++msgIdsIt)
|
||||
{
|
||||
const RsGxsGroupId& grpId = msgIdsIt->first;
|
||||
std::vector<RsGxsMessageId> &msgIdV = msgIdsIt->second;
|
||||
|
||||
for(; mit != msgs.end(); ++mit)
|
||||
{
|
||||
std::vector<RsNxsMsg*>& msgV = mit->second;
|
||||
std::vector<RsNxsMsg*>::iterator vit = msgV.begin();
|
||||
std::vector<RsGxsMessageId>::iterator msgIdIt;
|
||||
for (msgIdIt = msgIdV.begin(); msgIdIt != msgIdV.end(); ++msgIdIt)
|
||||
{
|
||||
const RsGxsMessageId& msgId = *msgIdIt;
|
||||
std::vector<RsNxsMsg*> &nxsMsgV = msgs[grpId];
|
||||
|
||||
for(; vit != msgV.end(); ++vit)
|
||||
{
|
||||
RsNxsMsg* msg = *vit;
|
||||
RsFileHash currHash;
|
||||
pqihash pHash;
|
||||
pHash.addData(msg->msg.bin_data, msg->msg.bin_len);
|
||||
pHash.Complete(currHash);
|
||||
std::vector<RsNxsMsg*>::iterator nxsMsgIt;
|
||||
for (nxsMsgIt = nxsMsgV.begin(); nxsMsgIt != nxsMsgV.end(); ++nxsMsgIt)
|
||||
{
|
||||
RsNxsMsg *nxsMsg = *nxsMsgIt;
|
||||
if (nxsMsg && msgId == nxsMsg->msgId)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(msg->metaData == NULL || currHash != msg->metaData->mHash)
|
||||
{
|
||||
std::cerr << "(EE) deleting message data with wrong hash or null meta data. meta=" << (void*)msg->metaData << std::endl;
|
||||
msgsToDel[msg->grpId].push_back(msg->msgId);
|
||||
}
|
||||
if (nxsMsgIt == nxsMsgV.end())
|
||||
{
|
||||
msgsToDel[grpId].push_back(msgId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete msg;
|
||||
}
|
||||
}
|
||||
GxsMsgResult::iterator mit = msgs.begin();
|
||||
|
||||
mDs->removeMsgs(msgsToDel);
|
||||
for(; mit != msgs.end(); ++mit)
|
||||
{
|
||||
std::vector<RsNxsMsg*>& msgV = mit->second;
|
||||
std::vector<RsNxsMsg*>::iterator vit = msgV.begin();
|
||||
|
||||
RsStackMutex stack(mIntegrityMutex);
|
||||
mDone = true;
|
||||
for(; vit != msgV.end(); ++vit)
|
||||
{
|
||||
RsNxsMsg* msg = *vit;
|
||||
RsFileHash currHash;
|
||||
pqihash pHash;
|
||||
pHash.addData(msg->msg.bin_data, msg->msg.bin_len);
|
||||
pHash.Complete(currHash);
|
||||
|
||||
std::vector<RsGxsGroupId>::iterator grpIt;
|
||||
for(grpIt = grpsToDel.begin(); grpIt != grpsToDel.end(); ++grpIt)
|
||||
{
|
||||
mDeletedGrps.push_back(*grpIt);
|
||||
}
|
||||
mDeletedMsgs = msgsToDel;
|
||||
if(msg->metaData == NULL || currHash != msg->metaData->mHash)
|
||||
{
|
||||
std::cerr << "(EE) deleting message data with wrong hash or null meta data. meta=" << (void*)msg->metaData << std::endl;
|
||||
msgsToDel[msg->grpId].push_back(msg->msgId);
|
||||
}
|
||||
else if(!msg->metaData->mAuthorId.isNull() && subscribed_groups.find(msg->metaData->mGroupId)!=subscribed_groups.end())
|
||||
{
|
||||
#ifdef GXSUTIL_DEBUG
|
||||
std::cerr << "TimeStamping message authors' key ID " << msg->metaData->mAuthorId << " in message " << msg->msgId << ", group ID " << msg->grpId<< std::endl;
|
||||
#endif
|
||||
used_gxs_ids.insert(msg->metaData->mAuthorId) ;
|
||||
}
|
||||
|
||||
return true;
|
||||
delete msg;
|
||||
}
|
||||
}
|
||||
|
||||
mDs->removeMsgs(msgsToDel);
|
||||
|
||||
RsStackMutex stack(mIntegrityMutex);
|
||||
mDone = true;
|
||||
|
||||
std::vector<RsGxsGroupId>::iterator grpIt;
|
||||
for(grpIt = grpsToDel.begin(); grpIt != grpsToDel.end(); ++grpIt)
|
||||
{
|
||||
mDeletedGrps.push_back(*grpIt);
|
||||
}
|
||||
mDeletedMsgs = msgsToDel;
|
||||
|
||||
#ifdef GXSUTIL_DEBUG
|
||||
std::cerr << "At end of pass, this is the list used GXS ids: " << std::endl;
|
||||
std::cerr << " requesting them to GXS identity service to enforce loading." << std::endl;
|
||||
#endif
|
||||
|
||||
std::list<RsPeerId> connected_friends ;
|
||||
rsPeers->getOnlineList(connected_friends) ;
|
||||
|
||||
std::vector<RsGxsId> gxs_ids ;
|
||||
|
||||
for(std::set<RsGxsId>::const_iterator it(used_gxs_ids.begin());it!=used_gxs_ids.end();++it)
|
||||
{
|
||||
gxs_ids.push_back(*it) ;
|
||||
#ifdef GXSUTIL_DEBUG
|
||||
std::cerr << " " << *it << std::endl;
|
||||
#endif
|
||||
}
|
||||
int nb_requested_not_in_cache = 0;
|
||||
|
||||
#ifdef GXSUTIL_DEBUG
|
||||
std::cerr << " issuing random get on friends for non existing IDs" << std::endl;
|
||||
#endif
|
||||
|
||||
// now request a cache update for them, which triggers downloading from friends, if missing.
|
||||
|
||||
for(;nb_requested_not_in_cache<MAX_GXS_IDS_REQUESTS_NET && gxs_ids.size()>0;)
|
||||
{
|
||||
uint32_t n = RSRandom::random_u32() % gxs_ids.size() ;
|
||||
#ifdef GXSUTIL_DEBUG
|
||||
std::cerr << " requesting ID " << gxs_ids[n] ;
|
||||
#endif
|
||||
|
||||
if(!mGixs->haveKey(gxs_ids[n])) // checks if we have it already in the cache (conservative way to ensure that we atually have it)
|
||||
{
|
||||
mGixs->requestKey(gxs_ids[n],connected_friends);
|
||||
|
||||
++nb_requested_not_in_cache ;
|
||||
#ifdef GXSUTIL_DEBUG
|
||||
std::cerr << " ... from cache/net" << std::endl;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef GXSUTIL_DEBUG
|
||||
std::cerr << " ... already in cache" << std::endl;
|
||||
#endif
|
||||
|
||||
// Note: we could time_stamp even in the case where the id is not cached. Anyway, it's not really a problem here, since IDs have a high chance of
|
||||
// behing eventually stamped.
|
||||
|
||||
mGixs->timeStampKey(gxs_ids[n]) ;
|
||||
}
|
||||
|
||||
gxs_ids[n] = gxs_ids[gxs_ids.size()-1] ;
|
||||
gxs_ids.pop_back() ;
|
||||
}
|
||||
#ifdef GXSUTIL_DEBUG
|
||||
std::cerr << " total actual cache requests: "<< nb_requested_not_in_cache << std::endl;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RsGxsIntegrityCheck::isDone()
|
||||
|
@ -30,6 +30,8 @@
|
||||
#include "serialiser/rsnxsitems.h"
|
||||
#include "rsgds.h"
|
||||
|
||||
class RsGixs ;
|
||||
|
||||
/*!
|
||||
* Handy function for cleaning out meta result containers
|
||||
* @param container
|
||||
@ -40,10 +42,9 @@ void freeAndClearContainerResource(Container container)
|
||||
typename Container::iterator meta_it = container.begin();
|
||||
|
||||
for(; meta_it != container.end(); ++meta_it)
|
||||
{
|
||||
delete meta_it->second;
|
||||
if(meta_it->second != NULL)
|
||||
delete meta_it->second;
|
||||
|
||||
}
|
||||
container.clear();
|
||||
}
|
||||
|
||||
@ -112,7 +113,7 @@ public:
|
||||
* @param chunkSize
|
||||
* @param sleepPeriod
|
||||
*/
|
||||
RsGxsIntegrityCheck(RsGeneralDataService* const dataService);
|
||||
RsGxsIntegrityCheck(RsGeneralDataService* const dataService, RsGixs *gixs);
|
||||
|
||||
|
||||
bool check();
|
||||
@ -129,6 +130,8 @@ private:
|
||||
RsMutex mIntegrityMutex;
|
||||
std::list<RsGxsGroupId> mDeletedGrps;
|
||||
std::map<RsGxsGroupId, std::vector<RsGxsMessageId> > mDeletedMsgs;
|
||||
|
||||
RsGixs *mGixs ;
|
||||
};
|
||||
|
||||
class GroupUpdate
|
||||
|
@ -127,6 +127,13 @@ public:
|
||||
*/
|
||||
virtual int sharePublishKey(const RsGxsGroupId& grpId,const std::set<RsPeerId>& peers)=0 ;
|
||||
|
||||
/*!
|
||||
* \brief rejectMessage
|
||||
* Tells the network exchange service to not download this message again, at least for some time (maybe 24h or more)
|
||||
* in order to avoid cluttering the network pipe with copied of this rejected message.
|
||||
* \param msgId
|
||||
*/
|
||||
virtual void rejectMessage(const RsGxsMessageId& msgId) =0;
|
||||
};
|
||||
|
||||
#endif // RSGNP_H
|
||||
|
1582
libretroshare/src/gxstunnel/p3gxstunnel.cc
Normal file
261
libretroshare/src/gxstunnel/p3gxstunnel.h
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* libretroshare/src/chat: distantchat.h
|
||||
*
|
||||
* Services for RetroShare.
|
||||
*
|
||||
* Copyright 2015 by Cyril Soler
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License Version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA.
|
||||
*
|
||||
* Please report all bugs and problems to "csoler@users.sourceforge.net".
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Generic tunnel service
|
||||
//
|
||||
// Preconditions:
|
||||
// * the secured tunnel service takes care of:
|
||||
// - tunnel health: tunnels are kept alive using special items, re-openned when necessary, etc.
|
||||
// - transport: items are ACK-ed and re-sent if never received
|
||||
// - encryption: items are all encrypted and authenticated using PFS(DH)+HMAC(sha1)+AES(128)
|
||||
// * each tunnel is associated to a specific GXS id on both sides. Consequently, services that request tunnels from different IDs to a
|
||||
// server for the same GXS id need to be handled correctly.
|
||||
// * client services must register to the secured tunnel service if they want to use it.
|
||||
// * multiple services can use the same tunnel. Items contain a service Id that is obtained when registering to the secured tunnel service.
|
||||
//
|
||||
// GUI
|
||||
// * the GUI should show for each tunnel:
|
||||
// - starting and ending GXS ids
|
||||
// - tunnel status (DH ok, closed from distant peer, locally closed, etc)
|
||||
// - amount of data that is transferred in the tunnel
|
||||
// - number of pending items (and total size)
|
||||
// - number ACKed items both ways.
|
||||
//
|
||||
// We can use an additional tab "Authenticated tunnels" in the statistics->turtle window for that purpose.
|
||||
//
|
||||
// Interaction with services:
|
||||
//
|
||||
// Services request tunnels from a given GXS id and to a given GXS id. When ready, they get a handle (type = RsGxsTunnelId)
|
||||
//
|
||||
// Services send data in the tunnel using the virtual peer id
|
||||
//
|
||||
// Data is send to a service ID (could be any existing service ID). The endpoint of the tunnel must register each service, in order to
|
||||
// allow the data to be transmitted/sent from/to that service. Otherwise an error is issued.
|
||||
//
|
||||
// Encryption
|
||||
// * the whole tunnel traffic is encrypted using AES-128 with random IV
|
||||
// * a random key is established using DH key exchange for each connection (establishment of a new virtual peer)
|
||||
// * encrypted items are authenticated with HMAC(sha1).
|
||||
// * DH public keys are the only chunks of data that travel un-encrypted along the tunnel. They are
|
||||
// signed to avoid any MITM interactions. No time-stamp is used in DH exchange since a replay attack would not work.
|
||||
//
|
||||
// Algorithms
|
||||
//
|
||||
// * we need two layers: the turtle layer, and the GXS id layer.
|
||||
// - for each pair of GXS ids talking, a single turtle tunnel is used
|
||||
// - that tunnel can be shared by multiple services using it.
|
||||
// - services are responsoble for asking tunnels and also droppping them when unused.
|
||||
// - at the turtle layer, the tunnel will be effectively closed only when no service uses it.
|
||||
// * IDs
|
||||
// TurtleVirtualPeerId:
|
||||
// - Used by tunnel service for each turtle tunnel
|
||||
// - one virtual peer ID per GXS tunnel
|
||||
//
|
||||
// GxsTunnelId:
|
||||
// - one GxsTunnelId per couple of GXS ids. But we also need to allow multiple services to use the tunnel.
|
||||
//
|
||||
// * at the turtle layer:
|
||||
// - accept virtual peers from turtle tunnel service. The hash for that VP only depends on the server GXS id at server side, which is our
|
||||
// own ID at server side, and destination ID at client side. What happens if two different clients request to talk to the same GXS id? (same hash)
|
||||
// They should use different virtual peers, so it should be ok.
|
||||
//
|
||||
// Turtle hash: [ 0 ---------------15 16---19 ]
|
||||
// Destination Random
|
||||
//
|
||||
// We Use 16 bytes to target the exact destination of the hash. The source part is just 4 arbitrary bytes that need to be different for all source
|
||||
// IDs that come from the same peer, which is quite likely to be sufficient. The real source of the tunnel will make itself known when sending the
|
||||
// DH key.
|
||||
//
|
||||
// * at the GXS layer
|
||||
// - we should be able to have as many tunnels as they are different couples of GXS ids to interact. That means the tunnel should be determined
|
||||
// by a mix between our own GXS id and the GXS id we're talking to. That is what the TunnelVirtualPeer is.
|
||||
//
|
||||
//
|
||||
// RequestTunnel(source_own_id,destination_id) -
|
||||
// | |
|
||||
// +---------------------------> p3Turtle::monitorTunnels( hash(destination_id) ) |
|
||||
// | |
|
||||
// [Turtle async work] -------------------+ | Turtle layer: one virtual peer id
|
||||
// | | |
|
||||
// handleTunnelRequest() <-----------------------------------------------+ | |
|
||||
// | | |
|
||||
// +---------------- keep record in _gxs_tunnel_virtual_peer_id, initiate DH exchange | -
|
||||
// | |
|
||||
// handleDHPublicKey() <-----------------------------------------------------------------------------+ |
|
||||
// | |
|
||||
// +---------------- update _gxs_tunnel_contacts[ tunnel_hash = hash(own_id, destination_id) ] | GxsTunnelId level
|
||||
// | |
|
||||
// +---------------- notify client service that Peer(destination_id, tunnel_hash) is ready to talk to |
|
||||
// -
|
||||
|
||||
#include <turtle/turtleclientservice.h>
|
||||
#include <retroshare/rsgxstunnel.h>
|
||||
#include <services/p3service.h>
|
||||
#include <gxstunnel/rsgxstunnelitems.h>
|
||||
|
||||
class RsGixs ;
|
||||
|
||||
static const uint32_t GXS_TUNNEL_AES_KEY_SIZE = 16 ;
|
||||
|
||||
class p3GxsTunnelService: public RsGxsTunnelService, public RsTurtleClientService, public p3Service
|
||||
{
|
||||
public:
|
||||
p3GxsTunnelService(RsGixs *pids) ;
|
||||
virtual void connectToTurtleRouter(p3turtle *) ;
|
||||
|
||||
// Creates the invite if the public key of the distant peer is available.
|
||||
// Om success, stores the invite in the map above, so that we can respond to tunnel requests.
|
||||
//
|
||||
virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,RsGxsTunnelId& tunnel_id,uint32_t service_id,uint32_t& error_code) ;
|
||||
|
||||
virtual bool closeExistingTunnel(const RsGxsTunnelId &tunnel_id,uint32_t service_id) ;
|
||||
virtual bool getTunnelsInfo(std::vector<GxsTunnelInfo>& infos);
|
||||
virtual bool getTunnelInfo(const RsGxsTunnelId& tunnel_id,GxsTunnelInfo& info);
|
||||
virtual bool sendData(const RsGxsTunnelId& tunnel_id,uint32_t service_id,const uint8_t *data,uint32_t size) ;
|
||||
|
||||
virtual bool registerClientService(uint32_t service_id,RsGxsTunnelClientService *service) ;
|
||||
|
||||
// derived from p3service
|
||||
|
||||
virtual int tick();
|
||||
virtual RsServiceInfo getServiceInfo();
|
||||
|
||||
private:
|
||||
void flush() ;
|
||||
virtual void handleIncomingItem(const RsGxsTunnelId &tunnel_id, RsGxsTunnelItem *) ;
|
||||
|
||||
class GxsTunnelPeerInfo
|
||||
{
|
||||
public:
|
||||
GxsTunnelPeerInfo() : last_contact(0), last_keep_alive_sent(0), status(0), direction(0)
|
||||
{
|
||||
memset(aes_key, 0, GXS_TUNNEL_AES_KEY_SIZE);
|
||||
|
||||
total_sent = 0 ;
|
||||
total_received = 0 ;
|
||||
}
|
||||
|
||||
time_t last_contact ; // used to keep track of working connexion
|
||||
time_t last_keep_alive_sent ; // last time we sent a keep alive packet.
|
||||
|
||||
unsigned char aes_key[GXS_TUNNEL_AES_KEY_SIZE] ;
|
||||
|
||||
uint32_t status ; // info: do we have a tunnel ?
|
||||
RsPeerId virtual_peer_id; // given by the turtle router. Identifies the tunnel.
|
||||
RsGxsId to_gxs_id; // gxs id we're talking to
|
||||
RsGxsId own_gxs_id ; // gxs id we're using to talk.
|
||||
RsTurtleGenericTunnelItem::Direction direction ; // specifiec wether we are client(managing the tunnel) or server.
|
||||
TurtleFileHash hash ; // hash that is last used. This is necessary for handling tunnel establishment
|
||||
std::set<uint32_t> client_services ;// services that used this tunnel
|
||||
uint32_t total_sent ;
|
||||
uint32_t total_received ;
|
||||
};
|
||||
|
||||
class GxsTunnelDHInfo
|
||||
{
|
||||
public:
|
||||
GxsTunnelDHInfo() : dh(0), direction(0), status(0) {}
|
||||
|
||||
DH *dh ;
|
||||
RsGxsId gxs_id ;
|
||||
RsGxsId own_gxs_id ;
|
||||
RsGxsTunnelId tunnel_id ; // this is a proxy, since we cna always recompute that from the two previous values.
|
||||
RsTurtleGenericTunnelItem::Direction direction ;
|
||||
uint32_t status ;
|
||||
TurtleFileHash hash ;
|
||||
};
|
||||
|
||||
struct GxsTunnelData
|
||||
{
|
||||
RsGxsTunnelDataItem *data_item ;
|
||||
time_t last_sending_attempt ;
|
||||
};
|
||||
|
||||
// This maps contains the current peers to talk to with distant chat.
|
||||
//
|
||||
std::map<RsGxsTunnelId,GxsTunnelPeerInfo> _gxs_tunnel_contacts ; // current peers we can talk to
|
||||
std::map<TurtleVirtualPeerId,GxsTunnelDHInfo> _gxs_tunnel_virtual_peer_ids ; // current virtual peers. Used to figure out tunnels, etc.
|
||||
|
||||
// List of items to be sent asap. Used to store items that we cannot pass directly to
|
||||
// sendTurtleData(), because of Mutex protection.
|
||||
|
||||
std::map<uint64_t,GxsTunnelData> pendingGxsTunnelDataItems ; // items that need provable transport and encryption
|
||||
std::list<RsGxsTunnelItem*> pendingGxsTunnelItems ; // items that do not need provable transport, yet need encryption
|
||||
std::list<RsGxsTunnelDHPublicKeyItem*> pendingDHItems ;
|
||||
|
||||
// Overloaded from RsTurtleClientService
|
||||
|
||||
virtual bool handleTunnelRequest(const RsFileHash &hash,const RsPeerId& peer_id) ;
|
||||
virtual void receiveTurtleData(RsTurtleGenericTunnelItem *item,const RsFileHash& hash,const RsPeerId& virtual_peer_id,RsTurtleGenericTunnelItem::Direction direction) ;
|
||||
void addVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&,RsTurtleGenericTunnelItem::Direction dir) ;
|
||||
void removeVirtualPeer(const TurtleFileHash&, const TurtleVirtualPeerId&) ;
|
||||
|
||||
// session handling handles
|
||||
|
||||
void startClientGxsTunnelConnection(const RsGxsId &to_gxs_id, const RsGxsId& from_gxs_id, uint32_t service_id, RsGxsTunnelId &tunnel_id) ;
|
||||
void locked_restartDHSession(const RsPeerId &virtual_peer_id, const RsGxsId &own_gxs_id) ;
|
||||
|
||||
// utility functions
|
||||
|
||||
static TurtleFileHash randomHashFromDestinationGxsId(const RsGxsId& destination) ;
|
||||
static RsGxsId destinationGxsIdFromHash(const TurtleFileHash& sum) ;
|
||||
|
||||
// Cryptography management
|
||||
|
||||
void handleRecvDHPublicKey(RsGxsTunnelDHPublicKeyItem *item) ;
|
||||
bool locked_sendDHPublicKey(const DH *dh, const RsGxsId& own_gxs_id, const RsPeerId& virtual_peer_id) ;
|
||||
bool locked_initDHSessionKey(DH *&dh);
|
||||
|
||||
TurtleVirtualPeerId virtualPeerIdFromHash(const TurtleFileHash& hash) ; // ... and to a hash for p3turtle
|
||||
RsGxsTunnelId makeGxsTunnelId(const RsGxsId &own_id, const RsGxsId &distant_id) const; // creates a unique ID from two GXS ids.
|
||||
|
||||
// item handling
|
||||
|
||||
void handleRecvStatusItem(const RsGxsTunnelId& id,RsGxsTunnelStatusItem *item) ;
|
||||
void handleRecvTunnelDataItem(const RsGxsTunnelId& id,RsGxsTunnelDataItem *item) ;
|
||||
void handleRecvTunnelDataAckItem(const RsGxsTunnelId &id, RsGxsTunnelDataAckItem *item);
|
||||
|
||||
// Comunication with Turtle service
|
||||
|
||||
bool locked_sendEncryptedTunnelData(RsGxsTunnelItem *item) ;
|
||||
bool locked_sendClearTunnelData(RsGxsTunnelDHPublicKeyItem *item); // this limits the usage to DH items. Others should be encrypted!
|
||||
|
||||
bool handleEncryptedData(const uint8_t *data_bytes,uint32_t data_size,const TurtleFileHash& hash,const RsPeerId& virtual_peer_id) ;
|
||||
|
||||
// local data
|
||||
|
||||
p3turtle *mTurtle ;
|
||||
RsGixs *mGixs ;
|
||||
RsMutex mGxsTunnelMtx ;
|
||||
|
||||
uint64_t global_item_counter ;
|
||||
|
||||
std::map<uint32_t,RsGxsTunnelClientService*> mRegisteredServices ;
|
||||
|
||||
void debug_dump();
|
||||
};
|
||||
|
486
libretroshare/src/gxstunnel/rsgxstunnelitems.cc
Normal file
@ -0,0 +1,486 @@
|
||||
|
||||
/*
|
||||
* libretroshare/src/serialiser: rsbaseitems.cc
|
||||
*
|
||||
* RetroShare Serialiser.
|
||||
*
|
||||
* Copyright 2007-2008 by Robert Fernie.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License Version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA.
|
||||
*
|
||||
* Please report all bugs and problems to "retroshare@lunamutt.com".
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdexcept>
|
||||
#include <time.h>
|
||||
#include "serialiser/rsbaseserial.h"
|
||||
#include "serialiser/rstlvbase.h"
|
||||
#include "util/rsprint.h"
|
||||
|
||||
#include "gxstunnel/rsgxstunnelitems.h"
|
||||
|
||||
#define GXS_TUNNEL_ITEM_DEBUG 1
|
||||
|
||||
std::ostream& RsGxsTunnelDHPublicKeyItem::print(std::ostream &out, uint16_t indent)
|
||||
{
|
||||
printRsItemBase(out, "RsGxsTunnelDHPublicKeyItem", indent);
|
||||
uint16_t int_Indent = indent + 2;
|
||||
|
||||
printIndent(out, int_Indent);
|
||||
out << " Signature Key ID: " << signature.keyId << std::endl ;
|
||||
out << " Public Key ID: " << gxs_key.keyId << std::endl ;
|
||||
|
||||
printRsItemEnd(out, "RsGxsTunnelMsgItem", indent);
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& RsGxsTunnelDataItem::print(std::ostream &out, uint16_t indent)
|
||||
{
|
||||
printRsItemBase(out, "RsGxsTunnelDataItem", indent);
|
||||
uint16_t int_Indent = indent + 2;
|
||||
|
||||
printIndent(out, int_Indent);
|
||||
out << " message id : " << std::hex << unique_item_counter << std::dec << std::endl ;
|
||||
out << " service id : " << std::hex << service_id << std::dec << std::endl ;
|
||||
out << " flags : " << std::hex << flags << std::dec << std::endl ;
|
||||
out << " size : " << data_size << std::endl ;
|
||||
out << " data : " << RsUtil::BinToHex(data,std::min(50u,data_size)) << ((data_size>50u)?"...":"") << std::endl ;
|
||||
|
||||
printRsItemEnd(out, "RsGxsTunnelDataItem", indent);
|
||||
return out;
|
||||
}
|
||||
std::ostream& RsGxsTunnelDataAckItem::print(std::ostream &out, uint16_t indent)
|
||||
{
|
||||
printRsItemBase(out, "RsGxsTunnelDataItem", indent);
|
||||
uint16_t int_Indent = indent + 2;
|
||||
|
||||
printIndent(out, int_Indent);
|
||||
out << " message id : " << std::hex << unique_item_counter << std::dec << std::endl ;
|
||||
|
||||
printRsItemEnd(out, "RsGxsTunnelDataAckItem", indent);
|
||||
return out;
|
||||
}
|
||||
std::ostream& RsGxsTunnelStatusItem::print(std::ostream &out, uint16_t indent)
|
||||
{
|
||||
printRsItemBase(out, "RsGxsTunnelDataItem", indent);
|
||||
uint16_t int_Indent = indent + 2;
|
||||
|
||||
printIndent(out, int_Indent);
|
||||
out << " flags : " << std::hex << status << std::dec << std::endl ;
|
||||
|
||||
printRsItemEnd(out, "RsGxsTunnelStatusItem", indent);
|
||||
return out;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
RsGxsTunnelDHPublicKeyItem::~RsGxsTunnelDHPublicKeyItem()
|
||||
{
|
||||
BN_free(public_key) ;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
RsItem *RsGxsTunnelSerialiser::deserialise(void *data, uint32_t *pktsize)
|
||||
{
|
||||
uint32_t rstype = getRsItemId(data);
|
||||
uint32_t rssize = getRsItemSize(data);
|
||||
|
||||
#ifdef GXS_TUNNEL_ITEM_DEBUG
|
||||
std::cerr << "deserializing packet..."<< std::endl ;
|
||||
#endif
|
||||
// look what we have...
|
||||
if (*pktsize < rssize) /* check size */
|
||||
{
|
||||
std::cerr << "GxsTunnel deserialisation: not enough size: pktsize=" << *pktsize << ", rssize=" << rssize << std::endl ;
|
||||
return NULL; /* not enough data */
|
||||
}
|
||||
|
||||
/* set the packet length */
|
||||
*pktsize = rssize;
|
||||
|
||||
/* ready to load */
|
||||
|
||||
if ((RS_PKT_VERSION_SERVICE != getRsItemVersion(rstype)) || (RS_SERVICE_TYPE_GXS_TUNNEL != getRsItemService(rstype)))
|
||||
{
|
||||
#ifdef GXS_TUNNEL_ITEM_DEBUG
|
||||
std::cerr << "GxsTunnel deserialisation: wrong type !" << std::endl ;
|
||||
#endif
|
||||
return NULL; /* wrong type */
|
||||
}
|
||||
|
||||
switch(getRsItemSubType(rstype))
|
||||
{
|
||||
case RS_PKT_SUBTYPE_GXS_TUNNEL_DH_PUBLIC_KEY: return deserialise_RsGxsTunnelDHPublicKeyItem(data,*pktsize) ;
|
||||
case RS_PKT_SUBTYPE_GXS_TUNNEL_DATA: return deserialise_RsGxsTunnelDataItem (data,*pktsize) ;
|
||||
case RS_PKT_SUBTYPE_GXS_TUNNEL_DATA_ACK: return deserialise_RsGxsTunnelDataAckItem (data,*pktsize) ;
|
||||
case RS_PKT_SUBTYPE_GXS_TUNNEL_STATUS: return deserialise_RsGxsTunnelStatusItem (data,*pktsize) ;
|
||||
default:
|
||||
std::cerr << "Unknown packet type in chat!" << std::endl ;
|
||||
return NULL ;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
uint32_t RsGxsTunnelDHPublicKeyItem::serial_size()
|
||||
{
|
||||
uint32_t s = 8 ; // header
|
||||
s += 4 ; // BN size
|
||||
s += BN_num_bytes(public_key) ; // public_key
|
||||
s += signature.TlvSize() ; // signature
|
||||
s += gxs_key.TlvSize() ; // gxs_key
|
||||
|
||||
return s ;
|
||||
}
|
||||
|
||||
uint32_t RsGxsTunnelDataItem::serial_size()
|
||||
{
|
||||
uint32_t s = 8 ; // header
|
||||
s += 8 ; // counter
|
||||
s += 4 ; // flags
|
||||
s += 4 ; // service id
|
||||
s += 4 ; // data_size
|
||||
s += data_size; // data
|
||||
|
||||
return s ;
|
||||
}
|
||||
|
||||
uint32_t RsGxsTunnelDataAckItem::serial_size()
|
||||
{
|
||||
uint32_t s = 8 ; // header
|
||||
s += 8 ; // counter
|
||||
|
||||
return s ;
|
||||
}
|
||||
|
||||
uint32_t RsGxsTunnelStatusItem::serial_size()
|
||||
{
|
||||
uint32_t s = 8 ; // header
|
||||
s += 4 ; // flags
|
||||
|
||||
return s ;
|
||||
}
|
||||
/*************************************************************************/
|
||||
|
||||
bool RsGxsTunnelDHPublicKeyItem::serialise(void *data,uint32_t& pktsize)
|
||||
{
|
||||
uint32_t tlvsize = serial_size() ;
|
||||
uint32_t offset = 0;
|
||||
|
||||
if (pktsize < tlvsize)
|
||||
return false; /* not enough space */
|
||||
|
||||
pktsize = tlvsize;
|
||||
|
||||
bool ok = true;
|
||||
|
||||
ok &= setRsItemHeader(data, tlvsize, PacketId(), tlvsize);
|
||||
|
||||
/* skip the header */
|
||||
offset += 8;
|
||||
|
||||
uint32_t s = BN_num_bytes(public_key) ;
|
||||
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, s);
|
||||
|
||||
BN_bn2bin(public_key,&((unsigned char *)data)[offset]) ;
|
||||
offset += s ;
|
||||
|
||||
ok &= signature.SetTlv(data, tlvsize, &offset);
|
||||
ok &= gxs_key.SetTlv(data, tlvsize, &offset);
|
||||
|
||||
if (offset != tlvsize)
|
||||
{
|
||||
ok = false;
|
||||
std::cerr << "RsGxsTunnelDHPublicKeyItem::serialiseItem() Size Error! offset=" << offset << ", tlvsize=" << tlvsize << std::endl;
|
||||
}
|
||||
return ok ;
|
||||
}
|
||||
|
||||
bool RsGxsTunnelStatusItem::serialise(void *data, uint32_t& pktsize)
|
||||
{
|
||||
uint32_t tlvsize = serial_size() ;
|
||||
uint32_t offset = 0;
|
||||
|
||||
if (pktsize < tlvsize)
|
||||
return false; /* not enough space */
|
||||
|
||||
pktsize = tlvsize;
|
||||
|
||||
bool ok = true;
|
||||
|
||||
ok &= setRsItemHeader(data, tlvsize, PacketId(), tlvsize);
|
||||
|
||||
#ifdef GXS_TUNNEL_ITEM_DEBUG
|
||||
std::cerr << "RsGxsTunnelSerialiser serialising chat status item." << std::endl;
|
||||
std::cerr << "RsGxsTunnelSerialiser::serialiseItem() Header: " << ok << std::endl;
|
||||
std::cerr << "RsGxsTunnelSerialiser::serialiseItem() Size: " << tlvsize << std::endl;
|
||||
#endif
|
||||
|
||||
/* skip the header */
|
||||
offset += 8;
|
||||
|
||||
/* add mandatory parts first */
|
||||
ok &= setRawUInt32(data, tlvsize, &offset, status);
|
||||
|
||||
if (offset != tlvsize)
|
||||
{
|
||||
ok = false;
|
||||
std::cerr << "RsGxsTunnelSerialiser::serialiseItem() Size Error! " << std::endl;
|
||||
}
|
||||
#ifdef GXS_TUNNEL_ITEM_DEBUG
|
||||
std::cerr << "computed size: " << 256*((unsigned char*)data)[6]+((unsigned char*)data)[7] << std::endl ;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool RsGxsTunnelDataItem::serialise(void *dt, uint32_t& pktsize)
|
||||
{
|
||||
uint32_t tlvsize = serial_size() ;
|
||||
uint32_t offset = 0;
|
||||
|
||||
if (pktsize < tlvsize)
|
||||
return false; /* not enough space */
|
||||
|
||||
pktsize = tlvsize;
|
||||
|
||||
bool ok = true;
|
||||
|
||||
ok &= setRsItemHeader(dt, tlvsize, PacketId(), tlvsize);
|
||||
|
||||
#ifdef GXS_TUNNEL_ITEM_DEBUG
|
||||
std::cerr << "RsGxsTunnelSerialiser serialising chat status item." << std::endl;
|
||||
std::cerr << "RsGxsTunnelSerialiser::serialiseItem() Header: " << ok << std::endl;
|
||||
std::cerr << "RsGxsTunnelSerialiser::serialiseItem() Size: " << tlvsize << std::endl;
|
||||
#endif
|
||||
|
||||
/* skip the header */
|
||||
offset += 8;
|
||||
|
||||
/* add mandatory parts first */
|
||||
ok &= setRawUInt64(dt, tlvsize, &offset, unique_item_counter);
|
||||
ok &= setRawUInt32(dt, tlvsize, &offset, flags);
|
||||
ok &= setRawUInt32(dt, tlvsize, &offset, service_id);
|
||||
ok &= setRawUInt32(dt, tlvsize, &offset, data_size);
|
||||
|
||||
if(offset + data_size <= tlvsize)
|
||||
{
|
||||
memcpy(&((uint8_t*)dt)[offset],data,data_size) ;
|
||||
offset += data_size ;
|
||||
}
|
||||
else
|
||||
ok = false ;
|
||||
|
||||
if (offset != tlvsize)
|
||||
{
|
||||
ok = false;
|
||||
std::cerr << "RsGxsTunnelSerialiser::serialiseItem() Size Error! " << std::endl;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
bool RsGxsTunnelDataAckItem::serialise(void *data, uint32_t& pktsize)
|
||||
{
|
||||
uint32_t tlvsize = serial_size() ;
|
||||
uint32_t offset = 0;
|
||||
|
||||
if (pktsize < tlvsize)
|
||||
return false; /* not enough space */
|
||||
|
||||
pktsize = tlvsize;
|
||||
|
||||
bool ok = true;
|
||||
|
||||
ok &= setRsItemHeader(data, tlvsize, PacketId(), tlvsize);
|
||||
|
||||
#ifdef GXS_TUNNEL_ITEM_DEBUG
|
||||
std::cerr << "RsGxsTunnelSerialiser serialising chat status item." << std::endl;
|
||||
std::cerr << "RsGxsTunnelSerialiser::serialiseItem() Header: " << ok << std::endl;
|
||||
std::cerr << "RsGxsTunnelSerialiser::serialiseItem() Size: " << tlvsize << std::endl;
|
||||
#endif
|
||||
|
||||
/* skip the header */
|
||||
offset += 8;
|
||||
|
||||
/* add mandatory parts first */
|
||||
ok &= setRawUInt64(data, tlvsize, &offset, unique_item_counter);
|
||||
|
||||
if (offset != tlvsize)
|
||||
{
|
||||
ok = false;
|
||||
std::cerr << "RsGxsTunnelSerialiser::serialiseItem() Size Error! " << std::endl;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
RsGxsTunnelDHPublicKeyItem *RsGxsTunnelSerialiser::deserialise_RsGxsTunnelDHPublicKeyItem(void *data,uint32_t /*size*/)
|
||||
{
|
||||
uint32_t offset = 8; // skip the header
|
||||
uint32_t rssize = getRsItemSize(data);
|
||||
bool ok = true ;
|
||||
|
||||
RsGxsTunnelDHPublicKeyItem *item = new RsGxsTunnelDHPublicKeyItem() ;
|
||||
|
||||
uint32_t s=0 ;
|
||||
/* get mandatory parts first */
|
||||
ok &= getRawUInt32(data, rssize, &offset, &s);
|
||||
|
||||
item->public_key = BN_bin2bn(&((unsigned char *)data)[offset],s,NULL) ;
|
||||
offset += s ;
|
||||
|
||||
ok &= item->signature.GetTlv(data, rssize, &offset) ;
|
||||
ok &= item->gxs_key.GetTlv(data, rssize, &offset) ;
|
||||
|
||||
if (offset != rssize)
|
||||
{
|
||||
std::cerr << "RsGxsTunnelDHPublicKeyItem::() Size error while deserializing." << std::endl ;
|
||||
delete item ;
|
||||
return NULL ;
|
||||
}
|
||||
if (!ok)
|
||||
{
|
||||
std::cerr << "RsGxsTunnelDHPublicKeyItem::() Unknown error while deserializing." << std::endl ;
|
||||
delete item ;
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
return item ;
|
||||
}
|
||||
|
||||
RsGxsTunnelDataItem *RsGxsTunnelSerialiser::deserialise_RsGxsTunnelDataItem(void *dat,uint32_t size)
|
||||
{
|
||||
uint32_t offset = 8; // skip the header
|
||||
uint32_t rssize = getRsItemSize(dat);
|
||||
bool ok = true ;
|
||||
|
||||
RsGxsTunnelDataItem *item = new RsGxsTunnelDataItem();
|
||||
|
||||
/* get mandatory parts first */
|
||||
|
||||
ok &= getRawUInt64(dat, rssize, &offset, &item->unique_item_counter);
|
||||
ok &= getRawUInt32(dat, rssize, &offset, &item->flags);
|
||||
ok &= getRawUInt32(dat, rssize, &offset, &item->service_id);
|
||||
ok &= getRawUInt32(dat, rssize, &offset, &item->data_size);
|
||||
|
||||
if(offset + item->data_size <= size)
|
||||
{
|
||||
item->data = (unsigned char*)malloc(item->data_size) ;
|
||||
|
||||
if(dat == NULL)
|
||||
{
|
||||
delete item ;
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
memcpy(item->data,&((uint8_t*)dat)[offset],item->data_size) ;
|
||||
offset += item->data_size ;
|
||||
}
|
||||
else
|
||||
ok = false ;
|
||||
|
||||
|
||||
if (offset != rssize)
|
||||
{
|
||||
std::cerr << "RsGxsTunnelDHPublicKeyItem::() Size error while deserializing." << std::endl ;
|
||||
delete item ;
|
||||
return NULL ;
|
||||
}
|
||||
if (!ok)
|
||||
{
|
||||
std::cerr << "RsGxsTunnelDHPublicKeyItem::() Unknown error while deserializing." << std::endl ;
|
||||
delete item ;
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
return item ;
|
||||
}
|
||||
|
||||
RsGxsTunnelDataAckItem *RsGxsTunnelSerialiser::deserialise_RsGxsTunnelDataAckItem(void *dat,uint32_t /* size */)
|
||||
{
|
||||
uint32_t offset = 8; // skip the header
|
||||
uint32_t rssize = getRsItemSize(dat);
|
||||
bool ok = true ;
|
||||
|
||||
RsGxsTunnelDataAckItem *item = new RsGxsTunnelDataAckItem();
|
||||
|
||||
/* get mandatory parts first */
|
||||
|
||||
ok &= getRawUInt64(dat, rssize, &offset, &item->unique_item_counter);
|
||||
|
||||
if (offset != rssize)
|
||||
{
|
||||
std::cerr << "RsGxsTunnelDHPublicKeyItem::() Size error while deserializing." << std::endl ;
|
||||
delete item ;
|
||||
return NULL ;
|
||||
}
|
||||
if (!ok)
|
||||
{
|
||||
std::cerr << "RsGxsTunnelDHPublicKeyItem::() Unknown error while deserializing." << std::endl ;
|
||||
delete item ;
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
return item ;
|
||||
}
|
||||
|
||||
RsGxsTunnelStatusItem *RsGxsTunnelSerialiser::deserialise_RsGxsTunnelStatusItem(void *dat,uint32_t size)
|
||||
{
|
||||
uint32_t offset = 8; // skip the header
|
||||
uint32_t rssize = getRsItemSize(dat);
|
||||
bool ok = true ;
|
||||
|
||||
RsGxsTunnelStatusItem *item = new RsGxsTunnelStatusItem();
|
||||
|
||||
/* get mandatory parts first */
|
||||
|
||||
ok &= getRawUInt32(dat, rssize, &offset, &item->status);
|
||||
|
||||
if (offset != rssize)
|
||||
{
|
||||
std::cerr << "RsGxsTunnelDHPublicKeyItem::() Size error while deserializing." << std::endl ;
|
||||
delete item ;
|
||||
return NULL ;
|
||||
}
|
||||
if (!ok)
|
||||
{
|
||||
std::cerr << "RsGxsTunnelDHPublicKeyItem::() Unknown error while deserializing." << std::endl ;
|
||||
delete item ;
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
return item ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
177
libretroshare/src/gxstunnel/rsgxstunnelitems.h
Normal file
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* libretroshare/src/serialiser: rschatitems.h
|
||||
*
|
||||
* RetroShare Serialiser.
|
||||
*
|
||||
* Copyright 2007-2008 by Robert Fernie.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License Version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA.
|
||||
*
|
||||
* Please report all bugs and problems to "retroshare@lunamutt.com".
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include "retroshare/rstypes.h"
|
||||
#include "serialiser/rstlvkeys.h"
|
||||
#include "serialiser/rsserviceids.h"
|
||||
#include "serialiser/rsserial.h"
|
||||
|
||||
#include "serialiser/rstlvidset.h"
|
||||
#include "serialiser/rstlvfileitem.h"
|
||||
|
||||
/* chat Flags */
|
||||
const uint32_t RS_GXS_TUNNEL_FLAG_CLOSING_DISTANT_CONNECTION = 0x0400;
|
||||
const uint32_t RS_GXS_TUNNEL_FLAG_ACK_DISTANT_CONNECTION = 0x0800;
|
||||
const uint32_t RS_GXS_TUNNEL_FLAG_KEEP_ALIVE = 0x1000;
|
||||
|
||||
const uint8_t RS_PKT_SUBTYPE_GXS_TUNNEL_DATA = 0x01 ;
|
||||
const uint8_t RS_PKT_SUBTYPE_GXS_TUNNEL_DH_PUBLIC_KEY = 0x02 ;
|
||||
const uint8_t RS_PKT_SUBTYPE_GXS_TUNNEL_STATUS = 0x03 ;
|
||||
const uint8_t RS_PKT_SUBTYPE_GXS_TUNNEL_DATA_ACK = 0x04 ;
|
||||
|
||||
typedef uint64_t GxsTunnelDHSessionId ;
|
||||
|
||||
class RsGxsTunnelItem: public RsItem
|
||||
{
|
||||
public:
|
||||
RsGxsTunnelItem(uint8_t item_subtype) : RsItem(RS_PKT_VERSION_SERVICE,RS_SERVICE_TYPE_GXS_TUNNEL,item_subtype)
|
||||
{
|
||||
setPriorityLevel(QOS_PRIORITY_RS_CHAT_ITEM) ;
|
||||
}
|
||||
|
||||
virtual ~RsGxsTunnelItem() {}
|
||||
virtual void clear() {}
|
||||
virtual std::ostream& print(std::ostream &out, uint16_t indent = 0) = 0 ;
|
||||
|
||||
virtual bool serialise(void *data,uint32_t& size) = 0 ; // Isn't it better that items can serialize themselves ?
|
||||
virtual uint32_t serial_size() = 0 ; // deserialise is handled using a constructor
|
||||
};
|
||||
|
||||
/*!
|
||||
* For sending distant communication data. The item is not encrypted after being serialised, but the data it.
|
||||
* The MAC is computed over encrypted data using the PFS key. All other items (except DH keys) are serialised, encrypted, and
|
||||
* sent as data in a RsGxsTunnelDataItem.
|
||||
*
|
||||
* @see p3GxsTunnelService
|
||||
*/
|
||||
class RsGxsTunnelDataItem: public RsGxsTunnelItem
|
||||
{
|
||||
public:
|
||||
RsGxsTunnelDataItem() :RsGxsTunnelItem(RS_PKT_SUBTYPE_GXS_TUNNEL_DATA) { data=NULL ;data_size=0; }
|
||||
RsGxsTunnelDataItem(uint8_t subtype) :RsGxsTunnelItem(subtype) { data=NULL ;data_size=0; }
|
||||
|
||||
virtual ~RsGxsTunnelDataItem() {}
|
||||
virtual void clear() {}
|
||||
virtual std::ostream& print(std::ostream &out, uint16_t indent = 0);
|
||||
|
||||
virtual bool serialise(void *data,uint32_t& size) ; // Isn't it better that items can serialize themselves ?
|
||||
virtual uint32_t serial_size() ; // deserialise is handled using a constructor
|
||||
|
||||
uint64_t unique_item_counter; // this allows to make the item unique
|
||||
uint32_t flags; // mainly NEEDS_HACK?
|
||||
uint32_t service_id ;
|
||||
uint32_t data_size ; // encrypted data size
|
||||
unsigned char *data ; // encrypted data
|
||||
};
|
||||
|
||||
// Used to send status of connection. This can be closing orders, flushing orders, etc.
|
||||
// These items are always sent encrypted.
|
||||
|
||||
class RsGxsTunnelStatusItem: public RsGxsTunnelItem
|
||||
{
|
||||
public:
|
||||
RsGxsTunnelStatusItem() :RsGxsTunnelItem(RS_PKT_SUBTYPE_GXS_TUNNEL_STATUS) {}
|
||||
RsGxsTunnelStatusItem(void *data,uint32_t size) ; // deserialization
|
||||
|
||||
virtual ~RsGxsTunnelStatusItem() {}
|
||||
virtual std::ostream& print(std::ostream &out, uint16_t indent = 0);
|
||||
|
||||
virtual bool serialise(void *data,uint32_t& size) ; // Isn't it better that items can serialize themselves ?
|
||||
virtual uint32_t serial_size() ; // deserialise is handled using a constructor
|
||||
|
||||
uint32_t status ;
|
||||
};
|
||||
|
||||
// Used to confirm reception of an encrypted item.
|
||||
|
||||
class RsGxsTunnelDataAckItem: public RsGxsTunnelItem
|
||||
{
|
||||
public:
|
||||
RsGxsTunnelDataAckItem() :RsGxsTunnelItem(RS_PKT_SUBTYPE_GXS_TUNNEL_DATA_ACK) {}
|
||||
RsGxsTunnelDataAckItem(void *data,uint32_t size) ; // deserialization
|
||||
|
||||
virtual ~RsGxsTunnelDataAckItem() {}
|
||||
virtual std::ostream& print(std::ostream &out, uint16_t indent = 0);
|
||||
|
||||
virtual bool serialise(void *data,uint32_t& size) ; // Isn't it better that items can serialize themselves ?
|
||||
virtual uint32_t serial_size() ; // deserialise is handled using a constructor
|
||||
|
||||
uint64_t unique_item_counter ; // unique identifier for that item
|
||||
};
|
||||
|
||||
|
||||
// This class contains the public Diffie-Hellman parameters to be sent
|
||||
// when performing a DH agreement over a distant chat tunnel.
|
||||
//
|
||||
class RsGxsTunnelDHPublicKeyItem: public RsGxsTunnelItem
|
||||
{
|
||||
public:
|
||||
RsGxsTunnelDHPublicKeyItem() :RsGxsTunnelItem(RS_PKT_SUBTYPE_GXS_TUNNEL_DH_PUBLIC_KEY) {}
|
||||
RsGxsTunnelDHPublicKeyItem(void *data,uint32_t size) ; // deserialization
|
||||
|
||||
virtual ~RsGxsTunnelDHPublicKeyItem() ;
|
||||
virtual std::ostream& print(std::ostream &out, uint16_t indent = 0);
|
||||
|
||||
virtual bool serialise(void *data,uint32_t& size) ; // Isn't it better that items can serialize themselves ?
|
||||
virtual uint32_t serial_size() ; // deserialise is handled using a constructor
|
||||
|
||||
// Private data to DH public key item
|
||||
//
|
||||
BIGNUM *public_key ;
|
||||
|
||||
RsTlvKeySignature signature ; // signs the public key in a row.
|
||||
RsTlvSecurityKey gxs_key ; // public key of the signer
|
||||
|
||||
private:
|
||||
// make the object non copy-able
|
||||
RsGxsTunnelDHPublicKeyItem(const RsGxsTunnelDHPublicKeyItem&) : RsGxsTunnelItem(RS_PKT_SUBTYPE_GXS_TUNNEL_DH_PUBLIC_KEY) {}
|
||||
const RsGxsTunnelDHPublicKeyItem& operator=(const RsGxsTunnelDHPublicKeyItem&) { return *this ;}
|
||||
};
|
||||
|
||||
class RsGxsTunnelSerialiser: public RsSerialType
|
||||
{
|
||||
public:
|
||||
RsGxsTunnelSerialiser() :RsSerialType(RS_PKT_VERSION_SERVICE, RS_SERVICE_TYPE_GXS_TUNNEL) {}
|
||||
|
||||
virtual uint32_t size (RsItem *item)
|
||||
{
|
||||
return static_cast<RsGxsTunnelItem *>(item)->serial_size() ;
|
||||
}
|
||||
virtual bool serialise(RsItem *item, void *data, uint32_t *size)
|
||||
{
|
||||
return static_cast<RsGxsTunnelItem *>(item)->serialise(data,*size) ;
|
||||
}
|
||||
RsItem *deserialise(void *data, uint32_t *pktsize);
|
||||
private:
|
||||
static RsGxsTunnelDataAckItem *deserialise_RsGxsTunnelDataAckItem (void *data, uint32_t size) ;
|
||||
static RsGxsTunnelDataItem *deserialise_RsGxsTunnelDataItem (void *data, uint32_t size) ;
|
||||
static RsGxsTunnelStatusItem *deserialise_RsGxsTunnelStatusItem (void *data, uint32_t size) ;
|
||||
static RsGxsTunnelDHPublicKeyItem *deserialise_RsGxsTunnelDHPublicKeyItem(void *data, uint32_t size) ;
|
||||
};
|
||||
|
@ -731,6 +731,13 @@ SOURCES += serialiser/rsnxsitems.cc \
|
||||
gxs/rsgxsutil.cc \
|
||||
gxs/rsgxsrequesttypes.cc
|
||||
|
||||
# gxs tunnels
|
||||
HEADERS += gxstunnel/p3gxstunnel.h \
|
||||
gxstunnel/rsgxstunnelitems.h \
|
||||
retroshare/rsgxstunnel.h
|
||||
|
||||
SOURCES += gxstunnel/p3gxstunnel.cc \
|
||||
gxstunnel/rsgxstunnelitems.cc
|
||||
|
||||
# Identity Service
|
||||
HEADERS += retroshare/rsidentity.h \
|
||||
@ -851,3 +858,4 @@ test_bitdht {
|
||||
|
||||
# ENABLED UDP NOW.
|
||||
}
|
||||
|
||||
|
@ -208,7 +208,7 @@ p3Config::p3Config()
|
||||
}
|
||||
|
||||
|
||||
bool p3Config::loadConfiguration(RsFileHash &loadHash)
|
||||
bool p3Config::loadConfiguration(RsFileHash& /* loadHash */)
|
||||
{
|
||||
return loadConfig();
|
||||
}
|
||||
|
@ -103,17 +103,14 @@ void p3HistoryMgr::addMessage(const ChatMessage& cm)
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
if (cm.chat_id.isGxsId() && mPrivateEnable == true) {
|
||||
if (cm.incoming) {
|
||||
peerName = cm.chat_id.toGxsId().toStdString();
|
||||
} else {
|
||||
uint32_t status;
|
||||
RsGxsId from_gxs_id;
|
||||
if (rsMsgs->getDistantChatStatus(cm.chat_id.toGxsId(), status, &from_gxs_id))
|
||||
peerName = from_gxs_id.toStdString();
|
||||
}
|
||||
enabled = true;
|
||||
}
|
||||
if(cm.chat_id.isDistantChatId())
|
||||
{
|
||||
uint32_t status;
|
||||
DistantChatPeerInfo dcpinfo;
|
||||
if (rsMsgs->getDistantChatStatus(cm.chat_id.toDistantChatId(), dcpinfo))
|
||||
peerName = cm.chat_id.toPeerId().toStdString();
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
if(enabled == false)
|
||||
return;
|
||||
@ -411,8 +408,8 @@ bool p3HistoryMgr::chatIdToVirtualPeerId(ChatId chat_id, RsPeerId &peer_id)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (chat_id.isGxsId()) {
|
||||
peer_id = RsPeerId(chat_id.toGxsId());
|
||||
if (chat_id.isDistantChatId()) {
|
||||
peer_id = RsPeerId(chat_id.toDistantChatId());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -450,7 +447,7 @@ bool p3HistoryMgr::getMessages(const ChatId &chatId, std::list<HistoryMsg> &msgs
|
||||
if (chatId.isLobbyId() && mLobbyEnable == true) {
|
||||
enabled = true;
|
||||
}
|
||||
if (chatId.isGxsId() && mPrivateEnable == true) {
|
||||
if (chatId.isDistantChatId() && mPrivateEnable == true) {
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
|
@ -38,23 +38,16 @@ const int pqipersonzone = 82371;
|
||||
* #define PERSON_DEBUG 1
|
||||
****/
|
||||
|
||||
pqiperson::pqiperson(const RsPeerId& id, pqipersongrp *pg)
|
||||
:PQInterface(id), mNotifyMtx("pqiperson-notify"), mPersonMtx("pqiperson"),
|
||||
active(false), activepqi(NULL),
|
||||
inConnectAttempt(false), waittimes(0),
|
||||
pqipg(pg)
|
||||
{
|
||||
|
||||
/* must check id! */
|
||||
|
||||
return;
|
||||
}
|
||||
pqiperson::pqiperson(const RsPeerId& id, pqipersongrp *pg) :
|
||||
PQInterface(id), mNotifyMtx("pqiperson-notify"), mPersonMtx("pqiperson"),
|
||||
active(false), activepqi(NULL), inConnectAttempt(false), waittimes(0),
|
||||
pqipg(pg) {} // TODO: must check id!
|
||||
|
||||
pqiperson::~pqiperson()
|
||||
{
|
||||
RsStackMutex stack(mPersonMtx); /**** LOCK MUTEX ****/
|
||||
RS_STACK_MUTEX(mPersonMtx);
|
||||
|
||||
// clean up the children.
|
||||
// clean up the childrens
|
||||
std::map<uint32_t, pqiconnect *>::iterator it;
|
||||
for(it = kids.begin(); it != kids.end(); ++it)
|
||||
{
|
||||
@ -64,13 +57,11 @@ pqiperson::~pqiperson()
|
||||
kids.clear();
|
||||
}
|
||||
|
||||
|
||||
// The PQInterface interface.
|
||||
int pqiperson::SendItem(RsItem *i,uint32_t& serialized_size)
|
||||
int pqiperson::SendItem(RsItem *i,uint32_t& serialized_size)
|
||||
{
|
||||
RsStackMutex stack(mPersonMtx); /**** LOCK MUTEX ****/
|
||||
RS_STACK_MUTEX(mPersonMtx);
|
||||
|
||||
if (active)
|
||||
if(active)
|
||||
{
|
||||
// every outgoing item goes through this function, so try to not waste cpu cycles
|
||||
// check if debug output is wanted, to avoid unecessary work
|
||||
@ -103,10 +94,10 @@ int pqiperson::SendItem(RsItem *i,uint32_t& serialized_size)
|
||||
|
||||
RsItem *pqiperson::GetItem()
|
||||
{
|
||||
RsStackMutex stack(mPersonMtx); /**** LOCK MUTEX ****/
|
||||
RS_STACK_MUTEX(mPersonMtx);
|
||||
|
||||
if (active)
|
||||
return activepqi -> GetItem();
|
||||
return activepqi->GetItem();
|
||||
// else not possible.
|
||||
return NULL;
|
||||
}
|
||||
@ -114,58 +105,63 @@ RsItem *pqiperson::GetItem()
|
||||
bool pqiperson::RecvItem(RsItem *item)
|
||||
{
|
||||
#ifdef PERSON_DEBUG
|
||||
std::cerr << "pqiperson::RecvItem()";
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "pqiperson::RecvItem()" << std::endl;
|
||||
#endif
|
||||
|
||||
return pqipg->recvItem((RsRawItem *) item);
|
||||
}
|
||||
|
||||
|
||||
int pqiperson::status()
|
||||
int pqiperson::status()
|
||||
{
|
||||
RsStackMutex stack(mPersonMtx); /**** LOCK MUTEX ****/
|
||||
RS_STACK_MUTEX(mPersonMtx);
|
||||
|
||||
if (active)
|
||||
return activepqi -> status();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pqiperson::receiveHeartbeat()
|
||||
int pqiperson::receiveHeartbeat()
|
||||
{
|
||||
RsStackMutex stack(mPersonMtx); /**** LOCK MUTEX ****/
|
||||
#ifdef PERSON_DEBUG
|
||||
std::cerr << "pqiperson::receiveHeartbeat() from peer : "
|
||||
<< PeerId().toStdString() << std::endl;
|
||||
#endif
|
||||
|
||||
pqioutput(PQL_WARNING, pqipersonzone, "pqiperson::receiveHeartbeat() from peer : " + PeerId().toStdString());
|
||||
lastHeartbeatReceived = time(NULL);
|
||||
RS_STACK_MUTEX(mPersonMtx);
|
||||
lastHeartbeatReceived = time(NULL);
|
||||
|
||||
return true ;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// tick......
|
||||
int pqiperson::tick()
|
||||
{
|
||||
int activeTick = 0;
|
||||
{
|
||||
RsStackMutex stack(mPersonMtx); /**** LOCK MUTEX ****/
|
||||
|
||||
//if lastHeartbeatReceived is 0, it might be not activated so don't do a net reset.
|
||||
if (active && (lastHeartbeatReceived != 0) &&
|
||||
(time(NULL) - lastHeartbeatReceived) > HEARTBEAT_REPEAT_TIME * 5)
|
||||
{
|
||||
RS_STACK_MUTEX(mPersonMtx);
|
||||
|
||||
//if lastHeartbeatReceived is 0, it might be not activated so don't do a net reset.
|
||||
if ( active && (lastHeartbeatReceived != 0)
|
||||
&& (time(NULL) - lastHeartbeatReceived) > HEARTBEAT_REPEAT_TIME * 5)
|
||||
{
|
||||
int ageLastIncoming = time(NULL) - activepqi->getLastIncomingTS();
|
||||
std::string out = "pqiperson::tick() WARNING No heartbeat from: " + PeerId().toStdString();
|
||||
//out << " assume dead. calling pqissl::reset(), LastHeartbeat was: ";
|
||||
rs_sprintf_append(out, " LastHeartbeat was: %ld secs ago", time(NULL) - lastHeartbeatReceived);
|
||||
rs_sprintf_append(out, " LastIncoming was: %d secs ago", ageLastIncoming);
|
||||
pqioutput(PQL_WARNING, pqipersonzone, out);
|
||||
|
||||
#define NO_PACKET_TIMEOUT 60
|
||||
#ifdef PERSON_DEBUG
|
||||
std::cerr << "pqiperson::tick() WARNING No heartbeat from: "
|
||||
<< PeerId().toStdString() << " LastHeartbeat was: "
|
||||
<< time(NULL) - lastHeartbeatReceived
|
||||
<< "secs ago LastIncoming was: " << ageLastIncoming
|
||||
<< "secs ago" << std::endl;
|
||||
#endif
|
||||
|
||||
if (ageLastIncoming > NO_PACKET_TIMEOUT)
|
||||
if (ageLastIncoming > 60) // Check timeout
|
||||
{
|
||||
out = "pqiperson::tick() " + PeerId().toStdString();
|
||||
out += " No Heartbeat & No Packets -> assume dead. calling pqissl::reset()";
|
||||
pqioutput(PQL_WARNING, pqipersonzone, out);
|
||||
#ifdef PERSON_DEBUG
|
||||
std::cerr << "pqiperson::tick() " << PeerId().toStdString()
|
||||
<< " No Heartbeat & No Packets -> assume dead."
|
||||
<< "calling pqissl::reset()" << std::endl;
|
||||
#endif
|
||||
|
||||
this->reset_locked();
|
||||
}
|
||||
@ -174,34 +170,31 @@ int pqiperson::tick()
|
||||
|
||||
|
||||
{
|
||||
std::string out = "pqiperson::tick() Id: " + PeerId().toStdString() + " ";
|
||||
#ifdef PERSON_DEBUG
|
||||
std::string statusStr = " inactive ";
|
||||
if (active)
|
||||
out += "***Active***";
|
||||
else
|
||||
out += ">>InActive<<";
|
||||
|
||||
out += "\n";
|
||||
rs_sprintf_append(out, "Activepqi: %p inConnectAttempt: ", activepqi);
|
||||
statusStr = " active ";
|
||||
|
||||
std::string connectStr = " Not Connecting ";
|
||||
if (inConnectAttempt)
|
||||
out += "In Connection Attempt";
|
||||
else
|
||||
out += " Not Connecting ";
|
||||
out += "\n";
|
||||
connectStr = " In Connection Attempt ";
|
||||
|
||||
std::cerr << "pqiperson::tick() Id: " << PeerId().toStdString()
|
||||
<< "activepqi: " << activepqi << " inConnectAttempt:"
|
||||
<< connectStr << std::endl;
|
||||
#endif
|
||||
|
||||
// tick the children.
|
||||
std::map<uint32_t, pqiconnect *>::iterator it;
|
||||
for(it = kids.begin(); it != kids.end(); ++it)
|
||||
{
|
||||
if (0 < (it->second) -> tick())
|
||||
{
|
||||
if (0 < (it->second)->tick())
|
||||
activeTick = 1;
|
||||
}
|
||||
rs_sprintf_append(out, "\tTicking Child: %d\n", it->first);
|
||||
#ifdef PERSON_DEBUG
|
||||
std::cerr << "\tTicking Child: "<< it->first << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
pqioutput(PQL_DEBUG_ALL, pqipersonzone, out);
|
||||
} // end of pqioutput.
|
||||
}
|
||||
}
|
||||
|
||||
// handle Notify Events that were generated.
|
||||
@ -214,44 +207,41 @@ int pqiperson::tick()
|
||||
// This is only used for out-of-band info....
|
||||
// otherwise could get dangerous loops.
|
||||
// - Actually, now we have - must store and process later.
|
||||
int pqiperson::notifyEvent(NetInterface *ni, int newState, const struct sockaddr_storage &remote_peer_address)
|
||||
int pqiperson::notifyEvent(NetInterface *ni, int newState,
|
||||
const sockaddr_storage &remote_peer_address)
|
||||
{
|
||||
#ifdef PERSON_DEBUG
|
||||
std::cerr << "pqiperson::notifyEvent() adding event to Queue. newState=" << newState << " from IP = " << sockaddr_storage_tostring(remote_peer_address) << std::endl;
|
||||
std::cerr << "pqiperson::notifyEvent() adding event to Queue. newState="
|
||||
<< newState << " from IP = "
|
||||
<< sockaddr_storage_tostring(remote_peer_address) << std::endl;
|
||||
#endif
|
||||
|
||||
if (mPersonMtx.trylock())
|
||||
{
|
||||
handleNotifyEvent_locked(ni, newState, remote_peer_address);
|
||||
|
||||
mPersonMtx.unlock();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
RsStackMutex stack(mNotifyMtx); /**** LOCK MUTEX ****/
|
||||
|
||||
RS_STACK_MUTEX(mNotifyMtx);
|
||||
mNotifyQueue.push_back(NotifyData(ni, newState, remote_peer_address));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void pqiperson::processNotifyEvents()
|
||||
void pqiperson::processNotifyEvents()
|
||||
{
|
||||
NetInterface *ni;
|
||||
int state;
|
||||
struct sockaddr_storage addr;
|
||||
sockaddr_storage addr;
|
||||
|
||||
while(1)
|
||||
while(1) // While there is notification to handle
|
||||
{
|
||||
{
|
||||
RsStackMutex stack(mNotifyMtx); /**** LOCK MUTEX ****/
|
||||
RS_STACK_MUTEX(mNotifyMtx);
|
||||
|
||||
if (mNotifyQueue.empty())
|
||||
{
|
||||
if(mNotifyQueue.empty())
|
||||
return;
|
||||
}
|
||||
|
||||
NotifyData &data = mNotifyQueue.front();
|
||||
ni = data.mNi;
|
||||
state = data.mState;
|
||||
@ -260,23 +250,21 @@ void pqiperson::processNotifyEvents()
|
||||
mNotifyQueue.pop_front();
|
||||
}
|
||||
|
||||
RsStackMutex stack(mPersonMtx); /**** LOCK MUTEX ****/
|
||||
RS_STACK_MUTEX(mPersonMtx);
|
||||
handleNotifyEvent_locked(ni, state, addr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int pqiperson::handleNotifyEvent_locked(NetInterface *ni, int newState, const struct sockaddr_storage &remote_peer_address)
|
||||
int pqiperson::handleNotifyEvent_locked(NetInterface *ni, int newState,
|
||||
const sockaddr_storage &remote_peer_address)
|
||||
{
|
||||
|
||||
{
|
||||
std::string out = "pqiperson::notifyEvent() Id: " + PeerId().toStdString() + "\n";
|
||||
rs_sprintf_append(out, "Message: %d from: %p\n", newState, ni);
|
||||
rs_sprintf_append(out, "Active pqi : %p", activepqi);
|
||||
|
||||
pqioutput(PQL_DEBUG_BASIC, pqipersonzone, out);
|
||||
}
|
||||
#ifdef PERSON_DEBUG
|
||||
std::cerr << "pqiperson::handleNotifyEvent_locked() Id: "
|
||||
<< PeerId().toStdString() << " Message: " << newState
|
||||
<< " from: " << ni << std::endl;
|
||||
int i = 0;
|
||||
#endif
|
||||
|
||||
/* find the pqi, */
|
||||
pqiconnect *pqi = NULL;
|
||||
@ -284,14 +272,14 @@ int pqiperson::handleNotifyEvent_locked(NetInterface *ni, int newState, const s
|
||||
std::map<uint32_t, pqiconnect *>::iterator it;
|
||||
|
||||
/* start again */
|
||||
int i = 0;
|
||||
for(it = kids.begin(); it != kids.end(); ++it)
|
||||
{
|
||||
std::string out;
|
||||
rs_sprintf(out, "pqiperson::connectattempt() Kid# %d of %u\n", i, kids.size());
|
||||
rs_sprintf_append(out, " type: %u in_ni: %p", it->first, ni);
|
||||
pqioutput(PQL_DEBUG_BASIC, pqipersonzone, out);
|
||||
i++;
|
||||
#ifdef PERSON_DEBUG
|
||||
std::cerr << "pqiperson::handleNotifyEvent_locked() Kid# " << i
|
||||
<< " of " << kids.size() << " type: " << it->first
|
||||
<< " in_ni: " << ni << std::endl;
|
||||
++i;
|
||||
#endif
|
||||
|
||||
if ((it->second)->thisNetInterface(ni))
|
||||
{
|
||||
@ -302,7 +290,8 @@ int pqiperson::handleNotifyEvent_locked(NetInterface *ni, int newState, const s
|
||||
|
||||
if (!pqi)
|
||||
{
|
||||
pqioutput(PQL_WARNING, pqipersonzone, "Unknown notfyEvent Source!");
|
||||
std::cerr << "pqiperson::handleNotifyEvent_locked Unknown Event Source!"
|
||||
<< std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -311,12 +300,13 @@ int pqiperson::handleNotifyEvent_locked(NetInterface *ni, int newState, const s
|
||||
{
|
||||
case CONNECT_RECEIVED:
|
||||
case CONNECT_SUCCESS:
|
||||
{
|
||||
|
||||
/* notify */
|
||||
if (pqipg)
|
||||
{
|
||||
pqissl *ssl = dynamic_cast<pqissl*>(ni);
|
||||
if(ssl != NULL)
|
||||
if(ssl)
|
||||
pqipg->notifyConnect(PeerId(), type, true, ssl->actAsServer(), remote_peer_address);
|
||||
else
|
||||
pqipg->notifyConnect(PeerId(), type, true, false, remote_peer_address);
|
||||
@ -324,96 +314,92 @@ int pqiperson::handleNotifyEvent_locked(NetInterface *ni, int newState, const s
|
||||
|
||||
if ((active) && (activepqi != pqi)) // already connected - trouble
|
||||
{
|
||||
pqioutput(PQL_WARNING, pqipersonzone, "pqiperson::notifyEvent() Id: " + PeerId().toStdString() + " CONNECT_SUCCESS+active-> activing new connection, shutting others");
|
||||
// TODO: 2015/12/19 Is this block dead code?
|
||||
|
||||
std::cerr << "pqiperson::handleNotifyEvent_locked Id: "
|
||||
<< PeerId().toStdString() << " CONNECT_SUCCESS+active->"
|
||||
<< "activing new connection, shutting others"
|
||||
<< std::endl;
|
||||
|
||||
// This is the RESET that's killing the connections.....
|
||||
//activepqi -> reset();
|
||||
//activepqi -> reset();
|
||||
// this causes a recursive call back into this fn.
|
||||
// which cleans up state.
|
||||
// we only do this if its not going to mess with new conn.
|
||||
}
|
||||
|
||||
/* now install a new one. */
|
||||
{
|
||||
|
||||
pqioutput(PQL_WARNING, pqipersonzone, "pqiperson::notifyEvent() Id: " + PeerId().toStdString() + " CONNECT_SUCCESS->marking so! (resetting others)");
|
||||
{
|
||||
#ifdef PERSON_DEBUG
|
||||
std::cerr << "pqiperson::handleNotifyEvent_locked Id: "
|
||||
<< PeerId().toStdString() << " CONNECT_SUCCESS->marking "
|
||||
<< "so! (resetting others)" << std::endl;
|
||||
#endif
|
||||
|
||||
// mark as active.
|
||||
active = true;
|
||||
lastHeartbeatReceived = 0;
|
||||
lastHeartbeatReceived = 0;
|
||||
activepqi = pqi;
|
||||
inConnectAttempt = false;
|
||||
inConnectAttempt = false;
|
||||
|
||||
activepqi->start(); // STARTUP THREAD.
|
||||
|
||||
/* reset all other children? (clear up long UDP attempt) */
|
||||
// reset all other children (clear up long UDP attempt)
|
||||
for(it = kids.begin(); it != kids.end(); ++it)
|
||||
{
|
||||
if (!(it->second)->thisNetInterface(ni))
|
||||
{
|
||||
std::string out;
|
||||
rs_sprintf(out, "Resetting pqi ref : %p", &(it->second));
|
||||
pqioutput(PQL_DEBUG_BASIC, pqipersonzone, out);
|
||||
it->second->reset();
|
||||
} else {
|
||||
//std::cerr << "Active pqi : not resetting." << std::endl;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CONNECT_UNREACHABLE:
|
||||
case CONNECT_FIREWALLED:
|
||||
case CONNECT_FAILED:
|
||||
|
||||
|
||||
if (active)
|
||||
{
|
||||
if (active && (activepqi == pqi))
|
||||
{
|
||||
if (activepqi == pqi)
|
||||
{
|
||||
pqioutput(PQL_WARNING, pqipersonzone, "pqiperson::notifyEvent() Id: " + PeerId().toStdString() + " CONNECT_FAILED->marking so!");
|
||||
#ifdef PERSON_DEBUG
|
||||
std::cerr << "pqiperson::handleNotifyEvent_locked Id: "
|
||||
<< PeerId().toStdString()
|
||||
<< " CONNECT_FAILED->marking so!" << std::endl;
|
||||
#endif
|
||||
|
||||
activepqi->shutdown(); // STOP THREAD.
|
||||
active = false;
|
||||
activepqi = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
pqioutput(PQL_WARNING, pqipersonzone, "pqiperson::notifyEvent() Id: " + PeerId().toStdString() + " CONNECT_FAILED-> from an unactive connection, don't flag the peer as not connected, just try next attempt !");
|
||||
}
|
||||
activepqi->shutdown(); // STOP THREAD.
|
||||
active = false;
|
||||
activepqi = NULL;
|
||||
}
|
||||
#ifdef PERSON_DEBUG
|
||||
else
|
||||
{
|
||||
pqioutput(PQL_WARNING, pqipersonzone, "pqiperson::notifyEvent() Id: " + PeerId().toStdString() + " CONNECT_FAILED+NOT active -> try connect again");
|
||||
}
|
||||
|
||||
std::cerr << "pqiperson::handleNotifyEvent_locked Id: "
|
||||
<< PeerId().toStdString() + " CONNECT_FAILED-> from "
|
||||
<< "an unactive connection, don't flag the peer as "
|
||||
<< "not connected, just try next attempt !" << std::endl;
|
||||
#endif
|
||||
/* notify up */
|
||||
if (pqipg)
|
||||
{
|
||||
pqipg->notifyConnect(PeerId(), type, false, false, remote_peer_address);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/***************** Not PQInterface Fns ***********************/
|
||||
|
||||
int pqiperson::reset()
|
||||
int pqiperson::reset()
|
||||
{
|
||||
RsStackMutex stack(mPersonMtx); /**** LOCK MUTEX ****/
|
||||
|
||||
RS_STACK_MUTEX(mPersonMtx);
|
||||
return reset_locked();
|
||||
}
|
||||
|
||||
int pqiperson::reset_locked()
|
||||
int pqiperson::reset_locked()
|
||||
{
|
||||
pqioutput(PQL_WARNING, pqipersonzone, "pqiperson::reset() resetting all pqiconnect for Id: " + PeerId().toStdString());
|
||||
#ifdef PERSON_DEBUG
|
||||
std::cerr << "pqiperson::reset_locked() resetting all pqiconnect for Id: "
|
||||
<< PeerId().toStdString() << std::endl;
|
||||
#endif
|
||||
|
||||
std::map<uint32_t, pqiconnect *>::iterator it;
|
||||
for(it = kids.begin(); it != kids.end(); ++it)
|
||||
@ -429,17 +415,18 @@ int pqiperson::reset_locked()
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pqiperson::fullstopthreads()
|
||||
int pqiperson::fullstopthreads()
|
||||
{
|
||||
RsStackMutex stack(mPersonMtx); /**** LOCK MUTEX ****/
|
||||
#ifdef PERSON_DEBUG
|
||||
std::cerr << "pqiperson::fullstopthreads() for Id: "
|
||||
<< PeerId().toStdString() << std::endl;
|
||||
#endif
|
||||
|
||||
pqioutput(PQL_WARNING, pqipersonzone, "pqiperson::fullstopthreads() for Id: " + PeerId().toStdString());
|
||||
RS_STACK_MUTEX(mPersonMtx);
|
||||
|
||||
std::map<uint32_t, pqiconnect *>::iterator it;
|
||||
for(it = kids.begin(); it != kids.end(); ++it)
|
||||
{
|
||||
(it->second) -> fullstop(); // WAIT FOR THREAD TO STOP.
|
||||
}
|
||||
(it->second)->fullstop(); // WAIT FOR THREAD TO STOP.
|
||||
|
||||
activepqi = NULL;
|
||||
active = false;
|
||||
@ -450,13 +437,12 @@ int pqiperson::fullstopthreads()
|
||||
|
||||
int pqiperson::addChildInterface(uint32_t type, pqiconnect *pqi)
|
||||
{
|
||||
RsStackMutex stack(mPersonMtx); /**** LOCK MUTEX ****/
|
||||
#ifdef PERSON_DEBUG
|
||||
std::cerr << "pqiperson::addChildInterface() : Id "
|
||||
<< PeerId().toStdString() << " " << type << std::endl;
|
||||
#endif
|
||||
|
||||
{
|
||||
std::string out;
|
||||
rs_sprintf(out, "pqiperson::addChildInterface() : Id %s %u", PeerId().toStdString().c_str(), type);
|
||||
pqioutput(PQL_DEBUG_BASIC, pqipersonzone, out);
|
||||
}
|
||||
RS_STACK_MUTEX(mPersonMtx);
|
||||
|
||||
kids[type] = pqi;
|
||||
return 1;
|
||||
@ -466,91 +452,78 @@ int pqiperson::addChildInterface(uint32_t type, pqiconnect *pqi)
|
||||
// functions to iterate over the connects and change state.
|
||||
|
||||
|
||||
int pqiperson::listen()
|
||||
int pqiperson::listen()
|
||||
{
|
||||
RsStackMutex stack(mPersonMtx); /**** LOCK MUTEX ****/
|
||||
#ifdef PERSON_DEBUG
|
||||
std::cerr << "pqiperson::listen() Id: " + PeerId().toStdString() << std::endl;
|
||||
#endif
|
||||
|
||||
pqioutput(PQL_DEBUG_BASIC, pqipersonzone, "pqiperson::listen() Id: " + PeerId().toStdString());
|
||||
RS_STACK_MUTEX(mPersonMtx);
|
||||
|
||||
if (!active)
|
||||
{
|
||||
std::map<uint32_t, pqiconnect *>::iterator it;
|
||||
for(it = kids.begin(); it != kids.end(); ++it)
|
||||
{
|
||||
// set them all listening.
|
||||
(it->second) -> listen();
|
||||
}
|
||||
(it->second)->listen();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int pqiperson::stoplistening()
|
||||
int pqiperson::stoplistening()
|
||||
{
|
||||
RsStackMutex stack(mPersonMtx); /**** LOCK MUTEX ****/
|
||||
#ifdef PERSON_DEBUG
|
||||
std::cerr << "pqiperson::stoplistening() Id: " + PeerId().toStdString()
|
||||
<< std::endl;
|
||||
#endif
|
||||
|
||||
pqioutput(PQL_DEBUG_BASIC, pqipersonzone, "pqiperson::stoplistening() Id: " + PeerId().toStdString());
|
||||
RS_STACK_MUTEX(mPersonMtx);
|
||||
|
||||
std::map<uint32_t, pqiconnect *>::iterator it;
|
||||
for(it = kids.begin(); it != kids.end(); ++it)
|
||||
{
|
||||
// set them all listening.
|
||||
(it->second) -> stoplistening();
|
||||
}
|
||||
(it->second)->stoplistening();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pqiperson::connect(uint32_t type, const struct sockaddr_storage &raddr,
|
||||
const struct sockaddr_storage &proxyaddr, const struct sockaddr_storage &srcaddr,
|
||||
uint32_t delay, uint32_t period, uint32_t timeout, uint32_t flags, uint32_t bandwidth,
|
||||
const std::string &domain_addr, uint16_t domain_port)
|
||||
int pqiperson::connect(uint32_t type, const sockaddr_storage &raddr,
|
||||
const sockaddr_storage &proxyaddr,
|
||||
const sockaddr_storage &srcaddr,
|
||||
uint32_t delay, uint32_t period, uint32_t timeout,
|
||||
uint32_t flags, uint32_t bandwidth,
|
||||
const std::string &domain_addr, uint16_t domain_port)
|
||||
{
|
||||
RsStackMutex stack(mPersonMtx); /**** LOCK MUTEX ****/
|
||||
|
||||
#ifdef PERSON_DEBUG
|
||||
std::cerr << "pqiperson::connect() Id: " << PeerId().toStdString()
|
||||
<< " type: " << type << " addr: "
|
||||
<< sockaddr_storage_tostring(raddr) << " proxyaddr: "
|
||||
<< sockaddr_storage_tostring(proxyaddr) << " srcaddr: "
|
||||
<< sockaddr_storage_tostring(srcaddr) << " delay: " << delay
|
||||
<< " period: " << period << " timeout: " << timeout << " flags: "
|
||||
<< flags << " bandwidth: " << bandwidth << std::endl;
|
||||
#endif
|
||||
{
|
||||
std::string out = "pqiperson::connect() Id: " + PeerId().toStdString();
|
||||
rs_sprintf_append(out, " type: %u", type);
|
||||
out += " addr: ";
|
||||
out += sockaddr_storage_tostring(raddr);
|
||||
out += " proxyaddr: ";
|
||||
out += sockaddr_storage_tostring(proxyaddr);
|
||||
out += " srcaddr: ";
|
||||
out += sockaddr_storage_tostring(srcaddr);
|
||||
rs_sprintf_append(out, " delay: %u", delay);
|
||||
rs_sprintf_append(out, " period: %u", period);
|
||||
rs_sprintf_append(out, " timeout: %u", timeout);
|
||||
rs_sprintf_append(out, " flags: %u", flags);
|
||||
rs_sprintf_append(out, " bandwidth: %u", bandwidth);
|
||||
//std::cerr << out.str();
|
||||
pqioutput(PQL_WARNING, pqipersonzone, out);
|
||||
}
|
||||
|
||||
RS_STACK_MUTEX(mPersonMtx);
|
||||
|
||||
std::map<uint32_t, pqiconnect *>::iterator it;
|
||||
|
||||
it = kids.find(type);
|
||||
if (it == kids.end())
|
||||
{
|
||||
#ifdef PERSON_DEBUG
|
||||
//pqioutput(PQL_DEBUG_BASIC, pqipersonzone, "pqiperson::connect() missing pqiconnect");
|
||||
#endif
|
||||
/* notify of fail! */
|
||||
|
||||
pqipg->notifyConnect(PeerId(), type, false, false, raddr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef PERSON_DEBUG
|
||||
std::cerr << "pqiperson::connect() WARNING, resetting for new connection attempt" << std::endl;
|
||||
std::cerr << "pqiperson::connect() resetting for new connection attempt" << std::endl;
|
||||
#endif
|
||||
|
||||
/* set the parameters */
|
||||
pqioutput(PQL_WARNING, pqipersonzone, "pqiperson::connect reset() before connection attempt");
|
||||
(it->second)->reset();
|
||||
|
||||
#ifdef PERSON_DEBUG
|
||||
std::cerr << "pqiperson::connect() WARNING, clearing rate cap" << std::endl;
|
||||
std::cerr << "pqiperson::connect() clearing rate cap" << std::endl;
|
||||
#endif
|
||||
setRateCap_locked(0,0);
|
||||
|
||||
@ -583,61 +556,66 @@ int pqiperson::connect(uint32_t type, const struct sockaddr_storage &raddr,
|
||||
}
|
||||
|
||||
|
||||
void pqiperson::getRates(RsBwRates &rates)
|
||||
void pqiperson::getRates(RsBwRates &rates)
|
||||
{
|
||||
RsStackMutex stack(mPersonMtx); /**** LOCK MUTEX ****/
|
||||
RS_STACK_MUTEX(mPersonMtx);
|
||||
|
||||
// get the rate from the active one.
|
||||
if ((!active) || (activepqi == NULL))
|
||||
return;
|
||||
activepqi -> getRates(rates);
|
||||
|
||||
activepqi->getRates(rates);
|
||||
}
|
||||
int pqiperson::gatherStatistics(std::list<RSTrafficClue>& out_lst,std::list<RSTrafficClue>& in_lst)
|
||||
|
||||
int pqiperson::gatherStatistics(std::list<RSTrafficClue>& out_lst,
|
||||
std::list<RSTrafficClue>& in_lst)
|
||||
{
|
||||
RsStackMutex stack(mPersonMtx); /**** LOCK MUTEX ****/
|
||||
RS_STACK_MUTEX(mPersonMtx);
|
||||
|
||||
// get the rate from the active one.
|
||||
if ((!active) || (activepqi == NULL))
|
||||
return 0;
|
||||
|
||||
return activepqi -> gatherStatistics(out_lst,in_lst);
|
||||
return activepqi->gatherStatistics(out_lst, in_lst);
|
||||
}
|
||||
int pqiperson::getQueueSize(bool in)
|
||||
|
||||
int pqiperson::getQueueSize(bool in)
|
||||
{
|
||||
RsStackMutex stack(mPersonMtx); /**** LOCK MUTEX ****/
|
||||
RS_STACK_MUTEX(mPersonMtx);
|
||||
|
||||
// get the rate from the active one.
|
||||
if ((!active) || (activepqi == NULL))
|
||||
return 0;
|
||||
return activepqi -> getQueueSize(in);
|
||||
|
||||
return activepqi->getQueueSize(in);
|
||||
}
|
||||
|
||||
bool pqiperson::getCryptoParams(RsPeerCryptoParams& params)
|
||||
bool pqiperson::getCryptoParams(RsPeerCryptoParams & params)
|
||||
{
|
||||
RsStackMutex stack(mPersonMtx); /**** LOCK MUTEX ****/
|
||||
RS_STACK_MUTEX(mPersonMtx);
|
||||
|
||||
if(active && activepqi != NULL)
|
||||
return activepqi->getCryptoParams(params) ;
|
||||
return activepqi->getCryptoParams(params);
|
||||
else
|
||||
{
|
||||
params.connexion_state = 0 ;
|
||||
params.cipher_name.clear() ;
|
||||
params.cipher_bits_1 = 0 ;
|
||||
params.cipher_bits_2 = 0 ;
|
||||
params.cipher_version.clear() ;
|
||||
params.connexion_state = 0;
|
||||
params.cipher_name.clear();
|
||||
params.cipher_bits_1 = 0;
|
||||
params.cipher_bits_2 = 0;
|
||||
params.cipher_version.clear();
|
||||
|
||||
return false ;
|
||||
}
|
||||
}
|
||||
|
||||
bool pqiconnect::getCryptoParams(RsPeerCryptoParams& params)
|
||||
bool pqiconnect::getCryptoParams(RsPeerCryptoParams & params)
|
||||
{
|
||||
pqissl *ssl = dynamic_cast<pqissl*>(ni) ;
|
||||
pqissl *ssl = dynamic_cast<pqissl*>(ni);
|
||||
|
||||
if(ssl != NULL)
|
||||
{
|
||||
ssl->getCryptoParams(params) ;
|
||||
return true ;
|
||||
ssl->getCryptoParams(params);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -650,31 +628,30 @@ bool pqiconnect::getCryptoParams(RsPeerCryptoParams& params)
|
||||
}
|
||||
}
|
||||
|
||||
float pqiperson::getRate(bool in)
|
||||
float pqiperson::getRate(bool in)
|
||||
{
|
||||
RsStackMutex stack(mPersonMtx); /**** LOCK MUTEX ****/
|
||||
RS_STACK_MUTEX(mPersonMtx);
|
||||
|
||||
// get the rate from the active one.
|
||||
if ((!active) || (activepqi == NULL))
|
||||
return 0;
|
||||
|
||||
return activepqi -> getRate(in);
|
||||
}
|
||||
|
||||
void pqiperson::setMaxRate(bool in, float val)
|
||||
void pqiperson::setMaxRate(bool in, float val)
|
||||
{
|
||||
RsStackMutex stack(mPersonMtx); /**** LOCK MUTEX ****/
|
||||
RS_STACK_MUTEX(mPersonMtx);
|
||||
|
||||
// set to all of them. (and us)
|
||||
PQInterface::setMaxRate(in, val);
|
||||
// clean up the children.
|
||||
std::map<uint32_t, pqiconnect *>::iterator it;
|
||||
for(it = kids.begin(); it != kids.end(); ++it)
|
||||
{
|
||||
(it->second) -> setMaxRate(in, val);
|
||||
}
|
||||
}
|
||||
|
||||
void pqiperson::setRateCap(float val_in, float val_out)
|
||||
void pqiperson::setRateCap(float val_in, float val_out)
|
||||
{
|
||||
// This methods might be called all the way down from pqiperson::tick() down
|
||||
// to pqissludp while completing a UDP connexion, causing a deadlock.
|
||||
@ -686,28 +663,30 @@ void pqiperson::setRateCap(float val_in, float val_out)
|
||||
// The lock cannot be locked by the same thread between the first test and
|
||||
// the "else" statement, so there is no possibility for this code to fail.
|
||||
//
|
||||
// We could actually put that code in RsMutex::lock()
|
||||
// We could actually put that code in RsMutex::lock()?
|
||||
// TODO: 2015/12/19 This code is already in RsMutex::lock() but is guarded
|
||||
// by RSTHREAD_SELF_LOCKING_GUARD which is specifically unset in the header
|
||||
// Why is that code guarded? Do it have an impact on performance?
|
||||
// Or we should not get in the situation of trying to relock the mutex on
|
||||
// the same thread NEVER?
|
||||
|
||||
if(pthread_equal(mPersonMtx.owner(),pthread_self())) // 1 - unlocked, or already locked by same thread
|
||||
return setRateCap_locked(val_in, val_out); // -> do nothing
|
||||
if(pthread_equal(mPersonMtx.owner(), pthread_self()))
|
||||
// Unlocked, or already locked by same thread
|
||||
setRateCap_locked(val_in, val_out);
|
||||
else
|
||||
{ // 2 - lock was free or locked by different thread => wait.
|
||||
RsStackMutex stack(mPersonMtx); /**** LOCK MUTEX ****/
|
||||
{
|
||||
// Lock was free or locked by different thread => wait.
|
||||
RS_STACK_MUTEX(mPersonMtx);
|
||||
setRateCap_locked(val_in, val_out);
|
||||
}
|
||||
}
|
||||
|
||||
void pqiperson::setRateCap_locked(float val_in, float val_out)
|
||||
void pqiperson::setRateCap_locked(float val_in, float val_out)
|
||||
{
|
||||
// set to all of them. (and us)
|
||||
PQInterface::setRateCap(val_in, val_out);
|
||||
// clean up the children.
|
||||
std::map<uint32_t, pqiconnect *>::iterator it;
|
||||
for(it = kids.begin(); it != kids.end(); ++it)
|
||||
{
|
||||
(it->second) -> setRateCap(val_in, val_out);
|
||||
}
|
||||
(it->second)->setRateCap(val_in, val_out);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -83,22 +83,20 @@ protected:
|
||||
|
||||
class pqipersongrp;
|
||||
|
||||
|
||||
class NotifyData
|
||||
{
|
||||
public:
|
||||
NotifyData()
|
||||
:mNi(NULL), mState(0)
|
||||
public:
|
||||
NotifyData() : mNi(NULL), mState(0)
|
||||
{
|
||||
sockaddr_storage_clear(mAddr);
|
||||
}
|
||||
|
||||
NotifyData(NetInterface *ni, int state, const struct sockaddr_storage &addr)
|
||||
:mNi(ni), mState(state), mAddr(addr) { return; }
|
||||
NotifyData(NetInterface *ni, int state, const sockaddr_storage &addr) :
|
||||
mNi(ni), mState(state), mAddr(addr) {}
|
||||
|
||||
NetInterface *mNi;
|
||||
int mState;
|
||||
struct sockaddr_storage mAddr;
|
||||
sockaddr_storage mAddr;
|
||||
};
|
||||
|
||||
|
||||
@ -106,82 +104,76 @@ class pqiperson: public PQInterface
|
||||
{
|
||||
public:
|
||||
pqiperson(const RsPeerId& id, pqipersongrp *ppg);
|
||||
virtual ~pqiperson(); // must clean up children.
|
||||
virtual ~pqiperson(); // must clean up children.
|
||||
|
||||
// control of the connection.
|
||||
int reset();
|
||||
int listen();
|
||||
int stoplistening();
|
||||
int reset();
|
||||
int listen();
|
||||
int stoplistening();
|
||||
|
||||
int connect(uint32_t type, const struct sockaddr_storage &raddr,
|
||||
const struct sockaddr_storage &proxyaddr, const struct sockaddr_storage &srcaddr,
|
||||
uint32_t delay, uint32_t period, uint32_t timeout, uint32_t flags, uint32_t bandwidth,
|
||||
const std::string &domain_addr, uint16_t domain_port);
|
||||
int connect(uint32_t type, const sockaddr_storage &raddr,
|
||||
const sockaddr_storage &proxyaddr, const sockaddr_storage &srcaddr,
|
||||
uint32_t delay, uint32_t period, uint32_t timeout, uint32_t flags,
|
||||
uint32_t bandwidth, const std::string &domain_addr, uint16_t domain_port);
|
||||
|
||||
int fullstopthreads();
|
||||
int fullstopthreads();
|
||||
int receiveHeartbeat();
|
||||
|
||||
int receiveHeartbeat();
|
||||
// add in connection method.
|
||||
int addChildInterface(uint32_t type, pqiconnect *pqi);
|
||||
int addChildInterface(uint32_t type, pqiconnect *pqi);
|
||||
|
||||
virtual bool getCryptoParams(RsPeerCryptoParams&) ;
|
||||
virtual bool getCryptoParams(RsPeerCryptoParams&);
|
||||
|
||||
// The PQInterface interface.
|
||||
virtual int SendItem(RsItem *,uint32_t& serialized_size);
|
||||
virtual int SendItem(RsItem *item)
|
||||
{
|
||||
std::cerr << "Warning pqiperson::sendItem(RsItem*) should not be called. Plz call SendItem(RsItem *,uint32_t& serialized_size) instead." << std::endl;
|
||||
uint32_t serialized_size ;
|
||||
return SendItem(item,serialized_size) ;
|
||||
}
|
||||
virtual RsItem *GetItem();
|
||||
virtual bool RecvItem(RsItem *item);
|
||||
virtual int SendItem(RsItem *,uint32_t& serialized_size);
|
||||
virtual int SendItem(RsItem *item)
|
||||
{
|
||||
std::cerr << "Warning pqiperson::sendItem(RsItem*) should not be called."
|
||||
<< "Plz call SendItem(RsItem *,uint32_t& serialized_size) instead."
|
||||
<< std::endl;
|
||||
uint32_t serialized_size;
|
||||
return SendItem(item, serialized_size);
|
||||
}
|
||||
|
||||
virtual int status();
|
||||
virtual int tick();
|
||||
virtual RsItem *GetItem();
|
||||
virtual bool RecvItem(RsItem *item);
|
||||
|
||||
// overloaded callback function for the child - notify of a change.
|
||||
virtual int notifyEvent(NetInterface *ni, int event, const struct sockaddr_storage &addr);
|
||||
virtual int status();
|
||||
virtual int tick();
|
||||
|
||||
// PQInterface for rate control overloaded....
|
||||
virtual int getQueueSize(bool in);
|
||||
virtual void getRates(RsBwRates &rates);
|
||||
virtual float getRate(bool in);
|
||||
virtual void setMaxRate(bool in, float val);
|
||||
virtual void setRateCap(float val_in, float val_out);
|
||||
virtual int gatherStatistics(std::list<RSTrafficClue>& outqueue_lst,std::list<RSTrafficClue>& inqueue_lst) ;
|
||||
// overloaded callback function for the child - notify of a change.
|
||||
virtual int notifyEvent(NetInterface *ni, int event, const struct sockaddr_storage &addr);
|
||||
|
||||
// PQInterface for rate control overloaded....
|
||||
virtual int getQueueSize(bool in);
|
||||
virtual void getRates(RsBwRates &rates);
|
||||
virtual float getRate(bool in);
|
||||
virtual void setMaxRate(bool in, float val);
|
||||
virtual void setRateCap(float val_in, float val_out);
|
||||
virtual int gatherStatistics(std::list<RSTrafficClue>& outqueue_lst,
|
||||
std::list<RSTrafficClue>& inqueue_lst);
|
||||
|
||||
private:
|
||||
void processNotifyEvents();
|
||||
int handleNotifyEvent_locked(NetInterface *ni, int event,
|
||||
const sockaddr_storage &addr);
|
||||
|
||||
private:
|
||||
|
||||
void processNotifyEvents();
|
||||
int handleNotifyEvent_locked(NetInterface *ni, int event, const struct sockaddr_storage &addr);
|
||||
|
||||
RsMutex mNotifyMtx; /**** LOCKS Notify Queue ****/
|
||||
|
||||
RsMutex mNotifyMtx; // LOCKS Notify Queue
|
||||
std::list<NotifyData> mNotifyQueue;
|
||||
|
||||
RsMutex mPersonMtx; /**** LOCKS below ****/
|
||||
RsMutex mPersonMtx; // LOCKS below
|
||||
|
||||
int reset_locked();
|
||||
int reset_locked();
|
||||
|
||||
void setRateCap_locked(float val_in, float val_out);
|
||||
void setRateCap_locked(float val_in, float val_out);
|
||||
|
||||
std::map<uint32_t, pqiconnect *> kids;
|
||||
bool active;
|
||||
pqiconnect *activepqi;
|
||||
bool inConnectAttempt;
|
||||
int waittimes;
|
||||
time_t lastHeartbeatReceived;//use to track connection failure
|
||||
|
||||
private: /* Helper functions */
|
||||
|
||||
|
||||
time_t lastHeartbeatReceived; // use to track connection failure
|
||||
pqipersongrp *pqipg; /* parent for callback */
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -54,7 +54,7 @@ const int PQISTREAM_ABS_MAX = 100000000; /* 100 MB/sec (actually per loop) */
|
||||
pqistreamer::pqistreamer(RsSerialiser *rss, const RsPeerId& id, BinInterface *bio_in, int bio_flags_in)
|
||||
:PQInterface(id), mStreamerMtx("pqistreamer"),
|
||||
mBio(bio_in), mBio_flags(bio_flags_in), mRsSerialiser(rss),
|
||||
mPkt_wpending(NULL),
|
||||
mPkt_wpending(NULL), mPkt_wpending_size(0),
|
||||
mTotalRead(0), mTotalSent(0),
|
||||
mCurrRead(0), mCurrSent(0),
|
||||
mAvgReadCount(0), mAvgSentCount(0)
|
||||
@ -117,6 +117,7 @@ pqistreamer::~pqistreamer()
|
||||
{
|
||||
free(mPkt_wpending);
|
||||
mPkt_wpending = NULL;
|
||||
mPkt_wpending_size = 0 ;
|
||||
}
|
||||
|
||||
free_rpend_locked();
|
||||
@ -416,104 +417,140 @@ time_t pqistreamer::getLastIncomingTS()
|
||||
int pqistreamer::handleoutgoing_locked()
|
||||
{
|
||||
#ifdef DEBUG_PQISTREAMER
|
||||
pqioutput(PQL_DEBUG_ALL, pqistreamerzone, "pqistreamer::handleoutgoing_locked()");
|
||||
pqioutput(PQL_DEBUG_ALL, pqistreamerzone, "pqistreamer::handleoutgoing_locked()");
|
||||
#endif
|
||||
|
||||
int maxbytes = outAllowedBytes_locked();
|
||||
int sentbytes = 0;
|
||||
int len;
|
||||
int ss;
|
||||
// std::cerr << "pqistreamer: maxbytes=" << maxbytes<< std::endl ;
|
||||
int maxbytes = outAllowedBytes_locked();
|
||||
int sentbytes = 0;
|
||||
|
||||
std::list<void *>::iterator it;
|
||||
// std::cerr << "pqistreamer: maxbytes=" << maxbytes<< std::endl ;
|
||||
|
||||
// if not connection, or cannot send anything... pause.
|
||||
if (!(mBio->isactive()))
|
||||
{
|
||||
/* if we are not active - clear anything in the queues. */
|
||||
locked_clear_out_queue() ;
|
||||
std::list<void *>::iterator it;
|
||||
|
||||
/* also remove the pending packets */
|
||||
if (mPkt_wpending)
|
||||
{
|
||||
free(mPkt_wpending);
|
||||
mPkt_wpending = NULL;
|
||||
}
|
||||
// if not connection, or cannot send anything... pause.
|
||||
if (!(mBio->isactive()))
|
||||
{
|
||||
/* if we are not active - clear anything in the queues. */
|
||||
locked_clear_out_queue() ;
|
||||
|
||||
outSentBytes_locked(sentbytes);
|
||||
return 0;
|
||||
}
|
||||
/* also remove the pending packets */
|
||||
if (mPkt_wpending)
|
||||
{
|
||||
free(mPkt_wpending);
|
||||
mPkt_wpending = NULL;
|
||||
mPkt_wpending_size = 0 ;
|
||||
}
|
||||
|
||||
// a very simple round robin
|
||||
outSentBytes_locked(sentbytes);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool sent = true;
|
||||
while(sent) // catch if all items sent.
|
||||
{
|
||||
sent = false;
|
||||
// a very simple round robin
|
||||
|
||||
if ((!(mBio->cansend(0))) || (maxbytes < sentbytes))
|
||||
{
|
||||
bool sent = true;
|
||||
int nsent = 0 ;
|
||||
while(sent) // catch if all items sent.
|
||||
{
|
||||
sent = false;
|
||||
|
||||
if ((!(mBio->cansend(0))) || (maxbytes < sentbytes))
|
||||
{
|
||||
|
||||
#ifdef DEBUG_TRANSFERS
|
||||
if (maxbytes < sentbytes)
|
||||
{
|
||||
std::cerr << "pqistreamer::handleoutgoing_locked() Stopped sending sentbytes > maxbytes. Sent " << sentbytes << " bytes ";
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "pqistreamer::handleoutgoing_locked() Stopped sending at cansend() is false";
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
if (maxbytes < sentbytes)
|
||||
{
|
||||
std::cerr << "pqistreamer::handleoutgoing_locked() Stopped sending sentbytes > maxbytes. Sent " << sentbytes << " bytes ";
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "pqistreamer::handleoutgoing_locked() Stopped sending at cansend() is false";
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
outSentBytes_locked(sentbytes);
|
||||
return 0;
|
||||
}
|
||||
outSentBytes_locked(sentbytes);
|
||||
return 0;
|
||||
}
|
||||
#define GROUP_OUTGOING_PACKETS 1
|
||||
// send a out_pkt., else send out_data. unless
|
||||
// there is a pending packet.
|
||||
if (!mPkt_wpending)
|
||||
#ifdef GROUP_OUTGOING_PACKETS
|
||||
{
|
||||
void *dta;
|
||||
mPkt_wpending_size = 0 ;
|
||||
int k=0;
|
||||
|
||||
// send a out_pkt., else send out_data. unless
|
||||
// there is a pending packet.
|
||||
if (!mPkt_wpending)
|
||||
mPkt_wpending = locked_pop_out_data() ;
|
||||
while(mPkt_wpending_size < maxbytes && (dta = locked_pop_out_data())!=NULL )
|
||||
{
|
||||
uint32_t s = getRsItemSize(dta);
|
||||
mPkt_wpending = realloc(mPkt_wpending,s+mPkt_wpending_size) ;
|
||||
memcpy( &((char*)mPkt_wpending)[mPkt_wpending_size],dta,s) ;
|
||||
free(dta);
|
||||
mPkt_wpending_size += s ;
|
||||
++k ;
|
||||
}
|
||||
#ifdef DEBUG_PQISTREAMER
|
||||
if(k > 1)
|
||||
std::cerr << "Packed " << k << " packets into " << mPkt_wpending_size << " bytes." << std::endl;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
{
|
||||
void *dta = locked_pop_out_data() ;
|
||||
|
||||
if (mPkt_wpending)
|
||||
if(dta != NULL)
|
||||
{
|
||||
// write packet.
|
||||
len = getRsItemSize(mPkt_wpending);
|
||||
|
||||
#ifdef DEBUG_PQISTREAMER
|
||||
std::cout << "Sending Out Pkt of size " << len << " !" << std::endl;
|
||||
#endif
|
||||
|
||||
if (len != (ss = mBio->senddata(mPkt_wpending, len)))
|
||||
{
|
||||
#ifdef DEBUG_PQISTREAMER
|
||||
std::string out;
|
||||
rs_sprintf(out, "Problems with Send Data! (only %d bytes sent, total pkt size=%d)", ss, len);
|
||||
// std::cerr << out << std::endl ;
|
||||
pqioutput(PQL_DEBUG_BASIC, pqistreamerzone, out);
|
||||
#endif
|
||||
|
||||
outSentBytes_locked(sentbytes);
|
||||
// pkt_wpending will kept til next time.
|
||||
// ensuring exactly the same data is written (openSSL requirement).
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TRANSFERS
|
||||
std::cerr << "pqistreamer::handleoutgoing_locked() Sent Packet len: " << len << " @ " << RsUtil::AccurateTimeString();
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
free(mPkt_wpending);
|
||||
mPkt_wpending = NULL;
|
||||
|
||||
sentbytes += len;
|
||||
sent = true;
|
||||
mPkt_wpending = dta ;
|
||||
mPkt_wpending_size = getRsItemSize(dta);
|
||||
}
|
||||
}
|
||||
outSentBytes_locked(sentbytes);
|
||||
return 1;
|
||||
#endif
|
||||
if (mPkt_wpending)
|
||||
{
|
||||
// write packet.
|
||||
#ifdef DEBUG_PQISTREAMER
|
||||
std::cout << "Sending Out Pkt of size " << mPkt_wpending_size << " !" << std::endl;
|
||||
#endif
|
||||
int ss=0;
|
||||
|
||||
if (mPkt_wpending_size != (ss = mBio->senddata(mPkt_wpending, mPkt_wpending_size)))
|
||||
{
|
||||
#ifdef DEBUG_PQISTREAMER
|
||||
std::string out;
|
||||
rs_sprintf(out, "Problems with Send Data! (only %d bytes sent, total pkt size=%d)", ss, mPkt_wpending_size);
|
||||
// std::cerr << out << std::endl ;
|
||||
pqioutput(PQL_DEBUG_BASIC, pqistreamerzone, out);
|
||||
#endif
|
||||
|
||||
outSentBytes_locked(sentbytes);
|
||||
// pkt_wpending will kept til next time.
|
||||
// ensuring exactly the same data is written (openSSL requirement).
|
||||
return -1;
|
||||
}
|
||||
++nsent;
|
||||
|
||||
#ifdef DEBUG_TRANSFERS
|
||||
std::cerr << "pqistreamer::handleoutgoing_locked() Sent Packet len: " << mPkt_wpending_size << " @ " << RsUtil::AccurateTimeString();
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
sentbytes += mPkt_wpending_size;
|
||||
|
||||
free(mPkt_wpending);
|
||||
mPkt_wpending = NULL;
|
||||
mPkt_wpending_size = 0 ;
|
||||
|
||||
sent = true;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_PQISTREAMER
|
||||
if(nsent > 0)
|
||||
std::cerr << "nsent = " << nsent << ", total bytes=" << sentbytes << std::endl;
|
||||
#endif
|
||||
outSentBytes_locked(sentbytes);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -113,6 +113,7 @@ class pqistreamer: public PQInterface
|
||||
RsSerialiser *mRsSerialiser;
|
||||
|
||||
void *mPkt_wpending; // storage for pending packet to write.
|
||||
uint32_t mPkt_wpending_size; // ... and its size.
|
||||
|
||||
void allocate_rpend_locked(); // use these two functions to allocate/free the buffer below
|
||||
void free_rpend_locked();
|
||||
|
132
libretroshare/src/retroshare/rsgxstunnel.h
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* libretroshare/src/services: rsgrouter.h
|
||||
*
|
||||
* Services for RetroShare.
|
||||
*
|
||||
* Copyright 2013 by Cyril Soler
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License Version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
* USA.
|
||||
*
|
||||
* Please report all bugs and problems to "csoler@users.sourceforge.net".
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/rsdir.h"
|
||||
#include "retroshare/rsids.h"
|
||||
#include "retroshare/rsturtle.h"
|
||||
#include "retroshare/rsgxsifacetypes.h"
|
||||
|
||||
class RsGxsTunnelService
|
||||
{
|
||||
public:
|
||||
typedef GXSTunnelId RsGxsTunnelId ;
|
||||
|
||||
enum {
|
||||
RS_GXS_TUNNEL_ERROR_NO_ERROR = 0x0000,
|
||||
RS_GXS_TUNNEL_ERROR_UNKNOWN_GXS_ID = 0x0001
|
||||
};
|
||||
|
||||
enum {
|
||||
RS_GXS_TUNNEL_STATUS_UNKNOWN = 0x00,
|
||||
RS_GXS_TUNNEL_STATUS_TUNNEL_DN = 0x01,
|
||||
RS_GXS_TUNNEL_STATUS_CAN_TALK = 0x02,
|
||||
RS_GXS_TUNNEL_STATUS_REMOTELY_CLOSED = 0x03
|
||||
};
|
||||
|
||||
class RsGxsTunnelClientService
|
||||
{
|
||||
public:
|
||||
// The client should derive this in order to handle notifications from the tunnel service.
|
||||
// This cannot be ignored because the client needs to know when the tunnel is active.
|
||||
|
||||
virtual void notifyTunnelStatus(const RsGxsTunnelId& tunnel_id,uint32_t tunnel_status) =0;
|
||||
|
||||
// Data obtained from the corresponding GXS id. The memory ownership is transferred to the client, which
|
||||
// is responsible to free it using free() once used.
|
||||
|
||||
virtual void receiveData(const RsGxsTunnelId& id,unsigned char *data,uint32_t data_size) =0;
|
||||
|
||||
// Used by the creator of the service to supply a pointer to the GXS tunnel service for it to be able to send data etc.
|
||||
|
||||
virtual void connectToGxsTunnelService(RsGxsTunnelService *tunnel_service) =0;
|
||||
};
|
||||
|
||||
class GxsTunnelInfo
|
||||
{
|
||||
public:
|
||||
// Tunnel information
|
||||
|
||||
RsGxsTunnelId tunnel_id ;
|
||||
RsGxsId destination_gxs_id ; // GXS Id we're talking to
|
||||
RsGxsId source_gxs_id ; // GXS Id we're using to talk
|
||||
uint32_t tunnel_status ; // active, requested, DH pending, etc.
|
||||
uint32_t total_size_sent ; // total bytes sent through that tunnel since openned (including management).
|
||||
uint32_t total_size_received ; // total bytes received through that tunnel since openned (including management).
|
||||
|
||||
// Data packets
|
||||
|
||||
uint32_t pending_data_packets; // number of packets not acknowledged by other side, still on their way. Should be 0 unless something bad happens.
|
||||
uint32_t total_data_packets_sent ; // total number of data packets sent (does not include tunnel management)
|
||||
uint32_t total_data_packets_received ; // total number of data packets received (does not include tunnel management)
|
||||
};
|
||||
|
||||
// This is the interface file for the secured tunnel service
|
||||
//
|
||||
//===================================================//
|
||||
// Debugging info //
|
||||
//===================================================//
|
||||
|
||||
virtual bool getTunnelsInfo(std::vector<GxsTunnelInfo>& infos) =0;
|
||||
virtual bool getTunnelInfo(const RsGxsTunnelId& tunnel_id,GxsTunnelInfo& info) =0;
|
||||
|
||||
// retrieve the routing probabilities
|
||||
|
||||
//===================================================//
|
||||
// Communication to other services. //
|
||||
//===================================================//
|
||||
|
||||
// Register a new client service. The service ID needs to be unique, and it's the coder's resonsibility to use an ID that is not used elsewhere
|
||||
// for the same purpose.
|
||||
|
||||
virtual bool registerClientService(uint32_t service_id,RsGxsTunnelClientService *service) =0;
|
||||
|
||||
// Asks for a tunnel. The service will request it to turtle router, and exchange a AES key using DH.
|
||||
// When the tunnel is secured, the client---here supplied as argument---will be notified. He can
|
||||
// then send data into the tunnel. The same tunnel may be used by different clients.
|
||||
// The service id is passed on so that the client is notified when the tunnel is up.
|
||||
|
||||
virtual bool requestSecuredTunnel(const RsGxsId& to_id,const RsGxsId& from_id,RsGxsTunnelId& tunnel_id,uint32_t service_id,uint32_t& error_code) =0 ;
|
||||
|
||||
// Data is sent through the established tunnel, possibly multiple times, until reception is acknowledged. If the tunnel does not exist, the item is rejected and
|
||||
// an error is issued. In any case, the memory ownership of the data is *not* transferred to the tunnel service, so the client should delete it afterwards, if needed.
|
||||
|
||||
virtual bool sendData(const RsGxsTunnelId& tunnel_id, uint32_t client_service_id, const uint8_t *data, uint32_t data_size) =0;
|
||||
|
||||
// Removes any established tunnel to this GXS id. This makes the tunnel refuse further data, but the tunnel will be however kept alive
|
||||
// until all pending data is flushed. All clients attached to the tunnel will be notified that the tunnel gets closed.
|
||||
|
||||
virtual bool closeExistingTunnel(const RsGxsTunnelId& to_id,uint32_t service_id) =0;
|
||||
|
||||
//===================================================//
|
||||
// Routage feedback from other services //
|
||||
//===================================================//
|
||||
|
||||
};
|
||||
|
||||
// To access the GRouter from anywhere
|
||||
//
|
||||
extern RsGxsTunnelService *rsGxsTunnel ;
|
@ -209,15 +209,17 @@ static const int SHA1_SIZE = 20 ;
|
||||
|
||||
// These constants are random, but should be different, in order to make the various IDs incompatible with each other.
|
||||
//
|
||||
static const uint32_t RS_GENERIC_ID_SSL_ID_TYPE = 0x0001 ;
|
||||
static const uint32_t RS_GENERIC_ID_PGP_ID_TYPE = 0x0002 ;
|
||||
static const uint32_t RS_GENERIC_ID_SHA1_ID_TYPE = 0x0003 ;
|
||||
static const uint32_t RS_GENERIC_ID_PGP_FINGERPRINT_TYPE = 0x0004 ;
|
||||
static const uint32_t RS_GENERIC_ID_GXS_GROUP_ID_TYPE = 0x0005 ;
|
||||
static const uint32_t RS_GENERIC_ID_GXS_ID_TYPE = 0x0006 ;
|
||||
static const uint32_t RS_GENERIC_ID_GXS_MSG_ID_TYPE = 0x0007 ;
|
||||
static const uint32_t RS_GENERIC_ID_GXS_CIRCLE_ID_TYPE = 0x0008 ;
|
||||
static const uint32_t RS_GENERIC_ID_GROUTER_ID_TYPE = 0x0009 ;
|
||||
static const uint32_t RS_GENERIC_ID_SSL_ID_TYPE = 0x0001 ;
|
||||
static const uint32_t RS_GENERIC_ID_PGP_ID_TYPE = 0x0002 ;
|
||||
static const uint32_t RS_GENERIC_ID_SHA1_ID_TYPE = 0x0003 ;
|
||||
static const uint32_t RS_GENERIC_ID_PGP_FINGERPRINT_TYPE = 0x0004 ;
|
||||
static const uint32_t RS_GENERIC_ID_GXS_GROUP_ID_TYPE = 0x0005 ;
|
||||
static const uint32_t RS_GENERIC_ID_GXS_ID_TYPE = 0x0006 ;
|
||||
static const uint32_t RS_GENERIC_ID_GXS_MSG_ID_TYPE = 0x0007 ;
|
||||
static const uint32_t RS_GENERIC_ID_GXS_CIRCLE_ID_TYPE = 0x0008 ;
|
||||
static const uint32_t RS_GENERIC_ID_GROUTER_ID_TYPE = 0x0009 ;
|
||||
static const uint32_t RS_GENERIC_ID_GXS_TUNNEL_ID_TYPE = 0x0010 ;
|
||||
static const uint32_t RS_GENERIC_ID_GXS_DISTANT_CHAT_ID_TYPE = 0x0011 ;
|
||||
|
||||
typedef t_RsGenericIdType< SSL_ID_SIZE , false, RS_GENERIC_ID_SSL_ID_TYPE> SSLIdType ;
|
||||
typedef t_RsGenericIdType< PGP_KEY_ID_SIZE , true, RS_GENERIC_ID_PGP_ID_TYPE> PGPIdType ;
|
||||
@ -227,4 +229,6 @@ typedef t_RsGenericIdType< PGP_KEY_FINGERPRINT_SIZE, true, RS_GENERIC_ID_PGP_F
|
||||
typedef t_RsGenericIdType< CERT_SIGN_LEN , false, RS_GENERIC_ID_GXS_GROUP_ID_TYPE > GXSGroupId ;
|
||||
typedef t_RsGenericIdType< CERT_SIGN_LEN , false, RS_GENERIC_ID_GXS_ID_TYPE > GXSId ;
|
||||
typedef t_RsGenericIdType< CERT_SIGN_LEN , false, RS_GENERIC_ID_GXS_CIRCLE_ID_TYPE > GXSCircleId ;
|
||||
typedef t_RsGenericIdType< SSL_ID_SIZE , false, RS_GENERIC_ID_GXS_TUNNEL_ID_TYPE > GXSTunnelId ;
|
||||
typedef t_RsGenericIdType< SSL_ID_SIZE , false, RS_GENERIC_ID_GXS_DISTANT_CHAT_ID_TYPE > DistantChatPeerId ;
|
||||
|
||||
|
@ -99,9 +99,6 @@ typedef uint64_t ChatLobbyId ;
|
||||
typedef uint64_t ChatLobbyMsgId ;
|
||||
typedef std::string ChatLobbyNickName ;
|
||||
|
||||
typedef RsPeerId DistantChatPeerId ;
|
||||
//typedef GRouterKeyId DistantMsgPeerId ;
|
||||
|
||||
typedef uint64_t MessageId ;
|
||||
|
||||
|
||||
@ -253,12 +250,10 @@ public:
|
||||
#define RS_CHAT_PRIVATE 0x0002
|
||||
#define RS_CHAT_AVATAR_AVAILABLE 0x0004
|
||||
|
||||
#define RS_DISTANT_CHAT_STATUS_UNKNOWN 0x0000
|
||||
#define RS_DISTANT_CHAT_STATUS_TUNNEL_DN 0x0001
|
||||
#define RS_DISTANT_CHAT_STATUS_TUNNEL_OK 0x0002
|
||||
#define RS_DISTANT_CHAT_STATUS_CAN_TALK 0x0003
|
||||
#define RS_DISTANT_CHAT_STATUS_REMOTELY_CLOSED 0x0004
|
||||
#define RS_DISTANT_CHAT_STATUS_WAITING_DH 0x0005
|
||||
#define RS_DISTANT_CHAT_STATUS_UNKNOWN 0x0000
|
||||
#define RS_DISTANT_CHAT_STATUS_TUNNEL_DN 0x0001
|
||||
#define RS_DISTANT_CHAT_STATUS_CAN_TALK 0x0002
|
||||
#define RS_DISTANT_CHAT_STATUS_REMOTELY_CLOSED 0x0003
|
||||
|
||||
#define RS_DISTANT_CHAT_ERROR_NO_ERROR 0x0000
|
||||
#define RS_DISTANT_CHAT_ERROR_DECRYPTION_FAILED 0x0001
|
||||
@ -275,9 +270,13 @@ public:
|
||||
#define RS_DISTANT_MESSAGING_CONTACT_PERMISSION_FLAG_EVERYBODY 0x0001
|
||||
#define RS_DISTANT_MESSAGING_CONTACT_PERMISSION_FLAG_CONTACT_LIST 0x0002
|
||||
|
||||
#define RS_DISTANT_CHAT_CONTACT_PERMISSION_FLAG_NONE 0x0000
|
||||
#define RS_DISTANT_CHAT_CONTACT_PERMISSION_FLAG_EVERYBODY 0x0001
|
||||
#define RS_DISTANT_CHAT_CONTACT_PERMISSION_FLAG_CONTACT_LIST 0x0002
|
||||
struct DistantChatPeerInfo
|
||||
{
|
||||
RsGxsId to_id ;
|
||||
RsGxsId own_id ;
|
||||
DistantChatPeerId peer_id ; // this is the tunnel id actually
|
||||
uint32_t status ; // see the values in rsmsgs.h
|
||||
};
|
||||
|
||||
// Identifier for an chat endpoint like
|
||||
// neighbour peer, distant peer, chatlobby, broadcast
|
||||
@ -286,8 +285,8 @@ class ChatId
|
||||
public:
|
||||
ChatId();
|
||||
explicit ChatId(RsPeerId id);
|
||||
explicit ChatId(RsGxsId id);
|
||||
explicit ChatId(ChatLobbyId id);
|
||||
explicit ChatId(DistantChatPeerId id);
|
||||
explicit ChatId(std::string str);
|
||||
static ChatId makeBroadcastId();
|
||||
|
||||
@ -299,13 +298,14 @@ public:
|
||||
|
||||
bool isNotSet() const;
|
||||
bool isPeerId() const;
|
||||
bool isGxsId() const;
|
||||
bool isDistantChatId() const;
|
||||
bool isLobbyId() const;
|
||||
bool isBroadcast() const;
|
||||
|
||||
RsPeerId toPeerId() const;
|
||||
RsGxsId toGxsId() const;
|
||||
ChatLobbyId toLobbyId() const;
|
||||
DistantChatPeerId toDistantChatId() const;
|
||||
|
||||
// for the very specific case of transfering a status string
|
||||
// from the chatservice to the gui,
|
||||
@ -321,7 +321,7 @@ private:
|
||||
|
||||
Type type;
|
||||
RsPeerId peer_id;
|
||||
RsGxsId gxs_id;
|
||||
DistantChatPeerId distant_chat_id;
|
||||
ChatLobbyId lobby_id;
|
||||
};
|
||||
|
||||
@ -382,15 +382,6 @@ class ChatLobbyInfo
|
||||
time_t last_activity ; // last recorded activity. Useful for removing dead lobbies.
|
||||
};
|
||||
|
||||
struct DistantChatInviteInfo
|
||||
{
|
||||
DistantChatPeerId pid ; // pid to contact the invite and refer to it.
|
||||
std::string encrypted_radix64_string ; // encrypted radix string used to for the chat link
|
||||
RsPgpId destination_pgp_id ; // pgp is of the destination of the chat link
|
||||
time_t time_of_validity ; // time when te invite becomes unusable
|
||||
uint32_t invite_flags ; // used to keep track of wether signature was ok or not.
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const Rs::Msgs::MessageInfo &info);
|
||||
|
||||
class RsMsgs;
|
||||
@ -491,9 +482,9 @@ virtual ChatLobbyId createChatLobby(const std::string& lobby_name,const RsGxsId&
|
||||
/* Distant chat */
|
||||
/****************************************/
|
||||
|
||||
virtual bool initiateDistantChatConnexion(const RsGxsId& to_pid,const RsGxsId& from_pid,uint32_t& error_code) = 0;
|
||||
virtual bool getDistantChatStatus(const RsGxsId& gxs_id,uint32_t& status, RsGxsId *from_gxs_id = NULL) = 0;
|
||||
virtual bool closeDistantChatConnexion(const RsGxsId& pid) = 0;
|
||||
virtual bool initiateDistantChatConnexion(const RsGxsId& to_pid,const RsGxsId& from_pid,DistantChatPeerId& pid,uint32_t& error_code) = 0;
|
||||
virtual bool getDistantChatStatus(const DistantChatPeerId& pid,DistantChatPeerInfo& info)=0;
|
||||
virtual bool closeDistantChatConnexion(const DistantChatPeerId& pid)=0;
|
||||
|
||||
};
|
||||
|
||||
|
@ -42,12 +42,14 @@ class p3Service ;
|
||||
class RsServiceControl ;
|
||||
class RsReputations ;
|
||||
class RsTurtle ;
|
||||
class RsGxsTunnelService ;
|
||||
class RsDht ;
|
||||
class RsDisc ;
|
||||
class RsMsgs ;
|
||||
class RsGxsForums;
|
||||
class RsGxsChannels;
|
||||
class RsNotify;
|
||||
class RsServiceControl;
|
||||
class p3LinkMgr ;
|
||||
class MainPage ;
|
||||
class QIcon ;
|
||||
@ -74,6 +76,12 @@ class RsGcxs;
|
||||
class PgpAuxUtils;
|
||||
class p3Config;
|
||||
|
||||
namespace resource_api
|
||||
{
|
||||
class ResourceRouter;
|
||||
class StateTokenServer;
|
||||
}
|
||||
|
||||
// Plugin API version. Not used yet, but will be in the future the
|
||||
// main value that decides for compatibility.
|
||||
//
|
||||
@ -107,6 +115,8 @@ public:
|
||||
RsUtil::inited_ptr<RsDisc> mDisc;
|
||||
RsUtil::inited_ptr<RsDht> mDht;
|
||||
RsUtil::inited_ptr<RsNotify> mNotify;
|
||||
RsUtil::inited_ptr<RsServiceControl> mServiceControl;
|
||||
RsUtil::inited_ptr<RsPluginHandler> mPluginHandler;
|
||||
|
||||
// gxs
|
||||
std::string mGxsDir;
|
||||
@ -117,6 +127,7 @@ public:
|
||||
RsUtil::inited_ptr<PgpAuxUtils> mPgpAuxUtils;
|
||||
RsUtil::inited_ptr<RsGxsForums> mGxsForums;
|
||||
RsUtil::inited_ptr<RsGxsChannels> mGxsChannels;
|
||||
RsUtil::inited_ptr<RsGxsTunnelService> mGxsTunnels;
|
||||
RsUtil::inited_ptr<RsReputations> mReputations;
|
||||
};
|
||||
|
||||
@ -145,6 +156,12 @@ class RsPlugin
|
||||
virtual p3Config *p3_config() const { return NULL ; }
|
||||
virtual uint16_t rs_service_id() const { return 0 ; }
|
||||
|
||||
|
||||
// creates a new resource api handler object. ownership is transferred to the caller.
|
||||
// the caller should supply a statetokenserver, and keep it valid until destruction
|
||||
// the plugin should return a entry point name. this is to make the entry point name independent from file names
|
||||
virtual resource_api::ResourceRouter* new_resource_api_handler(const RsPlugInInterfaces& ifaces, resource_api::StateTokenServer* sts, std::string &entrypoint) const { return 0;}
|
||||
|
||||
// Shutdown
|
||||
virtual void stop() {}
|
||||
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "util/rsthreads.h"
|
||||
|
||||
#include "chat/p3chatservice.h"
|
||||
#include "gxstunnel/p3gxstunnel.h"
|
||||
|
||||
#include "services/p3msgservice.h"
|
||||
#include "services/p3statusservice.h"
|
||||
@ -160,6 +161,7 @@ class RsServer: public RsControl, public RsTickingThread
|
||||
p3MsgService *msgSrv;
|
||||
p3ChatService *chatSrv;
|
||||
p3StatusService *mStatusSrv;
|
||||
p3GxsTunnelService *mGxsTunnels;
|
||||
|
||||
// This list contains all threaded services. It will be used to shut them down properly.
|
||||
|
||||
|
@ -65,11 +65,11 @@ ChatId::ChatId(RsPeerId id):
|
||||
peer_id = id;
|
||||
}
|
||||
|
||||
ChatId::ChatId(RsGxsId id):
|
||||
ChatId::ChatId(DistantChatPeerId id):
|
||||
lobby_id(0)
|
||||
{
|
||||
type = TYPE_PRIVATE_DISTANT;
|
||||
gxs_id = id;
|
||||
distant_chat_id = id;
|
||||
}
|
||||
|
||||
ChatId::ChatId(ChatLobbyId id):
|
||||
@ -93,7 +93,7 @@ ChatId::ChatId(std::string str):
|
||||
else if(str[0] == 'D')
|
||||
{
|
||||
type = TYPE_PRIVATE_DISTANT;
|
||||
gxs_id == GXSId(str.substr(1));
|
||||
distant_chat_id == DistantChatPeerId(str.substr(1));
|
||||
}
|
||||
else if(str[0] == 'L')
|
||||
{
|
||||
@ -143,7 +143,7 @@ std::string ChatId::toStdString() const
|
||||
else if(type == TYPE_PRIVATE_DISTANT)
|
||||
{
|
||||
str += "D";
|
||||
str += gxs_id.toStdString();
|
||||
str += distant_chat_id.toStdString();
|
||||
}
|
||||
else if(type == TYPE_LOBBY)
|
||||
{
|
||||
@ -186,7 +186,7 @@ bool ChatId::operator <(const ChatId& other) const
|
||||
case TYPE_PRIVATE:
|
||||
return peer_id < other.peer_id;
|
||||
case TYPE_PRIVATE_DISTANT:
|
||||
return gxs_id < other.gxs_id;
|
||||
return distant_chat_id < other.distant_chat_id;
|
||||
case TYPE_LOBBY:
|
||||
return lobby_id < other.lobby_id;
|
||||
case TYPE_BROADCAST:
|
||||
@ -210,7 +210,7 @@ bool ChatId::isSameEndpoint(const ChatId &other) const
|
||||
case TYPE_PRIVATE:
|
||||
return peer_id == other.peer_id;
|
||||
case TYPE_PRIVATE_DISTANT:
|
||||
return gxs_id == other.gxs_id;
|
||||
return distant_chat_id == other.distant_chat_id;
|
||||
case TYPE_LOBBY:
|
||||
return lobby_id == other.lobby_id;
|
||||
case TYPE_BROADCAST:
|
||||
@ -229,7 +229,7 @@ bool ChatId::isPeerId() const
|
||||
{
|
||||
return type == TYPE_PRIVATE;
|
||||
}
|
||||
bool ChatId::isGxsId() const
|
||||
bool ChatId::isDistantChatId() const
|
||||
{
|
||||
return type == TYPE_PRIVATE_DISTANT;
|
||||
}
|
||||
@ -251,14 +251,15 @@ RsPeerId ChatId::toPeerId() const
|
||||
return RsPeerId();
|
||||
}
|
||||
}
|
||||
RsGxsId ChatId::toGxsId() const
|
||||
|
||||
DistantChatPeerId ChatId::toDistantChatId() const
|
||||
{
|
||||
if(type == TYPE_PRIVATE_DISTANT)
|
||||
return gxs_id;
|
||||
return distant_chat_id;
|
||||
else
|
||||
{
|
||||
std::cerr << "ChatId Warning: conversation to RsGxsId requested, but type is different. Current value=\"" << toStdString() << "\"" << std::endl;
|
||||
return RsGxsId();
|
||||
std::cerr << "ChatId Warning: conversation to DistantChatPeerId requested, but type is different. Current value=\"" << toStdString() << "\"" << std::endl;
|
||||
return DistantChatPeerId();
|
||||
}
|
||||
}
|
||||
ChatLobbyId ChatId::toLobbyId() const
|
||||
@ -524,15 +525,15 @@ void p3Msgs::getPendingChatLobbyInvites(std::list<ChatLobbyInvite>& invites)
|
||||
{
|
||||
mChatSrv->getPendingChatLobbyInvites(invites) ;
|
||||
}
|
||||
bool p3Msgs::initiateDistantChatConnexion(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id,uint32_t& error_code)
|
||||
bool p3Msgs::initiateDistantChatConnexion(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id,DistantChatPeerId& pid,uint32_t& error_code)
|
||||
{
|
||||
return mChatSrv->initiateDistantChatConnexion(to_gxs_id,from_gxs_id,error_code) ;
|
||||
return mChatSrv->initiateDistantChatConnexion(to_gxs_id,from_gxs_id,pid,error_code) ;
|
||||
}
|
||||
bool p3Msgs::getDistantChatStatus(const RsGxsId &gxs_id,uint32_t &status,RsGxsId *from_gxs_id)
|
||||
bool p3Msgs::getDistantChatStatus(const DistantChatPeerId& pid,DistantChatPeerInfo& info)
|
||||
{
|
||||
return mChatSrv->getDistantChatStatus(gxs_id,status,from_gxs_id) ;
|
||||
return mChatSrv->getDistantChatStatus(pid,info) ;
|
||||
}
|
||||
bool p3Msgs::closeDistantChatConnexion(const RsGxsId& pid)
|
||||
bool p3Msgs::closeDistantChatConnexion(const DistantChatPeerId &pid)
|
||||
{
|
||||
return mChatSrv->closeDistantChatConnexion(pid) ;
|
||||
}
|
||||
|
@ -155,9 +155,9 @@ class p3Msgs: public RsMsgs
|
||||
virtual bool getLobbyAutoSubscribe(const ChatLobbyId& lobby_id);
|
||||
virtual ChatLobbyId createChatLobby(const std::string& lobby_name,const RsGxsId& lobby_identity,const std::string& lobby_topic,const std::set<RsPeerId>& invited_friends,ChatLobbyFlags privacy_type) ;
|
||||
|
||||
virtual bool initiateDistantChatConnexion(const RsGxsId& to_gxs_id,const RsGxsId& from_gxs_id,uint32_t& error_code) ;
|
||||
virtual bool getDistantChatStatus(const RsGxsId& gxs_id,uint32_t& status, RsGxsId *from_gxs_id=NULL) ;
|
||||
virtual bool closeDistantChatConnexion(const RsGxsId &pid) ;
|
||||
virtual bool initiateDistantChatConnexion(const RsGxsId& to_gxs_id, const RsGxsId& from_gxs_id, DistantChatPeerId &pid, uint32_t& error_code) ;
|
||||
virtual bool getDistantChatStatus(const DistantChatPeerId& gxs_id,DistantChatPeerInfo& info);
|
||||
virtual bool closeDistantChatConnexion(const DistantChatPeerId &pid) ;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -56,6 +56,8 @@
|
||||
#include <openssl/rand.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <gxstunnel/p3gxstunnel.h>
|
||||
|
||||
#define ENABLE_GROUTER
|
||||
|
||||
#if (defined(__unix__) || defined(unix)) && !defined(USG)
|
||||
@ -264,7 +266,7 @@ bool doPortRestrictions = false;
|
||||
|
||||
/******************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||
#ifndef WINDOWS_SYS
|
||||
int RsInit::InitRetroShare(int argc, char **argv, bool strictCheck)
|
||||
int RsInit::InitRetroShare(int argc, char **argv, bool /* strictCheck */)
|
||||
{
|
||||
/******************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||
#else
|
||||
@ -1486,13 +1488,17 @@ int RsServer::StartupRetroShare()
|
||||
pqih -> addService(tr,true);
|
||||
pqih -> addService(ftserver,true);
|
||||
|
||||
mGxsTunnels = new p3GxsTunnelService(mGxsIdService) ;
|
||||
mGxsTunnels->connectToTurtleRouter(tr) ;
|
||||
rsGxsTunnel = mGxsTunnels;
|
||||
|
||||
rsDisc = mDisc;
|
||||
rsMsgs = new p3Msgs(msgSrv, chatSrv);
|
||||
|
||||
// connect components to turtle router.
|
||||
|
||||
ftserver->connectToTurtleRouter(tr) ;
|
||||
chatSrv->connectToTurtleRouter(tr) ;
|
||||
chatSrv->connectToGxsTunnelService(mGxsTunnels) ;
|
||||
gr->connectToTurtleRouter(tr) ;
|
||||
#ifdef ENABLE_GROUTER
|
||||
msgSrv->connectToGlobalRouter(gr) ;
|
||||
@ -1504,6 +1510,7 @@ int RsServer::StartupRetroShare()
|
||||
pqih -> addService(msgSrv,true);
|
||||
pqih -> addService(chatSrv,true);
|
||||
pqih -> addService(mStatusSrv,true);
|
||||
pqih -> addService(mGxsTunnels,true);
|
||||
pqih -> addService(mReputations,true);
|
||||
|
||||
// set interfaces for plugins
|
||||
@ -1516,6 +1523,8 @@ int RsServer::StartupRetroShare()
|
||||
interfaces.mDisc = rsDisc;
|
||||
interfaces.mDht = rsDht;
|
||||
interfaces.mNotify = mNotify;
|
||||
interfaces.mServiceControl = serviceCtrl;
|
||||
interfaces.mPluginHandler = mPluginsManager;
|
||||
// gxs
|
||||
interfaces.mGxsDir = currGxsDir;
|
||||
interfaces.mIdentity = mGxsIdService;
|
||||
@ -1525,6 +1534,7 @@ int RsServer::StartupRetroShare()
|
||||
interfaces.mPgpAuxUtils = pgpAuxUtils;
|
||||
interfaces.mGxsForums = mGxsForums;
|
||||
interfaces.mGxsChannels = mGxsChannels;
|
||||
interfaces.mGxsTunnels = mGxsTunnels;
|
||||
interfaces.mReputations = mReputations;
|
||||
|
||||
mPluginsManager->setInterfaces(interfaces);
|
||||
|
@ -85,6 +85,8 @@ public:
|
||||
|
||||
struct MsgUpdateInfo
|
||||
{
|
||||
MsgUpdateInfo(): time_stamp(0), message_count(0) {}
|
||||
|
||||
uint32_t time_stamp ;
|
||||
uint32_t message_count ;
|
||||
};
|
||||
@ -105,7 +107,7 @@ public:
|
||||
virtual std::ostream &print(std::ostream &out, uint16_t indent);
|
||||
|
||||
RsGxsGroupId grpId;
|
||||
uint32_t msgUpdateTS; // the last time this group received a new msg
|
||||
uint32_t msgUpdateTS; // local time stamp this group last received a new msg
|
||||
};
|
||||
|
||||
|
||||
|
@ -38,6 +38,7 @@ uint32_t RsNxsSerialiser::size(RsItem *item) {
|
||||
RsNxsGrp* ngp;
|
||||
RsNxsMsg* nmg;
|
||||
RsNxsSyncGrp* sg;
|
||||
RsNxsSyncGrpStats* sgs;
|
||||
RsNxsSyncGrpItem* sgl;
|
||||
RsNxsSyncMsg* sgm;
|
||||
RsNxsSyncMsgItem* sgml;
|
||||
@ -52,6 +53,9 @@ uint32_t RsNxsSerialiser::size(RsItem *item) {
|
||||
{
|
||||
return sizeNxsSyncGrp(sg);
|
||||
|
||||
} else if((sgs = dynamic_cast<RsNxsSyncGrpStats*>(item)) != NULL)
|
||||
{
|
||||
return sizeNxsSyncGrpStats(sgs);
|
||||
}else if(( ntx = dynamic_cast<RsNxsTransac*>(item)) != NULL){
|
||||
return sizeNxsTrans(ntx);
|
||||
}
|
||||
@ -109,6 +113,8 @@ RsItem* RsNxsSerialiser::deserialise(void *data, uint32_t *size) {
|
||||
return deserialNxsSyncMsgItem(data, size);
|
||||
case RS_PKT_SUBTYPE_NXS_GRP:
|
||||
return deserialNxsGrp(data, size);
|
||||
case RS_PKT_SUBTYPE_NXS_SYNC_GRP_STATS:
|
||||
return deserialNxsSyncGrpStats(data, size);
|
||||
case RS_PKT_SUBTYPE_NXS_MSG:
|
||||
return deserialNxsMsg(data, size);
|
||||
case RS_PKT_SUBTYPE_NXS_TRANS:
|
||||
@ -134,6 +140,7 @@ bool RsNxsSerialiser::serialise(RsItem *item, void *data, uint32_t *size){
|
||||
RsNxsGrp* ngp;
|
||||
RsNxsMsg* nmg;
|
||||
RsNxsSyncGrp* sg;
|
||||
RsNxsSyncGrpStats* sgs;
|
||||
RsNxsSyncGrpItem* sgl;
|
||||
RsNxsSyncMsg* sgm;
|
||||
RsNxsSyncMsgItem* sgml;
|
||||
@ -144,6 +151,10 @@ bool RsNxsSerialiser::serialise(RsItem *item, void *data, uint32_t *size){
|
||||
{
|
||||
return serialiseNxsSyncGrp(sg, data, size);
|
||||
|
||||
}else if((sgs = dynamic_cast<RsNxsSyncGrpStats*>(item)) != NULL)
|
||||
{
|
||||
return serialiseNxsSyncGrpStats(sgs, data, size);
|
||||
|
||||
}else if ((ntx = dynamic_cast<RsNxsTransac*>(item)) != NULL)
|
||||
{
|
||||
return serialiseNxsTrans(ntx, data, size);
|
||||
@ -330,6 +341,54 @@ bool RsNxsSerialiser::serialiseNxsGrp(RsNxsGrp *item, void *data, uint32_t *size
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
bool RsNxsSerialiser::serialiseNxsSyncGrpStats(RsNxsSyncGrpStats *item, void *data, uint32_t *size)
|
||||
{
|
||||
|
||||
#ifdef RSSERIAL_DEBUG
|
||||
std::cerr << "RsNxsSerialiser::serialiseNxsSyncGrpStats()" << std::endl;
|
||||
#endif
|
||||
|
||||
uint32_t tlvsize = sizeNxsSyncGrpStats(item);
|
||||
uint32_t offset = 0;
|
||||
|
||||
if(*size < tlvsize){
|
||||
#ifdef RSSERIAL_DEBUG
|
||||
std::cerr << "RsNxsSerialiser::serialiseNxsSyncGrpStats()" << std::endl;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
*size = tlvsize;
|
||||
|
||||
bool ok = true;
|
||||
|
||||
ok &= setRsItemHeader(data, tlvsize, item->PacketId(), tlvsize);
|
||||
|
||||
/* skip the header */
|
||||
offset += 8;
|
||||
|
||||
ok &= setRawUInt32(data, *size, &offset, item->request_type);
|
||||
ok &= item->grpId.serialise(data, *size, offset) ;
|
||||
ok &= setRawUInt32(data, *size, &offset, item->number_of_posts);
|
||||
ok &= setRawUInt32(data, *size, &offset, item->last_post_TS);
|
||||
|
||||
if(offset != tlvsize){
|
||||
#ifdef RSSERIAL_DEBUG
|
||||
std::cerr << "RsNxsSerialiser::serialiseSyncGrpStats() FAIL Size Error! " << std::endl;
|
||||
#endif
|
||||
ok = false;
|
||||
}
|
||||
|
||||
#ifdef RSSERIAL_DEBUG
|
||||
if (!ok)
|
||||
{
|
||||
std::cerr << "RsNxsSerialiser::serialiseSyncGrpStats() NOK" << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
}
|
||||
bool RsNxsSerialiser::serialiseNxsSyncGrp(RsNxsSyncGrp *item, void *data, uint32_t *size)
|
||||
{
|
||||
|
||||
@ -707,6 +766,71 @@ RsNxsMsg* RsNxsSerialiser::deserialNxsMsg(void *data, uint32_t *size){
|
||||
return item;
|
||||
}
|
||||
|
||||
RsNxsSyncGrpStats* RsNxsSerialiser::deserialNxsSyncGrpStats(void *data, uint32_t *size){
|
||||
|
||||
#ifdef RSSERIAL_DEBUG
|
||||
std::cerr << "RsNxsSerialiser::deserialNxsSyncGrpStats()" << std::endl;
|
||||
#endif
|
||||
/* get the type and size */
|
||||
uint32_t rstype = getRsItemId(data);
|
||||
uint32_t rssize = getRsItemSize(data);
|
||||
|
||||
uint32_t offset = 0;
|
||||
|
||||
|
||||
if ((RS_PKT_VERSION_SERVICE != getRsItemVersion(rstype)) || (SERVICE_TYPE != getRsItemService(rstype)) || (RS_PKT_SUBTYPE_NXS_SYNC_GRP_STATS != getRsItemSubType(rstype)))
|
||||
{
|
||||
#ifdef RSSERIAL_DEBUG
|
||||
std::cerr << "RsNxsSerialiser::deserialNxsSyncGrpStats() FAIL wrong type" << std::endl;
|
||||
#endif
|
||||
return NULL; /* wrong type */
|
||||
}
|
||||
|
||||
if (*size < rssize) /* check size */
|
||||
{
|
||||
#ifdef RSSERIAL_DEBUG
|
||||
std::cerr << "RsNxsSerialiser::deserialNxsSyncGrpStats() FAIL wrong size" << std::endl;
|
||||
#endif
|
||||
return NULL; /* not enough data */
|
||||
}
|
||||
|
||||
/* set the packet length */
|
||||
*size = rssize;
|
||||
|
||||
bool ok = true;
|
||||
|
||||
RsNxsSyncGrpStats* item = new RsNxsSyncGrpStats(getRsItemService(rstype));
|
||||
/* skip the header */
|
||||
offset += 8;
|
||||
|
||||
ok &= getRawUInt32(data, *size, &offset, &(item->request_type));
|
||||
ok &= item->grpId.deserialise(data, *size, offset) ;
|
||||
ok &= getRawUInt32(data, *size, &offset, &(item->number_of_posts));
|
||||
ok &= getRawUInt32(data, *size, &offset, &(item->last_post_TS));
|
||||
|
||||
if (offset != rssize)
|
||||
{
|
||||
#ifdef RSSERIAL_DEBUG
|
||||
std::cerr << "RsNxsSerialiser::deserialNxsSyncGrpStats() FAIL size mismatch" << std::endl;
|
||||
#endif
|
||||
/* error */
|
||||
delete item;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
#ifdef RSSERIAL_DEBUG
|
||||
std::cerr << "RsNxsSerialiser::deserialNxsSyncGrpStats() NOK" << std::endl;
|
||||
#endif
|
||||
delete item;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
|
||||
RsNxsSyncGrp* RsNxsSerialiser::deserialNxsSyncGrp(void *data, uint32_t *size){
|
||||
|
||||
@ -1166,7 +1290,17 @@ uint32_t RsNxsSerialiser::sizeNxsSyncGrp(RsNxsSyncGrp *item)
|
||||
|
||||
return s;
|
||||
}
|
||||
uint32_t RsNxsSerialiser::sizeNxsSyncGrpStats(RsNxsSyncGrpStats *item)
|
||||
{
|
||||
uint32_t s = 8; // header size
|
||||
|
||||
s += 4; // request type
|
||||
s += item->grpId.serial_size();
|
||||
s += 4; // number_of_posts
|
||||
s += 4; // last_post_TS
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
uint32_t RsNxsSerialiser::sizeNxsSyncGrpItem(RsNxsSyncGrpItem *item)
|
||||
{
|
||||
@ -1260,7 +1394,6 @@ void RsNxsSyncMsg::clear()
|
||||
syncHash.clear();
|
||||
updateTS = 0;
|
||||
}
|
||||
|
||||
void RsNxsSyncGrpItem::clear()
|
||||
{
|
||||
flag = 0;
|
||||
@ -1430,7 +1563,23 @@ std::ostream& RsNxsMsg::print(std::ostream &out, uint16_t indent){
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& RsNxsSyncGrpStats::print(std::ostream &out, uint16_t indent){
|
||||
|
||||
printRsItemBase(out, "RsNxsSyncGrpStats", indent);
|
||||
uint16_t int_Indent = indent + 2;
|
||||
|
||||
out << "available posts: " << number_of_posts << std::endl;
|
||||
printIndent(out , int_Indent);
|
||||
out << "last update: " << last_post_TS << std::endl;
|
||||
printIndent(out , int_Indent);
|
||||
out << "group ID: " << grpId << std::endl;
|
||||
printIndent(out , int_Indent);
|
||||
out << "request type: " << request_type << std::endl;
|
||||
printIndent(out , int_Indent);
|
||||
|
||||
printRsItemEnd(out ,"RsNxsSyncGrpStats", indent);
|
||||
return out;
|
||||
}
|
||||
std::ostream& RsNxsTransac::print(std::ostream &out, uint16_t indent){
|
||||
|
||||
printRsItemBase(out, "RsNxsTransac", indent);
|
||||
|
@ -36,15 +36,17 @@
|
||||
#include "serialiser/rstlvkeys.h"
|
||||
#include "gxs/rsgxsdata.h"
|
||||
|
||||
// These items have "flag type" numbers, but this is not used.
|
||||
|
||||
const uint8_t RS_PKT_SUBTYPE_NXS_SYNC_GRP = 0x0001;
|
||||
const uint8_t RS_PKT_SUBTYPE_NXS_SYNC_GRP_ITEM = 0x0002;
|
||||
const uint8_t RS_PKT_SUBTYPE_NXS_GRP = 0x0004;
|
||||
const uint8_t RS_PKT_SUBTYPE_NXS_SYNC_MSG_ITEM = 0x0008;
|
||||
const uint8_t RS_PKT_SUBTYPE_NXS_SYNC_MSG = 0x0010;
|
||||
const uint8_t RS_PKT_SUBTYPE_NXS_MSG = 0x0020;
|
||||
const uint8_t RS_PKT_SUBTYPE_NXS_TRANS = 0x0040;
|
||||
const uint8_t RS_PKT_SUBTYPE_NXS_GRP_PUBLISH_KEY = 0x0080;
|
||||
const uint8_t RS_PKT_SUBTYPE_NXS_SYNC_GRP = 0x01;
|
||||
const uint8_t RS_PKT_SUBTYPE_NXS_SYNC_GRP_ITEM = 0x02;
|
||||
const uint8_t RS_PKT_SUBTYPE_NXS_SYNC_GRP_STATS = 0x03;
|
||||
const uint8_t RS_PKT_SUBTYPE_NXS_GRP = 0x04;
|
||||
const uint8_t RS_PKT_SUBTYPE_NXS_SYNC_MSG_ITEM = 0x08;
|
||||
const uint8_t RS_PKT_SUBTYPE_NXS_SYNC_MSG = 0x10;
|
||||
const uint8_t RS_PKT_SUBTYPE_NXS_MSG = 0x20;
|
||||
const uint8_t RS_PKT_SUBTYPE_NXS_TRANS = 0x40;
|
||||
const uint8_t RS_PKT_SUBTYPE_NXS_GRP_PUBLISH_KEY = 0x80;
|
||||
|
||||
|
||||
// possibility create second service to deal with this functionality
|
||||
@ -53,7 +55,7 @@ const uint8_t RS_PKT_SUBTYPE_EXT_SEARCH_GRP = 0x0001;
|
||||
const uint8_t RS_PKT_SUBTYPE_EXT_SEARCH_MSG = 0x0002;
|
||||
const uint8_t RS_PKT_SUBTYPE_EXT_DELETE_GRP = 0x0004;
|
||||
const uint8_t RS_PKT_SUBTYPE_EXT_DELETE_MSG = 0x0008;
|
||||
const uint8_t RS_PKT_SUBTYPE_EXT_SEARCH_REQ = 0x0010;
|
||||
const uint8_t RS_PKT_SUBTYPE_EXT_SEARCH_REQ = 0x0010;
|
||||
|
||||
|
||||
/*!
|
||||
@ -107,6 +109,27 @@ public:
|
||||
|
||||
};
|
||||
|
||||
/*!
|
||||
* Use to request statistics about a particular group
|
||||
*/
|
||||
class RsNxsSyncGrpStats : public RsNxsItem
|
||||
{
|
||||
public:
|
||||
|
||||
RsNxsSyncGrpStats(uint16_t servtype) : RsNxsItem(servtype, RS_PKT_SUBTYPE_NXS_SYNC_GRP_STATS) {}
|
||||
|
||||
virtual void clear() {}
|
||||
virtual std::ostream &print(std::ostream &out, uint16_t indent);
|
||||
|
||||
static const uint8_t GROUP_INFO_TYPE_REQUEST = 0x01;
|
||||
static const uint8_t GROUP_INFO_TYPE_RESPONSE = 0x02;
|
||||
|
||||
uint32_t request_type; // used to determine the type of request
|
||||
RsGxsGroupId grpId; // id of the group
|
||||
uint32_t number_of_posts; // number of posts in that group
|
||||
uint32_t last_post_TS; // time_stamp of last post
|
||||
};
|
||||
|
||||
/*!
|
||||
* Use to request grp list from peer
|
||||
* Server may advise client peer to use sync file
|
||||
@ -445,6 +468,10 @@ private:
|
||||
virtual bool serialiseNxsSyncGrp(RsNxsSyncGrp *item, void *data, uint32_t *size);
|
||||
virtual RsNxsSyncGrp* deserialNxsSyncGrp(void *data, uint32_t *size);
|
||||
|
||||
virtual uint32_t sizeNxsSyncGrpStats(RsNxsSyncGrpStats* item);
|
||||
virtual bool serialiseNxsSyncGrpStats(RsNxsSyncGrpStats *item, void *data, uint32_t *size);
|
||||
virtual RsNxsSyncGrpStats* deserialNxsSyncGrpStats(void *data, uint32_t *size);
|
||||
|
||||
/* for RS_PKT_SUBTYPE_SYNC_GRP_ITEM */
|
||||
|
||||
virtual uint32_t sizeNxsSyncGrpItem(RsNxsSyncGrpItem* item);
|
||||
|
@ -38,32 +38,33 @@
|
||||
*/
|
||||
|
||||
/* These are Cache Only */
|
||||
const uint16_t RS_SERVICE_TYPE_FILE_INDEX = 0x0001;
|
||||
const uint16_t RS_SERVICE_TYPE_FILE_INDEX = 0x0001;
|
||||
|
||||
/* These are Services only */
|
||||
const uint16_t RS_SERVICE_TYPE_DISC = 0x0011;
|
||||
const uint16_t RS_SERVICE_TYPE_CHAT = 0x0012;
|
||||
const uint16_t RS_SERVICE_TYPE_MSG = 0x0013;
|
||||
const uint16_t RS_SERVICE_TYPE_TURTLE = 0x0014;
|
||||
const uint16_t RS_SERVICE_TYPE_TUNNEL = 0x0015;
|
||||
const uint16_t RS_SERVICE_TYPE_HEARTBEAT = 0x0016;
|
||||
const uint16_t RS_SERVICE_TYPE_FILE_TRANSFER = 0x0017;
|
||||
const uint16_t RS_SERVICE_TYPE_GROUTER = 0x0018;
|
||||
const uint16_t RS_SERVICE_TYPE_DISC = 0x0011;
|
||||
const uint16_t RS_SERVICE_TYPE_CHAT = 0x0012;
|
||||
const uint16_t RS_SERVICE_TYPE_MSG = 0x0013;
|
||||
const uint16_t RS_SERVICE_TYPE_TURTLE = 0x0014;
|
||||
const uint16_t RS_SERVICE_TYPE_TUNNEL = 0x0015;
|
||||
const uint16_t RS_SERVICE_TYPE_HEARTBEAT = 0x0016;
|
||||
const uint16_t RS_SERVICE_TYPE_FILE_TRANSFER = 0x0017;
|
||||
const uint16_t RS_SERVICE_TYPE_GROUTER = 0x0018;
|
||||
|
||||
const uint16_t RS_SERVICE_TYPE_SERVICEINFO = 0x0020;
|
||||
const uint16_t RS_SERVICE_TYPE_SERVICEINFO = 0x0020;
|
||||
/* Bandwidth Control */
|
||||
const uint16_t RS_SERVICE_TYPE_BWCTRL = 0x0021;
|
||||
const uint16_t RS_SERVICE_TYPE_BWCTRL = 0x0021;
|
||||
// New Mail Service (replace old Msg Service)
|
||||
const uint16_t RS_SERVICE_TYPE_MAIL = 0x0022;
|
||||
const uint16_t RS_SERVICE_TYPE_DIRECT_MAIL = 0x0023;
|
||||
const uint16_t RS_SERVICE_TYPE_DISTANT_MAIL = 0x0024;
|
||||
const uint16_t RS_SERVICE_TYPE_GWEMAIL_MAIL = 0x0025;
|
||||
const uint16_t RS_SERVICE_TYPE_MAIL = 0x0022;
|
||||
const uint16_t RS_SERVICE_TYPE_DIRECT_MAIL = 0x0023;
|
||||
const uint16_t RS_SERVICE_TYPE_DISTANT_MAIL = 0x0024;
|
||||
const uint16_t RS_SERVICE_TYPE_GWEMAIL_MAIL = 0x0025;
|
||||
const uint16_t RS_SERVICE_TYPE_SERVICE_CONTROL= 0x0026;
|
||||
const uint16_t RS_SERVICE_TYPE_DISTANT_CHAT = 0x0027;
|
||||
const uint16_t RS_SERVICE_TYPE_DISTANT_CHAT = 0x0027;
|
||||
const uint16_t RS_SERVICE_TYPE_GXS_TUNNEL = 0x0028;
|
||||
|
||||
// Non essential services.
|
||||
const uint16_t RS_SERVICE_TYPE_BANLIST = 0x0101;
|
||||
const uint16_t RS_SERVICE_TYPE_STATUS = 0x0102;
|
||||
const uint16_t RS_SERVICE_TYPE_BANLIST = 0x0101;
|
||||
const uint16_t RS_SERVICE_TYPE_STATUS = 0x0102;
|
||||
|
||||
/* New Cache Services */
|
||||
/* Rs Network Exchange Service */
|
||||
|
@ -122,7 +122,7 @@ uint32_t p3GxsChannels::channelsAuthenPolicy()
|
||||
|
||||
|
||||
/** Overloaded to cache new groups **/
|
||||
RsGenExchange::ServiceCreate_Return p3GxsChannels::service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& keySet)
|
||||
RsGenExchange::ServiceCreate_Return p3GxsChannels::service_CreateGroup(RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& /* keySet */)
|
||||
{
|
||||
updateSubscribedGroup(grpItem->meta);
|
||||
return SERVICE_CREATE_SUCCESS;
|
||||
|
@ -40,8 +40,8 @@ class upnphandler: public pqiNetAssistFirewall
|
||||
virtual bool getExternalAddress(struct sockaddr_storage &addr);
|
||||
|
||||
/* TO IMPLEMENT: New Port Forward interface to support as many ports as necessary */
|
||||
virtual bool requestPortForward(const PortForwardParams ¶ms) { return false; }
|
||||
virtual bool statusPortForward(const uint32_t fwdId, PortForwardParams ¶ms) { return false; }
|
||||
virtual bool requestPortForward(const PortForwardParams & /* params */) { return false; }
|
||||
virtual bool statusPortForward(const uint32_t /* fwdId */, PortForwardParams & /*params*/) { return false; }
|
||||
|
||||
/* Public functions - for background thread operation,
|
||||
* but effectively private from rest of RS, as in derived class
|
||||
|
@ -40,6 +40,10 @@ std::string RsUtil::BinToHex(const std::string &bin)
|
||||
return BinToHex(bin.c_str(), bin.length());
|
||||
}
|
||||
|
||||
std::string RsUtil::BinToHex(const unsigned char *arr, const uint32_t len)
|
||||
{
|
||||
return BinToHex((char*)arr,len) ;
|
||||
}
|
||||
std::string RsUtil::BinToHex(const char *arr, const uint32_t len)
|
||||
{
|
||||
std::string out;
|
||||
|
@ -35,6 +35,7 @@ namespace RsUtil {
|
||||
|
||||
std::string BinToHex(const std::string &bin);
|
||||
std::string BinToHex(const char *arr, const uint32_t len);
|
||||
std::string BinToHex(const unsigned char *arr, const uint32_t len);
|
||||
std::string HashId(const std::string &id, bool reverse = false);
|
||||
|
||||
//std::string AccurateTimeString();
|
||||
|
@ -364,7 +364,7 @@ Changes for 0.5.5a
|
||||
|
||||
* Bug fixes
|
||||
- Fixed proper display of crypto params for UDP connections
|
||||
- Added missing location from cert when addign new friend
|
||||
- Added missing location from cert when adding new friend
|
||||
- Added missing IndicateConfigChanged to p3PeerMgrIMPL::setDynDNS
|
||||
- Fixed crash when closing the main window without the setting "Minimize to Tray Icon"
|
||||
- Renamed the setting "Do not Minimize to Tray Icon" to "Minimize to Tray
|
||||
@ -1189,7 +1189,7 @@ Changes for v0.5.3b
|
||||
- Added BSD specific changes - data directory and #including <sys/params.h>
|
||||
- improved plugin management to allow services to be used, and config pages to be added
|
||||
- Improvement to plugin system:
|
||||
- made config page system more automatic, to allow addign config pages from plugins
|
||||
- made config page system more automatic, to allow adding config pages from plugins
|
||||
- added (disabled) checkbox and function to allow all plugins for development
|
||||
- added config page methods to RsPlugin class
|
||||
- Mark local existing files in SearchDialog with red text color.
|
||||
@ -1202,7 +1202,7 @@ Changes for v0.5.3b
|
||||
- Added Cache system for GPG Certificates.
|
||||
- This should reduce gpg calls by 90+%.
|
||||
- Added translation for "[ ... Missing Message ... ]".
|
||||
- removed cache adding strategy to DL queue that was O(n^2). Now addign cache at the end of the queue
|
||||
- removed cache adding strategy to DL queue that was O(n^2). Now adding cache at the end of the queue
|
||||
- The channel message (in channels) is set to read when the user clicks on the show more button.
|
||||
- The forum/channel news feed is removed when the user reads the message in forums/channels.
|
||||
- The standard font is now used for new chat lobbies.
|
||||
|
@ -1037,8 +1037,9 @@ void IdDialog::chatIdentity()
|
||||
|
||||
RsGxsId from_gxs_id(action->data().toString().toStdString());
|
||||
uint32_t error_code ;
|
||||
DistantChatPeerId did ;
|
||||
|
||||
if(!rsMsgs->initiateDistantChatConnexion(RsGxsId(keyId), from_gxs_id, error_code))
|
||||
if(!rsMsgs->initiateDistantChatConnexion(RsGxsId(keyId), from_gxs_id, did, error_code))
|
||||
QMessageBox::information(NULL, tr("Distant chat cannot work"), QString("%1 %2: %3").arg(tr("Distant chat refused with this person.")).arg(tr("Error code")).arg(error_code)) ;
|
||||
}
|
||||
|
||||
|
@ -401,7 +401,7 @@ void MainWindow::initStackedPage()
|
||||
else
|
||||
icon = QIcon(":images/extension_48.png") ;
|
||||
|
||||
std::cerr << " Addign widget page for plugin " << rsPlugins->plugin(i)->getPluginName() << std::endl;
|
||||
std::cerr << " Adding widget page for plugin " << rsPlugins->plugin(i)->getPluginName() << std::endl;
|
||||
pluginPage->setIconPixmap(icon);
|
||||
pluginPage->setPageName(QString::fromUtf8(rsPlugins->plugin(i)->getPluginName().c_str()));
|
||||
addPage(pluginPage, grp, ¬ify);
|
||||
|
@ -1341,7 +1341,7 @@ void FlatStyle_RDM::updateRefs()
|
||||
if(details->type == DIR_TYPE_FILE) // only push files, not directories nor persons.
|
||||
_ref_entries.push_back(std::pair<void*,QString>(ref,computeDirectoryPath(*details)));
|
||||
#ifdef RDM_DEBUG
|
||||
std::cerr << "FlatStyle_RDM::postMods(): addign ref " << ref << std::endl;
|
||||
std::cerr << "FlatStyle_RDM::postMods(): adding ref " << ref << std::endl;
|
||||
#endif
|
||||
for(std::list<DirStub>::const_iterator it = details->children.begin(); it != details->children.end(); ++it)
|
||||
_ref_stack.push_back(it->ref) ;
|
||||
|
@ -300,16 +300,16 @@ void SearchDialog::initialiseFileTypeMappings()
|
||||
SearchDialog::FileTypeExtensionMap->insert(FILETYPE_IDX_AUDIO,
|
||||
"aac aif flac iff m3u m4a mid midi mp3 mpa ogg ra ram wav wma");
|
||||
SearchDialog::FileTypeExtensionMap->insert(FILETYPE_IDX_ARCHIVE,
|
||||
"7z bz2 gz pkg rar sea sit sitx tar zip");
|
||||
"7z bz2 gz pkg rar sea sit sitx tar zip tgz");
|
||||
SearchDialog::FileTypeExtensionMap->insert(FILETYPE_IDX_CDIMAGE,
|
||||
"iso nrg mdf");
|
||||
"iso nrg mdf bin");
|
||||
SearchDialog::FileTypeExtensionMap->insert(FILETYPE_IDX_DOCUMENT,
|
||||
"doc odt ott rtf pdf ps txt log msg wpd wps" );
|
||||
"doc odt ott rtf pdf ps txt log msg wpd wps ods xls epub" );
|
||||
SearchDialog::FileTypeExtensionMap->insert(FILETYPE_IDX_PICTURE,
|
||||
"3dm 3dmf ai bmp drw dxf eps gif ico indd jpe jpeg jpg mng pcx pcc pct pgm "
|
||||
"pix png psd psp qxd qxprgb sgi svg tga tif tiff xbm xcf");
|
||||
SearchDialog::FileTypeExtensionMap->insert(FILETYPE_IDX_PROGRAM,
|
||||
"app bat cgi com bin exe js pif py pl sh vb ws ");
|
||||
"app bat cgi com bin exe js pif py pl sh vb ws bash");
|
||||
SearchDialog::FileTypeExtensionMap->insert(FILETYPE_IDX_VIDEO,
|
||||
"3gp asf asx avi mov mp4 mkv flv mpeg mpg qt rm swf vob wmv");
|
||||
SearchDialog::initialised = true;
|
||||
|
@ -96,7 +96,7 @@ void ChatDialog::init(ChatId id, const QString &title)
|
||||
|
||||
if (cd == NULL) {
|
||||
|
||||
if(id.isGxsId())
|
||||
if(id.isDistantChatId())
|
||||
chatflags = RS_CHAT_OPEN | RS_CHAT_FOCUS; // force open for distant chat
|
||||
|
||||
if (chatflags & RS_CHAT_OPEN) {
|
||||
@ -104,12 +104,16 @@ void ChatDialog::init(ChatId id, const QString &title)
|
||||
ChatLobbyDialog* cld = new ChatLobbyDialog(id.toLobbyId());
|
||||
cld->init();
|
||||
cd = cld;
|
||||
} else if(id.isGxsId()) {
|
||||
PopupDistantChatDialog* pdcd = new PopupDistantChatDialog();
|
||||
QString peer_name = pdcd->getPeerName(id) ;
|
||||
pdcd->init(id.toGxsId(), tr("Talking to")+" "+peer_name) ;
|
||||
}
|
||||
else if(id.isDistantChatId())
|
||||
{
|
||||
PopupDistantChatDialog* pdcd = new PopupDistantChatDialog(id.toDistantChatId());
|
||||
|
||||
pdcd->init(id.toDistantChatId());
|
||||
cd = pdcd;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
RsPeerDetails sslDetails;
|
||||
if (rsPeers->getPeerDetails(id.toPeerId(), sslDetails)) {
|
||||
PopupChatDialog* pcd = new PopupChatDialog();
|
||||
@ -168,7 +172,7 @@ void ChatDialog::init(ChatId id, const QString &title)
|
||||
if(msg.chat_id.isBroadcast())
|
||||
return; // broadcast is not handled by a chat dialog
|
||||
|
||||
if(msg.incoming && (msg.chat_id.isPeerId() || msg.chat_id.isGxsId()))
|
||||
if(msg.incoming && (msg.chat_id.isPeerId() || msg.chat_id.isDistantChatId()))
|
||||
// play sound when recv a message
|
||||
SoundManager::play(SOUND_NEW_CHAT_MESSAGE);
|
||||
|
||||
@ -334,8 +338,8 @@ void ChatDialog::setPeerStatus(uint32_t status)
|
||||
RsPeerId vpid;
|
||||
if(mChatId.isPeerId())
|
||||
vpid = mChatId.toPeerId();
|
||||
if(mChatId.isGxsId())
|
||||
vpid = RsPeerId(mChatId.toGxsId());
|
||||
if(mChatId.isDistantChatId())
|
||||
vpid = RsPeerId(mChatId.toDistantChatId());
|
||||
cw->updateStatus(QString::fromStdString(vpid.toStdString()), status);
|
||||
}
|
||||
}
|
||||
|
@ -53,6 +53,8 @@
|
||||
#define COLUMN_ID 3
|
||||
#define COLUMN_COUNT 4
|
||||
|
||||
#define ROLE_SORT Qt::UserRole + 1
|
||||
|
||||
const static uint32_t timeToInactivity = 60 * 10; // in seconds
|
||||
|
||||
/** Default constructor */
|
||||
@ -80,10 +82,25 @@ ChatLobbyDialog::ChatLobbyDialog(const ChatLobbyId& lid, QWidget *parent, Qt::Wi
|
||||
distantChatAct = new QAction(QIcon(":/images/chat_24.png"), tr("Start private chat"), this);
|
||||
sendMessageAct = new QAction(QIcon(":/images/mail_new.png"), tr("Send Message"), this);
|
||||
|
||||
QActionGroup *sortgrp = new QActionGroup(this);
|
||||
actionSortByName = new QAction(QIcon(), tr("Sort by Name"), this);
|
||||
actionSortByName->setCheckable(true);
|
||||
actionSortByName->setChecked(true);
|
||||
actionSortByName->setActionGroup(sortgrp);
|
||||
|
||||
actionSortByActivity = new QAction(QIcon(), tr("Sort by Activity"), this);
|
||||
actionSortByActivity->setCheckable(true);
|
||||
actionSortByActivity->setChecked(false);
|
||||
actionSortByActivity->setActionGroup(sortgrp);
|
||||
|
||||
|
||||
connect(muteAct, SIGNAL(triggered()), this, SLOT(changePartipationState()));
|
||||
connect(distantChatAct, SIGNAL(triggered()), this, SLOT(distantChatParticipant()));
|
||||
connect(sendMessageAct, SIGNAL(triggered()), this, SLOT(sendMessage()));
|
||||
|
||||
connect(actionSortByName, SIGNAL(triggered()), this, SLOT(sortParcipants()));
|
||||
connect(actionSortByActivity, SIGNAL(triggered()), this, SLOT(sortParcipants()));
|
||||
|
||||
// Add a button to invite friends.
|
||||
//
|
||||
inviteFriendsButton = new QToolButton ;
|
||||
@ -94,7 +111,7 @@ ChatLobbyDialog::ChatLobbyDialog(const ChatLobbyId& lid, QWidget *parent, Qt::Wi
|
||||
inviteFriendsButton->setToolTip(tr("Invite friends to this lobby"));
|
||||
|
||||
mParticipantCompareRole = new RSTreeWidgetItemCompareRole;
|
||||
mParticipantCompareRole->setRole(0, Qt::UserRole);
|
||||
mParticipantCompareRole->setRole(COLUMN_ACTIVITY, ROLE_SORT);
|
||||
|
||||
{
|
||||
QIcon icon ;
|
||||
@ -179,6 +196,9 @@ void ChatLobbyDialog::participantsTreeWidgetCustomPopupMenu(QPoint)
|
||||
contextMnu.addAction(sendMessageAct);
|
||||
contextMnu.addSeparator();
|
||||
contextMnu.addAction(muteAct);
|
||||
contextMnu.addSeparator();
|
||||
contextMnu.addAction(actionSortByActivity);
|
||||
contextMnu.addAction(actionSortByName);
|
||||
|
||||
|
||||
muteAct->setCheckable(true);
|
||||
@ -451,6 +471,9 @@ void ChatLobbyDialog::updateParticipantsList()
|
||||
time_t tLastAct=widgetitem->text(COLUMN_ACTIVITY).toInt();
|
||||
time_t now = time(NULL);
|
||||
|
||||
widgetitem->setSizeHint(COLUMN_ICON, QSize(20,20));
|
||||
|
||||
|
||||
if(isParticipantMuted(it2->first))
|
||||
widgetitem->setIcon(COLUMN_ICON, QIcon(":/icons/bullet_red_128.png"));
|
||||
else if (tLastAct + timeToInactivity < now)
|
||||
@ -472,7 +495,7 @@ void ChatLobbyDialog::updateParticipantsList()
|
||||
}
|
||||
}
|
||||
ui.participantsList->setSortingEnabled(true);
|
||||
ui.participantsList->sortItems(COLUMN_NAME, Qt::AscendingOrder);
|
||||
sortParcipants();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -562,8 +585,9 @@ void ChatLobbyDialog::distantChatParticipant()
|
||||
rsMsgs->getIdentityForChatLobby(lobbyId, own_id);
|
||||
|
||||
uint32_t error_code ;
|
||||
DistantChatPeerId tunnel_id;
|
||||
|
||||
if(! rsMsgs->initiateDistantChatConnexion(gxs_id,own_id,error_code))
|
||||
if(! rsMsgs->initiateDistantChatConnexion(gxs_id,own_id,tunnel_id,error_code))
|
||||
{
|
||||
QString error_str ;
|
||||
switch(error_code)
|
||||
@ -761,3 +785,14 @@ void ChatLobbyDialog::showDialog(uint chatflags)
|
||||
dynamic_cast<ChatLobbyWidget*>(MainWindow::getPage(MainWindow::ChatLobby))->setCurrentChatPage(this) ;
|
||||
}
|
||||
}
|
||||
|
||||
void ChatLobbyDialog::sortParcipants()
|
||||
{
|
||||
|
||||
if (actionSortByActivity->isChecked()) {
|
||||
ui.participantsList->sortItems(COLUMN_ACTIVITY, Qt::DescendingOrder);
|
||||
} else if (actionSortByName->isChecked()) {
|
||||
ui.participantsList->sortItems(COLUMN_NAME, Qt::AscendingOrder);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ public:
|
||||
void setIdentity(const RsGxsId& gxs_id);
|
||||
bool isParticipantMuted(const RsGxsId &participant);
|
||||
ChatLobbyId id() const { return lobbyId ;}
|
||||
void sortParcipants();
|
||||
|
||||
private slots:
|
||||
void participantsTreeWidgetCustomPopupMenu( QPoint point );
|
||||
@ -104,6 +105,8 @@ private:
|
||||
|
||||
QAction *muteAct;
|
||||
QAction *distantChatAct;
|
||||
QAction *actionSortByName;
|
||||
QAction *actionSortByActivity;
|
||||
QWidgetAction *checkableAction;
|
||||
QAction *sendMessageAct;
|
||||
|
||||
|
@ -267,10 +267,12 @@ static QString getStyle(const QDir &styleDir, const QString &styleVariant, enumG
|
||||
|
||||
QString ChatStyle::formatMessage(enumFormatMessage type, const QString &name, const QDateTime ×tamp, const QString &message, unsigned int flag)
|
||||
{
|
||||
bool me = false;
|
||||
QDomDocument doc ;
|
||||
QString styleOptimized ;
|
||||
QString errorMsg ; int errorLine ; int errorColumn ;
|
||||
QString messageBody = message ;
|
||||
me = me || message.trimmed().startsWith("/me ");
|
||||
if (doc.setContent(messageBody, &errorMsg, &errorLine, &errorColumn)) {
|
||||
QDomElement body = doc.documentElement();
|
||||
if (!body.isNull()){
|
||||
@ -279,6 +281,12 @@ QString ChatStyle::formatMessage(enumFormatMessage type, const QString &name, co
|
||||
for (int curs = 0; curs < count; ++curs){
|
||||
QDomNode it = body.childNodes().item(curs);
|
||||
if (it.nodeName().toLower() != "style") {
|
||||
//find out if the message starts with /me
|
||||
if(it.isText()){
|
||||
me = me || it.toText().data().trimmed().startsWith("/me ");
|
||||
}else if(it.isElement()){
|
||||
me = me || it.toElement().text().trimmed().startsWith("/me ");
|
||||
}
|
||||
QString str;
|
||||
QTextStream stream(&str);
|
||||
it.toElement().save(stream, -1);
|
||||
@ -354,7 +362,22 @@ QString ChatStyle::formatMessage(enumFormatMessage type, const QString &name, co
|
||||
QString strName = RsHtml::plainText(name).prepend(QString("<a name=\"name\">")).append(QString("</a>"));
|
||||
QString strDate = DateTime::formatDate(timestamp.date()).prepend(QString("<a name=\"date\">")).append(QString("</a>"));
|
||||
QString strTime = DateTime::formatTime(timestamp.time()).prepend(QString("<a name=\"time\">")).append(QString("</a>"));
|
||||
|
||||
int bi = name.lastIndexOf(QRegExp(" \\(.*\\)")); //trim location from the end
|
||||
QString strShortName = RsHtml::plainText(name.left(bi)).prepend(QString("<a name=\"name\">")).append(QString("</a>"));
|
||||
|
||||
//handle /me
|
||||
//%nome% and %me% for including formatting conditionally
|
||||
//meName class for modifying the style of the name in the palce of /me
|
||||
if(me){
|
||||
messageBody = messageBody.replace(messageBody.indexOf("/me "), 3, strShortName.prepend(QString("<span class=\"meName\">")).append(QString("</span>"))); //replace only the first /me
|
||||
style = style.remove(QRegExp("%nome%.*%/nome%")).remove("%me%").remove("%/me%");
|
||||
} else {
|
||||
style = style.remove(QRegExp("%me%.*%/me%")).remove("%nome%").remove("%/nome%");
|
||||
}
|
||||
|
||||
QString formatMsg = style.replace("%name%", strName)
|
||||
.replace("%shortname%", strShortName)
|
||||
.replace("%date%", strDate)
|
||||
.replace("%time%", strTime)
|
||||
#ifdef COLORED_NICKNAMES
|
||||
|
@ -109,7 +109,7 @@ void ChatUserNotify::chatMessageReceived(ChatMessage msg)
|
||||
if(!msg.chat_id.isBroadcast()
|
||||
&&( ChatDialog::getExistingChat(msg.chat_id)
|
||||
|| (Settings->getChatFlags() & RS_CHAT_OPEN)
|
||||
|| msg.chat_id.isGxsId()))
|
||||
|| msg.chat_id.isDistantChatId()))
|
||||
{
|
||||
ChatDialog::chatMessageReceived(msg);
|
||||
}
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include "util/HandleRichText.h"
|
||||
#include "gui/chat/ChatUserNotify.h"//For BradCast
|
||||
#include "util/DateTime.h"
|
||||
#include "util/imageutil.h"
|
||||
|
||||
#include <retroshare/rsstatus.h>
|
||||
#include <retroshare/rsidentity.h>
|
||||
@ -125,6 +126,8 @@ ChatWidget::ChatWidget(QWidget *parent) :
|
||||
connect(ui->actionChooseFont, SIGNAL(triggered()), this, SLOT(chooseFont()));
|
||||
connect(ui->actionChooseColor, SIGNAL(triggered()), this, SLOT(chooseColor()));
|
||||
connect(ui->actionResetFont, SIGNAL(triggered()), this, SLOT(resetFont()));
|
||||
connect(ui->actionQuote, SIGNAL(triggered()), this, SLOT(quote()));
|
||||
connect(ui->actionSave_image, SIGNAL(triggered()), this, SLOT(saveImage()));
|
||||
|
||||
connect(ui->hashBox, SIGNAL(fileHashingFinished(QList<HashedFile>)), this, SLOT(fileHashingFinished(QList<HashedFile>)));
|
||||
|
||||
@ -255,7 +258,7 @@ void ChatWidget::init(const ChatId &chat_id, const QString &title)
|
||||
RsPeerId ownId = rsPeers->getOwnId();
|
||||
setName(QString::fromUtf8(rsPeers->getPeerName(ownId).c_str()));
|
||||
|
||||
if(chatId.isPeerId() || chatId.isGxsId())
|
||||
if(chatId.isPeerId() || chatId.isDistantChatId())
|
||||
chatStyle.setStyleFromSettings(ChatStyle::TYPE_PRIVATE);
|
||||
if(chatId.isBroadcast() || chatId.isLobbyId())
|
||||
chatStyle.setStyleFromSettings(ChatStyle::TYPE_PUBLIC);
|
||||
@ -334,7 +337,8 @@ void ChatWidget::init(const ChatId &chat_id, const QString &title)
|
||||
continue;
|
||||
|
||||
QString name;
|
||||
if (chatId.isLobbyId() || chatId.isGxsId()) {
|
||||
if (chatId.isLobbyId() || chatId.isDistantChatId())
|
||||
{
|
||||
RsIdentityDetails details;
|
||||
if (rsIdentity->getIdDetails(RsGxsId(historyIt->peerName), details))
|
||||
name = QString::fromUtf8(details.mNickname.c_str());
|
||||
@ -366,7 +370,7 @@ ChatWidget::ChatType ChatWidget::chatType()
|
||||
// but maybe it is good to have separate types in libretroshare and gui
|
||||
if(chatId.isPeerId())
|
||||
return CHATTYPE_PRIVATE;
|
||||
if(chatId.isGxsId())
|
||||
if(chatId.isDistantChatId())
|
||||
return CHATTYPE_DISTANT;
|
||||
if(chatId.isLobbyId())
|
||||
return CHATTYPE_LOBBY;
|
||||
@ -974,6 +978,14 @@ void ChatWidget::contextMenuTextBrowser(QPoint point)
|
||||
|
||||
contextMnu->addSeparator();
|
||||
contextMnu->addAction(ui->actionClearChatHistory);
|
||||
contextMnu->addAction(ui->actionQuote);
|
||||
|
||||
QTextCursor cursor = ui->textBrowser->cursorForPosition(point);
|
||||
if(ImageUtil::checkImage(cursor))
|
||||
{
|
||||
ui->actionSave_image->setData(point);
|
||||
contextMnu->addAction(ui->actionSave_image);
|
||||
}
|
||||
|
||||
contextMnu->exec(ui->textBrowser->viewport()->mapToGlobal(point));
|
||||
delete(contextMnu);
|
||||
@ -1522,77 +1534,83 @@ void ChatWidget::updateStatus(const QString &peer_id, int status)
|
||||
|
||||
// make virtual peer id from gxs id in case of distant chat
|
||||
RsPeerId vpid;
|
||||
if(chatId.isGxsId())
|
||||
vpid = RsPeerId(chatId.toGxsId());
|
||||
if(chatId.isDistantChatId())
|
||||
vpid = RsPeerId(chatId.toDistantChatId());
|
||||
else
|
||||
vpid = chatId.toPeerId();
|
||||
|
||||
/* set font size for status */
|
||||
if (peer_id.toStdString() == vpid.toStdString()) {
|
||||
// the peers status has changed
|
||||
if (peer_id.toStdString() == vpid.toStdString())
|
||||
{
|
||||
// the peers status has changed
|
||||
|
||||
QString peerName ;
|
||||
if(chatId.isGxsId())
|
||||
{
|
||||
RsIdentityDetails details ;
|
||||
if(rsIdentity->getIdDetails(chatId.toGxsId(),details))
|
||||
peerName = QString::fromUtf8( details.mNickname.c_str() ) ;
|
||||
else
|
||||
peerName = QString::fromStdString(chatId.toGxsId().toStdString()) ;
|
||||
}
|
||||
else
|
||||
peerName = QString::fromUtf8(rsPeers->getPeerName(chatId.toPeerId()).c_str());
|
||||
QString peerName ;
|
||||
if(chatId.isDistantChatId())
|
||||
{
|
||||
DistantChatPeerInfo dcpinfo ;
|
||||
RsIdentityDetails details ;
|
||||
|
||||
// is scrollbar at the end?
|
||||
QScrollBar *scrollbar = ui->textBrowser->verticalScrollBar();
|
||||
bool atEnd = (scrollbar->value() == scrollbar->maximum());
|
||||
if(rsMsgs->getDistantChatStatus(chatId.toDistantChatId(),dcpinfo))
|
||||
if(rsIdentity->getIdDetails(dcpinfo.to_id,details))
|
||||
peerName = QString::fromUtf8( details.mNickname.c_str() ) ;
|
||||
else
|
||||
peerName = QString::fromStdString(dcpinfo.to_id.toStdString()) ;
|
||||
else
|
||||
peerName = QString::fromStdString(chatId.toDistantChatId().toStdString()) ;
|
||||
}
|
||||
else
|
||||
peerName = QString::fromUtf8(rsPeers->getPeerName(chatId.toPeerId()).c_str());
|
||||
|
||||
switch (status) {
|
||||
case RS_STATUS_OFFLINE:
|
||||
ui->infoFrame->setVisible(true);
|
||||
ui->infoLabel->setText(peerName + " " + tr("appears to be Offline.") +"\n" + tr("Messages you send will be delivered after Friend is again Online"));
|
||||
break;
|
||||
// is scrollbar at the end?
|
||||
QScrollBar *scrollbar = ui->textBrowser->verticalScrollBar();
|
||||
bool atEnd = (scrollbar->value() == scrollbar->maximum());
|
||||
|
||||
case RS_STATUS_INACTIVE:
|
||||
ui->infoFrame->setVisible(true);
|
||||
ui->infoLabel->setText(peerName + " " + tr("is Idle and may not reply"));
|
||||
break;
|
||||
switch (status) {
|
||||
case RS_STATUS_OFFLINE:
|
||||
ui->infoFrame->setVisible(true);
|
||||
ui->infoLabel->setText(peerName + " " + tr("appears to be Offline.") +"\n" + tr("Messages you send will be delivered after Friend is again Online"));
|
||||
break;
|
||||
|
||||
case RS_STATUS_ONLINE:
|
||||
ui->infoFrame->setVisible(false);
|
||||
break;
|
||||
case RS_STATUS_INACTIVE:
|
||||
ui->infoFrame->setVisible(true);
|
||||
ui->infoLabel->setText(peerName + " " + tr("is Idle and may not reply"));
|
||||
break;
|
||||
|
||||
case RS_STATUS_AWAY:
|
||||
ui->infoLabel->setText(peerName + " " + tr("is Away and may not reply"));
|
||||
ui->infoFrame->setVisible(true);
|
||||
break;
|
||||
case RS_STATUS_ONLINE:
|
||||
ui->infoFrame->setVisible(false);
|
||||
break;
|
||||
|
||||
case RS_STATUS_BUSY:
|
||||
ui->infoLabel->setText(peerName + " " + tr("is Busy and may not reply"));
|
||||
ui->infoFrame->setVisible(true);
|
||||
break;
|
||||
}
|
||||
case RS_STATUS_AWAY:
|
||||
ui->infoLabel->setText(peerName + " " + tr("is Away and may not reply"));
|
||||
ui->infoFrame->setVisible(true);
|
||||
break;
|
||||
|
||||
ui->titleLabel->setText(peerName);
|
||||
ui->statusLabel->setText(QString("(%1)").arg(StatusDefs::name(status)));
|
||||
case RS_STATUS_BUSY:
|
||||
ui->infoLabel->setText(peerName + " " + tr("is Busy and may not reply"));
|
||||
ui->infoFrame->setVisible(true);
|
||||
break;
|
||||
}
|
||||
|
||||
peerStatus = status;
|
||||
ui->titleLabel->setText(peerName);
|
||||
ui->statusLabel->setText(QString("(%1)").arg(StatusDefs::name(status)));
|
||||
|
||||
if (atEnd) {
|
||||
// scroll to the end
|
||||
scrollbar->setValue(scrollbar->maximum());
|
||||
}
|
||||
peerStatus = status;
|
||||
|
||||
emit infoChanged(this);
|
||||
emit statusChanged(status);
|
||||
if (atEnd) {
|
||||
// scroll to the end
|
||||
scrollbar->setValue(scrollbar->maximum());
|
||||
}
|
||||
|
||||
// Notify all ChatWidgetHolder
|
||||
foreach (ChatWidgetHolder *chatWidgetHolder, mChatWidgetHolder) {
|
||||
chatWidgetHolder->updateStatus(status);
|
||||
}
|
||||
emit infoChanged(this);
|
||||
emit statusChanged(status);
|
||||
|
||||
return;
|
||||
}
|
||||
// Notify all ChatWidgetHolder
|
||||
foreach (ChatWidgetHolder *chatWidgetHolder, mChatWidgetHolder) {
|
||||
chatWidgetHolder->updateStatus(status);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// ignore status change
|
||||
}
|
||||
@ -1661,3 +1679,21 @@ bool ChatWidget::setStyle()
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ChatWidget::quote()
|
||||
{
|
||||
QString text = ui->textBrowser->textCursor().selection().toPlainText();
|
||||
if(text.length() > 0)
|
||||
{
|
||||
QStringList sl = text.split(QRegExp("[\r\n]"),QString::SkipEmptyParts);
|
||||
text = sl.join("\n>");
|
||||
emit ui->chatTextEdit->append(QString(">") + text);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatWidget::saveImage()
|
||||
{
|
||||
QPoint point = ui->actionSave_image->data().toPoint();
|
||||
QTextCursor cursor = ui->textBrowser->cursorForPosition(point);
|
||||
ImageUtil::extractImage(window(), cursor);
|
||||
}
|
||||
|
@ -185,6 +185,9 @@ private slots:
|
||||
bool fileSave();
|
||||
bool fileSaveAs();
|
||||
|
||||
void quote();
|
||||
void saveImage();
|
||||
|
||||
private:
|
||||
bool findText(const QString& qsStringToFind);
|
||||
bool findText(const QString& qsStringToFind, bool bBackWard, bool bForceMove);
|
||||
|
@ -972,6 +972,23 @@ border-image: url(:/images/closepressed.png)
|
||||
<string>Search Box</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionQuote">
|
||||
<property name="text">
|
||||
<string>Quote</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Quotes the selected text</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave_image">
|
||||
<property name="icon">
|
||||
<iconset resource="../images.qrc">
|
||||
<normaloff>:/images/document_save.png</normaloff>:/images/document_save.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save image</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
@ -43,9 +43,11 @@ PopupDistantChatDialog::~PopupDistantChatDialog()
|
||||
delete _update_timer ;
|
||||
}
|
||||
|
||||
PopupDistantChatDialog::PopupDistantChatDialog(QWidget *parent, Qt::WindowFlags flags)
|
||||
PopupDistantChatDialog::PopupDistantChatDialog(const DistantChatPeerId& tunnel_id,QWidget *parent, Qt::WindowFlags flags)
|
||||
: PopupChatDialog(parent,flags)
|
||||
{
|
||||
_tunnel_id = tunnel_id ;
|
||||
|
||||
_status_label = new QToolButton ;
|
||||
_update_timer = new QTimer ;
|
||||
|
||||
@ -61,97 +63,98 @@ PopupDistantChatDialog::PopupDistantChatDialog(QWidget *parent, Qt::WindowFlags
|
||||
updateDisplay() ;
|
||||
}
|
||||
|
||||
void PopupDistantChatDialog::init(const RsGxsId &gxs_id,const QString & title)
|
||||
void PopupDistantChatDialog::init(const DistantChatPeerId &peer_id)
|
||||
{
|
||||
_pid = gxs_id ;
|
||||
PopupChatDialog::init(ChatId(gxs_id), title) ;
|
||||
_tunnel_id = peer_id;
|
||||
DistantChatPeerInfo tinfo;
|
||||
|
||||
RsGxsId own_gxs_id ;
|
||||
uint32_t status ;
|
||||
if(!rsMsgs->getDistantChatStatus(_tunnel_id,tinfo))
|
||||
return ;
|
||||
|
||||
// do not use setOwnId, because we don't want the user to change the GXS avatar from the chat window
|
||||
RsIdentityDetails iddetails ;
|
||||
|
||||
if(rsIdentity->getIdDetails(tinfo.to_id,iddetails))
|
||||
PopupChatDialog::init(ChatId(peer_id), QString::fromUtf8(iddetails.mNickname.c_str())) ;
|
||||
else
|
||||
PopupChatDialog::init(ChatId(peer_id), QString::fromStdString(tinfo.to_id.toStdString())) ;
|
||||
|
||||
// Do not use setOwnId, because we don't want the user to change the GXS avatar from the chat window
|
||||
// it will not be transmitted.
|
||||
|
||||
if(rsMsgs->getDistantChatStatus(gxs_id,status,&own_gxs_id))
|
||||
ui.ownAvatarWidget->setId(ChatId(own_gxs_id));
|
||||
ui.ownAvatarWidget->setOwnId() ; // sets the flag
|
||||
ui.ownAvatarWidget->setId(ChatId(peer_id)) ; // sets the actual Id
|
||||
}
|
||||
|
||||
void PopupDistantChatDialog::updateDisplay()
|
||||
{
|
||||
if(RsAutoUpdatePage::eventsLocked()) // we need to do that by end, because it's not possible to derive from both PopupChatDialog and RsAutoUpdatePage
|
||||
return ; // which both derive from QObject. Signals-slot connexions won't work anymore.
|
||||
if(RsAutoUpdatePage::eventsLocked()) // we need to do that by end, because it's not possible to derive from both PopupChatDialog and RsAutoUpdatePage
|
||||
return ; // which both derive from QObject. Signals-slot connexions won't work anymore.
|
||||
|
||||
if(!isVisible())
|
||||
return ;
|
||||
if(!isVisible())
|
||||
return ;
|
||||
|
||||
//std::cerr << "Checking tunnel..." ;
|
||||
// make sure about the tunnel status
|
||||
//
|
||||
//std::cerr << "Checking tunnel..." ;
|
||||
// make sure about the tunnel status
|
||||
//
|
||||
|
||||
uint32_t status= RS_DISTANT_CHAT_STATUS_UNKNOWN;
|
||||
rsMsgs->getDistantChatStatus(_pid,status) ;
|
||||
DistantChatPeerInfo tinfo;
|
||||
rsMsgs->getDistantChatStatus(_tunnel_id,tinfo) ;
|
||||
|
||||
ui.avatarWidget->setId(ChatId(_pid));
|
||||
ui.avatarWidget->setId(ChatId(_tunnel_id));
|
||||
|
||||
QString msg;
|
||||
switch(status)
|
||||
{
|
||||
case RS_DISTANT_CHAT_STATUS_UNKNOWN: //std::cerr << "Unknown hash. Error!" << std::endl;
|
||||
_status_label->setIcon(QIcon(IMAGE_GRY_LED)) ;
|
||||
msg = tr("Hash Error. No tunnel.");
|
||||
_status_label->setToolTip(msg) ;
|
||||
getChatWidget()->updateStatusString("%1", msg, true);
|
||||
getChatWidget()->blockSending(tr("Can't send message, because there is no tunnel."));
|
||||
setPeerStatus(RS_STATUS_OFFLINE) ;
|
||||
break ;
|
||||
case RS_DISTANT_CHAT_STATUS_REMOTELY_CLOSED: std::cerr << "Chat remotely closed. " << std::endl;
|
||||
_status_label->setIcon(QIcon(IMAGE_RED_LED)) ;
|
||||
_status_label->setToolTip(QObject::tr("Distant peer has closed the chat")) ;
|
||||
|
||||
getChatWidget()->updateStatusString("%1", tr("The person you're talking to has deleted the secured chat tunnel. You may remove the chat window now."), true);
|
||||
getChatWidget()->blockSending(tr("Can't send message, because the chat partner deleted the secure tunnel."));
|
||||
setPeerStatus(RS_STATUS_OFFLINE) ;
|
||||
switch(tinfo.status)
|
||||
{
|
||||
case RS_DISTANT_CHAT_STATUS_UNKNOWN: //std::cerr << "Unknown hash. Error!" << std::endl;
|
||||
_status_label->setIcon(QIcon(IMAGE_GRY_LED)) ;
|
||||
msg = tr("Chat remotely closed. Please close this window.");
|
||||
_status_label->setToolTip(msg) ;
|
||||
getChatWidget()->updateStatusString("%1", msg, true);
|
||||
getChatWidget()->blockSending(tr("Can't send message, because there is no tunnel."));
|
||||
setPeerStatus(RS_STATUS_OFFLINE) ;
|
||||
break ;
|
||||
case RS_DISTANT_CHAT_STATUS_REMOTELY_CLOSED: std::cerr << "Chat remotely closed. " << std::endl;
|
||||
_status_label->setIcon(QIcon(IMAGE_RED_LED)) ;
|
||||
_status_label->setToolTip(QObject::tr("Distant peer has closed the chat")) ;
|
||||
|
||||
break ;
|
||||
case RS_DISTANT_CHAT_STATUS_TUNNEL_DN: //std::cerr << "Tunnel asked. Waiting for reponse. " << std::endl;
|
||||
_status_label->setIcon(QIcon(IMAGE_RED_LED)) ;
|
||||
msg = QObject::tr("Tunnel is pending...");
|
||||
_status_label->setToolTip(msg) ;
|
||||
getChatWidget()->updateStatusString("%1", msg, true);
|
||||
getChatWidget()->blockSending(msg);
|
||||
setPeerStatus(RS_STATUS_OFFLINE) ;
|
||||
break ;
|
||||
case RS_DISTANT_CHAT_STATUS_TUNNEL_OK: //std::cerr << "Tunnel is ok. " << std::endl;
|
||||
_status_label->setIcon(QIcon(IMAGE_YEL_LED)) ;
|
||||
msg = QObject::tr("Secured tunnel established. Waiting for ACK...");
|
||||
_status_label->setToolTip(msg) ;
|
||||
getChatWidget()->updateStatusString("%1", msg, true);
|
||||
getChatWidget()->blockSending(msg);
|
||||
setPeerStatus(RS_STATUS_ONLINE) ;
|
||||
break ;
|
||||
case RS_DISTANT_CHAT_STATUS_CAN_TALK: //std::cerr << "Tunnel is ok and data is transmitted." << std::endl;
|
||||
_status_label->setIcon(QIcon(IMAGE_GRN_LED)) ;
|
||||
msg = QObject::tr("Secured tunnel is working. You can talk!");
|
||||
_status_label->setToolTip(msg) ;
|
||||
getChatWidget()->unblockSending();
|
||||
setPeerStatus(RS_STATUS_ONLINE) ;
|
||||
break ;
|
||||
}
|
||||
getChatWidget()->updateStatusString("%1", tr("The person you're talking to has deleted the secured chat tunnel. You may remove the chat window now."), true);
|
||||
getChatWidget()->blockSending(tr("Can't send message, because the chat partner deleted the secure tunnel."));
|
||||
setPeerStatus(RS_STATUS_OFFLINE) ;
|
||||
|
||||
break ;
|
||||
case RS_DISTANT_CHAT_STATUS_TUNNEL_DN: //std::cerr << "Tunnel asked. Waiting for reponse. " << std::endl;
|
||||
_status_label->setIcon(QIcon(IMAGE_RED_LED)) ;
|
||||
msg = QObject::tr("Tunnel is pending...");
|
||||
_status_label->setToolTip(msg) ;
|
||||
getChatWidget()->updateStatusString("%1", msg, true);
|
||||
getChatWidget()->blockSending(msg);
|
||||
setPeerStatus(RS_STATUS_OFFLINE) ;
|
||||
break ;
|
||||
case RS_DISTANT_CHAT_STATUS_CAN_TALK: //std::cerr << "Tunnel is ok and data is transmitted." << std::endl;
|
||||
_status_label->setIcon(QIcon(IMAGE_GRN_LED)) ;
|
||||
msg = QObject::tr("Secured tunnel is working. You can talk!");
|
||||
_status_label->setToolTip(msg) ;
|
||||
getChatWidget()->unblockSending();
|
||||
setPeerStatus(RS_STATUS_ONLINE) ;
|
||||
break ;
|
||||
}
|
||||
}
|
||||
|
||||
void PopupDistantChatDialog::closeEvent(QCloseEvent *e)
|
||||
{
|
||||
//std::cerr << "Closing window => closing distant chat for hash " << _pid << std::endl;
|
||||
//std::cerr << "Closing window => closing distant chat for hash " << _pid << std::endl;
|
||||
|
||||
uint32_t status= RS_DISTANT_CHAT_STATUS_UNKNOWN;
|
||||
rsMsgs->getDistantChatStatus(_pid,status) ;
|
||||
DistantChatPeerInfo tinfo ;
|
||||
|
||||
if(status != RS_DISTANT_CHAT_STATUS_REMOTELY_CLOSED)
|
||||
rsMsgs->getDistantChatStatus(_tunnel_id,tinfo) ;
|
||||
|
||||
if(tinfo.status != RS_DISTANT_CHAT_STATUS_REMOTELY_CLOSED)
|
||||
{
|
||||
QString msg = tr("Closing this window will end the conversation, notify the peer and remove the encrypted tunnel.") ;
|
||||
|
||||
if(QMessageBox::Ok == QMessageBox::critical(NULL,tr("Kill the tunnel?"),msg, QMessageBox::Ok | QMessageBox::Cancel))
|
||||
rsMsgs->closeDistantChatConnexion(_pid) ;
|
||||
rsMsgs->closeDistantChatConnexion(_tunnel_id) ;
|
||||
else
|
||||
{
|
||||
e->ignore() ;
|
||||
@ -166,23 +169,26 @@ void PopupDistantChatDialog::closeEvent(QCloseEvent *e)
|
||||
|
||||
QString PopupDistantChatDialog::getPeerName(const ChatId &id) const
|
||||
{
|
||||
DistantChatPeerInfo tinfo;
|
||||
|
||||
rsMsgs->getDistantChatStatus(_tunnel_id,tinfo) ;
|
||||
|
||||
RsIdentityDetails details ;
|
||||
if(rsIdentity->getIdDetails(id.toGxsId(),details))
|
||||
if(rsIdentity->getIdDetails(tinfo.to_id,details))
|
||||
return QString::fromUtf8( details.mNickname.c_str() ) ;
|
||||
else
|
||||
return QString::fromStdString(id.toGxsId().toStdString()) ;
|
||||
return QString::fromStdString(tinfo.to_id.toStdString()) ;
|
||||
}
|
||||
|
||||
QString PopupDistantChatDialog::getOwnName() const
|
||||
{
|
||||
uint32_t status= RS_DISTANT_CHAT_STATUS_UNKNOWN;
|
||||
RsGxsId from_gxs_id ;
|
||||
DistantChatPeerInfo tinfo;
|
||||
|
||||
rsMsgs->getDistantChatStatus(_pid,status,&from_gxs_id) ;
|
||||
rsMsgs->getDistantChatStatus(_tunnel_id,tinfo) ;
|
||||
|
||||
RsIdentityDetails details ;
|
||||
if(rsIdentity->getIdDetails(from_gxs_id,details))
|
||||
if(rsIdentity->getIdDetails(tinfo.own_id,details))
|
||||
return QString::fromUtf8( details.mNickname.c_str() ) ;
|
||||
else
|
||||
return QString::fromStdString(from_gxs_id.toStdString()) ;
|
||||
return QString::fromStdString(tinfo.own_id.toStdString()) ;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <retroshare/rsgxstunnel.h>
|
||||
#include "PopupChatDialog.h"
|
||||
|
||||
class QTimer ;
|
||||
@ -33,11 +34,11 @@ class PopupDistantChatDialog: public PopupChatDialog
|
||||
|
||||
protected:
|
||||
/** Default constructor */
|
||||
PopupDistantChatDialog(QWidget *parent = 0, Qt::WindowFlags flags = 0);
|
||||
PopupDistantChatDialog(const DistantChatPeerId &tunnel_id, QWidget *parent = 0, Qt::WindowFlags flags = 0);
|
||||
/** Default destructor */
|
||||
virtual ~PopupDistantChatDialog();
|
||||
|
||||
virtual void init(const RsGxsId &gxs_id, const QString &title);
|
||||
virtual void init(const DistantChatPeerId& peer_id);
|
||||
virtual void closeEvent(QCloseEvent *e) ;
|
||||
|
||||
virtual QString getPeerName(const ChatId &id) const ;
|
||||
@ -48,7 +49,7 @@ class PopupDistantChatDialog: public PopupChatDialog
|
||||
|
||||
private:
|
||||
QTimer *_update_timer ;
|
||||
RsGxsId _pid ;
|
||||
DistantChatPeerId _tunnel_id ;
|
||||
QToolButton *_status_label ;
|
||||
|
||||
friend class ChatDialog;
|
||||
|
@ -124,8 +124,7 @@ void AvatarWidget::setFrameType(FrameType type)
|
||||
void AvatarWidget::setId(const ChatId &id)
|
||||
{
|
||||
mId = id;
|
||||
// mPgpId = rsPeers->getGPGId(id) ;
|
||||
// mFlag.isGpg = false ;
|
||||
mGxsId.clear();
|
||||
|
||||
setPixmap(QPixmap());
|
||||
|
||||
@ -136,12 +135,22 @@ void AvatarWidget::setId(const ChatId &id)
|
||||
refreshAvatarImage();
|
||||
refreshStatus();
|
||||
}
|
||||
void AvatarWidget::setOwnId(const RsGxsId& own_gxs_id)
|
||||
{
|
||||
mFlag.isOwnId = true;
|
||||
|
||||
setId(ChatId(own_gxs_id));
|
||||
void AvatarWidget::setGxsId(const RsGxsId &id)
|
||||
{
|
||||
mId = ChatId();
|
||||
mGxsId = id;
|
||||
|
||||
setPixmap(QPixmap());
|
||||
|
||||
if (id.isNull()) {
|
||||
setEnabled(false);
|
||||
}
|
||||
|
||||
refreshAvatarImage();
|
||||
refreshStatus();
|
||||
}
|
||||
|
||||
void AvatarWidget::setOwnId()
|
||||
{
|
||||
mFlag.isOwnId = true;
|
||||
@ -181,7 +190,7 @@ void AvatarWidget::refreshStatus()
|
||||
rsStatus->getOwnStatus(statusInfo);
|
||||
status = statusInfo.status ;
|
||||
}
|
||||
else if(mId.isGxsId())
|
||||
else if(mId.isDistantChatId())
|
||||
status = RS_STATUS_ONLINE ;
|
||||
else
|
||||
{
|
||||
@ -198,11 +207,15 @@ void AvatarWidget::refreshStatus()
|
||||
rsStatus->getStatus(mId.toPeerId(), statusInfo);
|
||||
status = statusInfo.status ;
|
||||
}
|
||||
else if(mId.isGxsId())
|
||||
{
|
||||
if(!rsMsgs->getDistantChatStatus(mId.toGxsId(),status))
|
||||
status = RS_STATUS_OFFLINE ;
|
||||
}
|
||||
else if(mId.isDistantChatId())
|
||||
{
|
||||
DistantChatPeerInfo dcpinfo ;
|
||||
|
||||
if(rsMsgs->getDistantChatStatus(mId.toDistantChatId(),dcpinfo))
|
||||
status = dcpinfo.status ;
|
||||
else
|
||||
std::cerr << "(EE) cannot get distant chat status for ID=" << mId.toDistantChatId() << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Unhandled chat id type in AvatarWidget::refreshStatus()" << std::endl;
|
||||
@ -235,13 +248,22 @@ void AvatarWidget::updateStatus(int status)
|
||||
void AvatarWidget::updateAvatar(const QString &peerId)
|
||||
{
|
||||
if(mId.isPeerId() && mId.toPeerId() == RsPeerId(peerId.toStdString()))
|
||||
refreshAvatarImage() ;
|
||||
|
||||
if(mId.isGxsId() && mId.toGxsId() == RsGxsId(peerId.toStdString()))
|
||||
refreshAvatarImage() ;
|
||||
refreshAvatarImage() ;
|
||||
else if(mId.isDistantChatId() && mId.toDistantChatId() == DistantChatPeerId(peerId.toStdString()))
|
||||
refreshAvatarImage() ;
|
||||
else
|
||||
std::cerr << "(EE) cannot update avatar. mId has unhandled type." << std::endl;
|
||||
}
|
||||
void AvatarWidget::refreshAvatarImage()
|
||||
{
|
||||
if (mGxsId.isNull()==false)
|
||||
{
|
||||
QPixmap avatar;
|
||||
|
||||
AvatarDefs::getAvatarFromGxsId(mGxsId, avatar, defaultAvatar);
|
||||
setPixmap(avatar);
|
||||
return;
|
||||
}
|
||||
if (mId.isNotSet())
|
||||
{
|
||||
QPixmap avatar(defaultAvatar);
|
||||
@ -262,12 +284,21 @@ void AvatarWidget::refreshAvatarImage()
|
||||
setPixmap(avatar);
|
||||
return;
|
||||
}
|
||||
else if (mId.isGxsId())
|
||||
else if (mId.isDistantChatId())
|
||||
{
|
||||
QPixmap avatar;
|
||||
AvatarDefs::getAvatarFromGxsId(mId.toGxsId(), avatar, defaultAvatar);
|
||||
setPixmap(avatar);
|
||||
return;
|
||||
QPixmap avatar;
|
||||
|
||||
DistantChatPeerInfo dcpinfo ;
|
||||
|
||||
if(rsMsgs->getDistantChatStatus(mId.toDistantChatId(),dcpinfo))
|
||||
{
|
||||
if(mFlag.isOwnId)
|
||||
AvatarDefs::getAvatarFromGxsId(dcpinfo.own_id, avatar, defaultAvatar);
|
||||
else
|
||||
AvatarDefs::getAvatarFromGxsId(dcpinfo.to_id, avatar, defaultAvatar);
|
||||
setPixmap(avatar);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
std::cerr << "WARNING: unhandled situation in AvatarWidget::refreshAvatarImage()" << std::endl;
|
||||
|
@ -50,8 +50,8 @@ public:
|
||||
QString frameState();
|
||||
void setFrameType(FrameType type);
|
||||
void setId(const ChatId& id) ;
|
||||
void setGxsId(const RsGxsId& id) ;
|
||||
void setOwnId();
|
||||
void setOwnId(const RsGxsId&);
|
||||
void setDefaultAvatar(const QString &avatar_file_name);
|
||||
|
||||
protected:
|
||||
@ -71,6 +71,7 @@ private:
|
||||
Ui::AvatarWidget *ui;
|
||||
|
||||
ChatId mId;
|
||||
RsGxsId mGxsId;
|
||||
|
||||
struct {
|
||||
bool isOwnId : 1;
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include <QPushButton>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <math.h>
|
||||
#include "Emoticons.h"
|
||||
#include "util/HandleRichText.h"
|
||||
|
||||
@ -48,7 +48,7 @@ void Emoticons::load()
|
||||
internalEmoticons = false;
|
||||
} else {
|
||||
// then embedded emotions
|
||||
sm_file.setFileName(":/smileys/emotes.acs");
|
||||
sm_file.setFileName(":/emojione/emotes.acs");
|
||||
if(!sm_file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
std::cout << "error opening ressource file" << std::endl ;
|
||||
@ -56,7 +56,7 @@ void Emoticons::load()
|
||||
}
|
||||
}
|
||||
#else
|
||||
QFile sm_file(QString(":/smileys/emotes.acs"));
|
||||
QFile sm_file(QString(":/emojione/emotes.acs"));
|
||||
if(!sm_file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
std::cout << "error opening ressource file" << std::endl ;
|
||||
@ -128,9 +128,9 @@ void Emoticons::showSmileyWidget(QWidget *parent, QWidget *button, const char *s
|
||||
|
||||
const int buttonWidth = 26;
|
||||
const int buttonHeight = 26;
|
||||
const int countPerLine = 9;
|
||||
|
||||
int rowCount = (Smileys.size()/countPerLine) + ((Smileys.size() % countPerLine) ? 1 : 0);
|
||||
int rowCount = (int)sqrt((double)Smileys.size());
|
||||
int countPerLine = (Smileys.size()/rowCount) + ((Smileys.size() % rowCount) ? 1 : 0);
|
||||
|
||||
smWidget->setAttribute( Qt::WA_DeleteOnClose);
|
||||
smWidget->setWindowTitle("Emoticons");
|
||||
|
@ -46,7 +46,7 @@ void GroupSelectionBox::selectedGroupIds(std::list<std::string> &groupIds) const
|
||||
QListWidgetItem *listItem = item(i);
|
||||
if (listItem->checkState() == Qt::Checked) {
|
||||
groupIds.push_back(item(i)->data(ROLE_ID).toString().toStdString());
|
||||
std::cerr << "Addign selected item " << groupIds.back() << std::endl;
|
||||
std::cerr << "Adding selected item " << groupIds.back() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -74,7 +74,7 @@ void GroupSelectionBox::selectedGroupNames(QList<QString> &groupNames) const
|
||||
QListWidgetItem *listItem = item(i);
|
||||
if (listItem->checkState() == Qt::Checked) {
|
||||
groupNames.push_back(item(i)->text());
|
||||
std::cerr << "Addign selected item " << groupNames.back().toUtf8().constData() << std::endl;
|
||||
std::cerr << "Adding selected item " << groupNames.back().toUtf8().constData() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ MimeTextEdit::MimeTextEdit(QWidget *parent)
|
||||
mCompleterKeyModifiers = Qt::ControlModifier;
|
||||
mCompleterKey = Qt::Key_Space;
|
||||
mForceCompleterShowNextKeyEvent = false;
|
||||
highliter = new RsSyntaxHighlighter(this);
|
||||
}
|
||||
|
||||
bool MimeTextEdit::canInsertFromMimeData(const QMimeData* source) const
|
||||
@ -231,6 +232,8 @@ void MimeTextEdit::contextMenuEvent(QContextMenuEvent *e)
|
||||
|
||||
/* Add actions for pasting links */
|
||||
contextMenu->addAction( tr("Paste as plain text"), this, SLOT(pastePlainText()));
|
||||
QAction *spoilerAction = contextMenu->addAction(tr("Spoiler"), this, SLOT(spoiler()));
|
||||
spoilerAction->setToolTip(tr("Select text to hide, then push this button"));
|
||||
contextMenu->addSeparator();
|
||||
QAction *pasteLinkAction = contextMenu->addAction(QIcon(":/images/pasterslink.png"), tr("Paste RetroShare Link"), this, SLOT(pasteLink()));
|
||||
contextMenu->addAction(QIcon(":/images/pasterslink.png"), tr("Paste my certificate link"), this, SLOT(pasteOwnCertificateLink()));
|
||||
@ -268,3 +271,8 @@ void MimeTextEdit::pastePlainText()
|
||||
{
|
||||
insertPlainText(QApplication::clipboard()->text());
|
||||
}
|
||||
|
||||
void MimeTextEdit::spoiler()
|
||||
{
|
||||
RsHtml::insertSpoilerText(this->textCursor());
|
||||
}
|
||||
|
@ -24,11 +24,14 @@
|
||||
|
||||
#include <QCompleter>
|
||||
#include "RSTextEdit.h"
|
||||
#include "util/RsSyntaxHighlighter.h"
|
||||
|
||||
class MimeTextEdit : public RSTextEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QColor textColorQuote READ textColorQuote WRITE setTextColorQuote)
|
||||
|
||||
public:
|
||||
MimeTextEdit(QWidget *parent = 0);
|
||||
|
||||
@ -44,6 +47,11 @@ public:
|
||||
// Add QAction to context menu (action won't be deleted)
|
||||
void addContextMenuAction(QAction *action);
|
||||
|
||||
QColor textColorQuote() const { return highliter->textColorQuote();}
|
||||
|
||||
public slots:
|
||||
void setTextColorQuote(QColor textColorQuote) { highliter->setTextColorQuote(textColorQuote);}
|
||||
|
||||
signals:
|
||||
void calculateContextMenuActions();
|
||||
|
||||
@ -59,6 +67,8 @@ private slots:
|
||||
void pasteLink();
|
||||
void pasteOwnCertificateLink();
|
||||
void pastePlainText();
|
||||
void spoiler();
|
||||
|
||||
private:
|
||||
QString textUnderCursor() const;
|
||||
|
||||
@ -69,6 +79,7 @@ private:
|
||||
bool mForceCompleterShowNextKeyEvent;
|
||||
QString mCompleterStartString;
|
||||
QList<QAction*> mContextMenuActions;
|
||||
RsSyntaxHighlighter *highliter;
|
||||
};
|
||||
|
||||
#endif // MIMETEXTEDIT_H
|
||||
|
@ -14,6 +14,8 @@ RSTextBrowser::RSTextBrowser(QWidget *parent) :
|
||||
mImageBlockWidget = NULL;
|
||||
mLinkClickActive = true;
|
||||
|
||||
highliter = new RsSyntaxHighlighter(this);
|
||||
|
||||
connect(this, SIGNAL(anchorClicked(QUrl)), this, SLOT(linkClicked(QUrl)));
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define RSTEXTBROWSER_H
|
||||
|
||||
#include <QTextBrowser>
|
||||
#include "util/RsSyntaxHighlighter.h"
|
||||
|
||||
class RSImageBlockWidget;
|
||||
|
||||
@ -9,6 +10,8 @@ class RSTextBrowser : public QTextBrowser
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QColor textColorQuote READ textColorQuote WRITE setTextColorQuote)
|
||||
|
||||
public:
|
||||
explicit RSTextBrowser(QWidget *parent = 0);
|
||||
|
||||
@ -20,8 +23,11 @@ public:
|
||||
|
||||
virtual QVariant loadResource(int type, const QUrl &name);
|
||||
|
||||
QColor textColorQuote() const { return highliter->textColorQuote();}
|
||||
|
||||
public slots:
|
||||
void showImages();
|
||||
void setTextColorQuote(QColor textColorQuote) { highliter->setTextColorQuote(textColorQuote);}
|
||||
|
||||
private slots:
|
||||
void linkClicked(const QUrl &url);
|
||||
@ -35,6 +41,7 @@ private:
|
||||
bool mShowImages;
|
||||
RSImageBlockWidget *mImageBlockWidget;
|
||||
bool mLinkClickActive;
|
||||
RsSyntaxHighlighter *highliter;
|
||||
};
|
||||
|
||||
#endif // RSTEXTBROWSER_H
|
||||
|
549
retroshare-gui/src/gui/emojione.qrc
Normal file
@ -0,0 +1,549 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>emojione/00A9.png</file>
|
||||
<file>emojione/00AE.png</file>
|
||||
<file>emojione/1F004.png</file>
|
||||
<file>emojione/1F4AA.png</file>
|
||||
<file>emojione/1F4AB.png</file>
|
||||
<file>emojione/1F4AC.png</file>
|
||||
<file>emojione/1F4AD.png</file>
|
||||
<file>emojione/1F4AE.png</file>
|
||||
<file>emojione/1F4AF.png</file>
|
||||
<file>emojione/1F4C0.png</file>
|
||||
<file>emojione/1F4C1.png</file>
|
||||
<file>emojione/1F4C2.png</file>
|
||||
<file>emojione/1F4C3.png</file>
|
||||
<file>emojione/1F4C4.png</file>
|
||||
<file>emojione/1F4C5.png</file>
|
||||
<file>emojione/1F4C6.png</file>
|
||||
<file>emojione/1F4C7.png</file>
|
||||
<file>emojione/1F4C8.png</file>
|
||||
<file>emojione/1F4C9.png</file>
|
||||
<file>emojione/1F4CA.png</file>
|
||||
<file>emojione/1F4CB.png</file>
|
||||
<file>emojione/1F4CC.png</file>
|
||||
<file>emojione/1F4CD.png</file>
|
||||
<file>emojione/1F4CE.png</file>
|
||||
<file>emojione/1F4CF.png</file>
|
||||
<file>emojione/1F4D0.png</file>
|
||||
<file>emojione/1F4D1.png</file>
|
||||
<file>emojione/1F4D2.png</file>
|
||||
<file>emojione/1F4D3.png</file>
|
||||
<file>emojione/1F4D4.png</file>
|
||||
<file>emojione/1F4D5.png</file>
|
||||
<file>emojione/1F4D6.png</file>
|
||||
<file>emojione/1F4D7.png</file>
|
||||
<file>emojione/1F4D8.png</file>
|
||||
<file>emojione/1F4D9.png</file>
|
||||
<file>emojione/1F4DA.png</file>
|
||||
<file>emojione/1F4DB.png</file>
|
||||
<file>emojione/1F4DC.png</file>
|
||||
<file>emojione/1F4DD.png</file>
|
||||
<file>emojione/1F4DE.png</file>
|
||||
<file>emojione/1F4DF.png</file>
|
||||
<file>emojione/1F4E0.png</file>
|
||||
<file>emojione/1F4E1.png</file>
|
||||
<file>emojione/1F4E2.png</file>
|
||||
<file>emojione/1F4E3.png</file>
|
||||
<file>emojione/1F4E4.png</file>
|
||||
<file>emojione/1F4E5.png</file>
|
||||
<file>emojione/1F4E6.png</file>
|
||||
<file>emojione/1F4E7.png</file>
|
||||
<file>emojione/1F4E8.png</file>
|
||||
<file>emojione/1F4E9.png</file>
|
||||
<file>emojione/1F4EA.png</file>
|
||||
<file>emojione/1F4EB.png</file>
|
||||
<file>emojione/1F4EC.png</file>
|
||||
<file>emojione/1F4ED.png</file>
|
||||
<file>emojione/1F4EE.png</file>
|
||||
<file>emojione/1F4EF.png</file>
|
||||
<file>emojione/1F4F0.png</file>
|
||||
<file>emojione/1F4F1.png</file>
|
||||
<file>emojione/1F4F2.png</file>
|
||||
<file>emojione/1F4F3.png</file>
|
||||
<file>emojione/1F4F4.png</file>
|
||||
<file>emojione/1F4F5.png</file>
|
||||
<file>emojione/1F4F6.png</file>
|
||||
<file>emojione/1F4F7.png</file>
|
||||
<file>emojione/1F4F8.png</file>
|
||||
<file>emojione/1F4F9.png</file>
|
||||
<file>emojione/1F4FA.png</file>
|
||||
<file>emojione/1F4FB.png</file>
|
||||
<file>emojione/1F4FC.png</file>
|
||||
<file>emojione/1F4FD.png</file>
|
||||
<file>emojione/1F4FE.png</file>
|
||||
<file>emojione/1F5E2.png</file>
|
||||
<file>emojione/1F17E.png</file>
|
||||
<file>emojione/1F17F.png</file>
|
||||
<file>emojione/1F18E.png</file>
|
||||
<file>emojione/1F19A.png</file>
|
||||
<file>emojione/1F21A.png</file>
|
||||
<file>emojione/1F22F.png</file>
|
||||
<file>emojione/1F23A.png</file>
|
||||
<file>emojione/1F32A.png</file>
|
||||
<file>emojione/1F32B.png</file>
|
||||
<file>emojione/1F32C.png</file>
|
||||
<file>emojione/1F36A.png</file>
|
||||
<file>emojione/1F37A.png</file>
|
||||
<file>emojione/1F37B.png</file>
|
||||
<file>emojione/1F43A.png</file>
|
||||
<file>emojione/1F43B.png</file>
|
||||
<file>emojione/1F43C.png</file>
|
||||
<file>emojione/1F43D.png</file>
|
||||
<file>emojione/1F43E.png</file>
|
||||
<file>emojione/1F43F.png</file>
|
||||
<file>emojione/1F44A.png</file>
|
||||
<file>emojione/1F44B.png</file>
|
||||
<file>emojione/1F44C.png</file>
|
||||
<file>emojione/1F44D.png</file>
|
||||
<file>emojione/1F44E.png</file>
|
||||
<file>emojione/1F44F.png</file>
|
||||
<file>emojione/1F46A.png</file>
|
||||
<file>emojione/1F46B.png</file>
|
||||
<file>emojione/1F46C.png</file>
|
||||
<file>emojione/1F46D.png</file>
|
||||
<file>emojione/1F46E.png</file>
|
||||
<file>emojione/1F46F.png</file>
|
||||
<file>emojione/1F47A.png</file>
|
||||
<file>emojione/1F47B.png</file>
|
||||
<file>emojione/1F47C.png</file>
|
||||
<file>emojione/1F47D.png</file>
|
||||
<file>emojione/1F47E.png</file>
|
||||
<file>emojione/1F47F.png</file>
|
||||
<file>emojione/1F48A.png</file>
|
||||
<file>emojione/1F48B.png</file>
|
||||
<file>emojione/1F48C.png</file>
|
||||
<file>emojione/1F48D.png</file>
|
||||
<file>emojione/1F48E.png</file>
|
||||
<file>emojione/1F48F.png</file>
|
||||
<file>emojione/1F49A.png</file>
|
||||
<file>emojione/1F49B.png</file>
|
||||
<file>emojione/1F49C.png</file>
|
||||
<file>emojione/1F49D.png</file>
|
||||
<file>emojione/1F49E.png</file>
|
||||
<file>emojione/1F49F.png</file>
|
||||
<file>emojione/1F54A.png</file>
|
||||
<file>emojione/1F60A.png</file>
|
||||
<file>emojione/1F60B.png</file>
|
||||
<file>emojione/1F60C.png</file>
|
||||
<file>emojione/1F60D.png</file>
|
||||
<file>emojione/1F60E.png</file>
|
||||
<file>emojione/1F60F.png</file>
|
||||
<file>emojione/1F61A.png</file>
|
||||
<file>emojione/1F61B.png</file>
|
||||
<file>emojione/1F61C.png</file>
|
||||
<file>emojione/1F61D.png</file>
|
||||
<file>emojione/1F61E.png</file>
|
||||
<file>emojione/1F61F.png</file>
|
||||
<file>emojione/1F62A.png</file>
|
||||
<file>emojione/1F62B.png</file>
|
||||
<file>emojione/1F62C.png</file>
|
||||
<file>emojione/1F62D.png</file>
|
||||
<file>emojione/1F62E.png</file>
|
||||
<file>emojione/1F62F.png</file>
|
||||
<file>emojione/1F63A.png</file>
|
||||
<file>emojione/1F63B.png</file>
|
||||
<file>emojione/1F63C.png</file>
|
||||
<file>emojione/1F63D.png</file>
|
||||
<file>emojione/1F63E.png</file>
|
||||
<file>emojione/1F63F.png</file>
|
||||
<file>emojione/1F64A.png</file>
|
||||
<file>emojione/1F64B.png</file>
|
||||
<file>emojione/1F64C.png</file>
|
||||
<file>emojione/1F64D.png</file>
|
||||
<file>emojione/1F64E.png</file>
|
||||
<file>emojione/1F64F.png</file>
|
||||
<file>emojione/1F68A.png</file>
|
||||
<file>emojione/1F68B.png</file>
|
||||
<file>emojione/1F68C.png</file>
|
||||
<file>emojione/1F68D.png</file>
|
||||
<file>emojione/1F68E.png</file>
|
||||
<file>emojione/1F68F.png</file>
|
||||
<file>emojione/1F69A.png</file>
|
||||
<file>emojione/1F69B.png</file>
|
||||
<file>emojione/1F69C.png</file>
|
||||
<file>emojione/1F69D.png</file>
|
||||
<file>emojione/1F69E.png</file>
|
||||
<file>emojione/1F69F.png</file>
|
||||
<file>emojione/1F170.png</file>
|
||||
<file>emojione/1F171.png</file>
|
||||
<file>emojione/1F191.png</file>
|
||||
<file>emojione/1F192.png</file>
|
||||
<file>emojione/1F193.png</file>
|
||||
<file>emojione/1F194.png</file>
|
||||
<file>emojione/1F195.png</file>
|
||||
<file>emojione/1F196.png</file>
|
||||
<file>emojione/1F197.png</file>
|
||||
<file>emojione/1F198.png</file>
|
||||
<file>emojione/1F199.png</file>
|
||||
<file>emojione/1F201.png</file>
|
||||
<file>emojione/1F202.png</file>
|
||||
<file>emojione/1F232.png</file>
|
||||
<file>emojione/1F233.png</file>
|
||||
<file>emojione/1F234.png</file>
|
||||
<file>emojione/1F235.png</file>
|
||||
<file>emojione/1F236.png</file>
|
||||
<file>emojione/1F237.png</file>
|
||||
<file>emojione/1F238.png</file>
|
||||
<file>emojione/1F239.png</file>
|
||||
<file>emojione/1F250.png</file>
|
||||
<file>emojione/1F251.png</file>
|
||||
<file>emojione/1F300.png</file>
|
||||
<file>emojione/1F301.png</file>
|
||||
<file>emojione/1F302.png</file>
|
||||
<file>emojione/1F303.png</file>
|
||||
<file>emojione/1F304.png</file>
|
||||
<file>emojione/1F305.png</file>
|
||||
<file>emojione/1F306.png</file>
|
||||
<file>emojione/1F307.png</file>
|
||||
<file>emojione/1F308.png</file>
|
||||
<file>emojione/1F309.png</file>
|
||||
<file>emojione/1F310.png</file>
|
||||
<file>emojione/1F311.png</file>
|
||||
<file>emojione/1F312.png</file>
|
||||
<file>emojione/1F313.png</file>
|
||||
<file>emojione/1F314.png</file>
|
||||
<file>emojione/1F315.png</file>
|
||||
<file>emojione/1F316.png</file>
|
||||
<file>emojione/1F317.png</file>
|
||||
<file>emojione/1F318.png</file>
|
||||
<file>emojione/1F319.png</file>
|
||||
<file>emojione/1F320.png</file>
|
||||
<file>emojione/1F321.png</file>
|
||||
<file>emojione/1F327.png</file>
|
||||
<file>emojione/1F328.png</file>
|
||||
<file>emojione/1F329.png</file>
|
||||
<file>emojione/1F330.png</file>
|
||||
<file>emojione/1F331.png</file>
|
||||
<file>emojione/1F332.png</file>
|
||||
<file>emojione/1F333.png</file>
|
||||
<file>emojione/1F334.png</file>
|
||||
<file>emojione/1F335.png</file>
|
||||
<file>emojione/1F336.png</file>
|
||||
<file>emojione/1F337.png</file>
|
||||
<file>emojione/1F338.png</file>
|
||||
<file>emojione/1F339.png</file>
|
||||
<file>emojione/1F340.png</file>
|
||||
<file>emojione/1F341.png</file>
|
||||
<file>emojione/1F342.png</file>
|
||||
<file>emojione/1F343.png</file>
|
||||
<file>emojione/1F344.png</file>
|
||||
<file>emojione/1F345.png</file>
|
||||
<file>emojione/1F346.png</file>
|
||||
<file>emojione/1F347.png</file>
|
||||
<file>emojione/1F348.png</file>
|
||||
<file>emojione/1F349.png</file>
|
||||
<file>emojione/1F350.png</file>
|
||||
<file>emojione/1F351.png</file>
|
||||
<file>emojione/1F352.png</file>
|
||||
<file>emojione/1F353.png</file>
|
||||
<file>emojione/1F354.png</file>
|
||||
<file>emojione/1F355.png</file>
|
||||
<file>emojione/1F356.png</file>
|
||||
<file>emojione/1F357.png</file>
|
||||
<file>emojione/1F358.png</file>
|
||||
<file>emojione/1F359.png</file>
|
||||
<file>emojione/1F360.png</file>
|
||||
<file>emojione/1F361.png</file>
|
||||
<file>emojione/1F362.png</file>
|
||||
<file>emojione/1F363.png</file>
|
||||
<file>emojione/1F364.png</file>
|
||||
<file>emojione/1F365.png</file>
|
||||
<file>emojione/1F366.png</file>
|
||||
<file>emojione/1F367.png</file>
|
||||
<file>emojione/1F368.png</file>
|
||||
<file>emojione/1F369.png</file>
|
||||
<file>emojione/1F370.png</file>
|
||||
<file>emojione/1F371.png</file>
|
||||
<file>emojione/1F372.png</file>
|
||||
<file>emojione/1F373.png</file>
|
||||
<file>emojione/1F374.png</file>
|
||||
<file>emojione/1F375.png</file>
|
||||
<file>emojione/1F376.png</file>
|
||||
<file>emojione/1F377.png</file>
|
||||
<file>emojione/1F378.png</file>
|
||||
<file>emojione/1F379.png</file>
|
||||
<file>emojione/1F380.png</file>
|
||||
<file>emojione/1F381.png</file>
|
||||
<file>emojione/1F382.png</file>
|
||||
<file>emojione/1F383.png</file>
|
||||
<file>emojione/1F384.png</file>
|
||||
<file>emojione/1F385.png</file>
|
||||
<file>emojione/1F386.png</file>
|
||||
<file>emojione/1F387.png</file>
|
||||
<file>emojione/1F388.png</file>
|
||||
<file>emojione/1F389.png</file>
|
||||
<file>emojione/1F390.png</file>
|
||||
<file>emojione/1F391.png</file>
|
||||
<file>emojione/1F392.png</file>
|
||||
<file>emojione/1F393.png</file>
|
||||
<file>emojione/1F394.png</file>
|
||||
<file>emojione/1F395.png</file>
|
||||
<file>emojione/1F396.png</file>
|
||||
<file>emojione/1F397.png</file>
|
||||
<file>emojione/1F398.png</file>
|
||||
<file>emojione/1F399.png</file>
|
||||
<file>emojione/1F400.png</file>
|
||||
<file>emojione/1F401.png</file>
|
||||
<file>emojione/1F402.png</file>
|
||||
<file>emojione/1F403.png</file>
|
||||
<file>emojione/1F404.png</file>
|
||||
<file>emojione/1F405.png</file>
|
||||
<file>emojione/1F406.png</file>
|
||||
<file>emojione/1F407.png</file>
|
||||
<file>emojione/1F408.png</file>
|
||||
<file>emojione/1F409.png</file>
|
||||
<file>emojione/1F410.png</file>
|
||||
<file>emojione/1F411.png</file>
|
||||
<file>emojione/1F412.png</file>
|
||||
<file>emojione/1F413.png</file>
|
||||
<file>emojione/1F414.png</file>
|
||||
<file>emojione/1F415.png</file>
|
||||
<file>emojione/1F416.png</file>
|
||||
<file>emojione/1F417.png</file>
|
||||
<file>emojione/1F418.png</file>
|
||||
<file>emojione/1F419.png</file>
|
||||
<file>emojione/1F420.png</file>
|
||||
<file>emojione/1F421.png</file>
|
||||
<file>emojione/1F422.png</file>
|
||||
<file>emojione/1F423.png</file>
|
||||
<file>emojione/1F424.png</file>
|
||||
<file>emojione/1F425.png</file>
|
||||
<file>emojione/1F426.png</file>
|
||||
<file>emojione/1F427.png</file>
|
||||
<file>emojione/1F428.png</file>
|
||||
<file>emojione/1F429.png</file>
|
||||
<file>emojione/1F430.png</file>
|
||||
<file>emojione/1F431.png</file>
|
||||
<file>emojione/1F432.png</file>
|
||||
<file>emojione/1F433.png</file>
|
||||
<file>emojione/1F434.png</file>
|
||||
<file>emojione/1F435.png</file>
|
||||
<file>emojione/1F436.png</file>
|
||||
<file>emojione/1F437.png</file>
|
||||
<file>emojione/1F438.png</file>
|
||||
<file>emojione/1F439.png</file>
|
||||
<file>emojione/1F440.png</file>
|
||||
<file>emojione/1F441.png</file>
|
||||
<file>emojione/1F442.png</file>
|
||||
<file>emojione/1F443.png</file>
|
||||
<file>emojione/1F444.png</file>
|
||||
<file>emojione/1F445.png</file>
|
||||
<file>emojione/1F446.png</file>
|
||||
<file>emojione/1F447.png</file>
|
||||
<file>emojione/1F448.png</file>
|
||||
<file>emojione/1F449.png</file>
|
||||
<file>emojione/1F450.png</file>
|
||||
<file>emojione/1F451.png</file>
|
||||
<file>emojione/1F452.png</file>
|
||||
<file>emojione/1F453.png</file>
|
||||
<file>emojione/1F454.png</file>
|
||||
<file>emojione/1F455.png</file>
|
||||
<file>emojione/1F456.png</file>
|
||||
<file>emojione/1F457.png</file>
|
||||
<file>emojione/1F458.png</file>
|
||||
<file>emojione/1F459.png</file>
|
||||
<file>emojione/1F460.png</file>
|
||||
<file>emojione/1F461.png</file>
|
||||
<file>emojione/1F462.png</file>
|
||||
<file>emojione/1F463.png</file>
|
||||
<file>emojione/1F464.png</file>
|
||||
<file>emojione/1F465.png</file>
|
||||
<file>emojione/1F466.png</file>
|
||||
<file>emojione/1F467.png</file>
|
||||
<file>emojione/1F468.png</file>
|
||||
<file>emojione/1F469.png</file>
|
||||
<file>emojione/1F470.png</file>
|
||||
<file>emojione/1F471.png</file>
|
||||
<file>emojione/1F472.png</file>
|
||||
<file>emojione/1F473.png</file>
|
||||
<file>emojione/1F474.png</file>
|
||||
<file>emojione/1F475.png</file>
|
||||
<file>emojione/1F476.png</file>
|
||||
<file>emojione/1F477.png</file>
|
||||
<file>emojione/1F478.png</file>
|
||||
<file>emojione/1F479.png</file>
|
||||
<file>emojione/1F480.png</file>
|
||||
<file>emojione/1F481.png</file>
|
||||
<file>emojione/1F482.png</file>
|
||||
<file>emojione/1F483.png</file>
|
||||
<file>emojione/1F484.png</file>
|
||||
<file>emojione/1F485.png</file>
|
||||
<file>emojione/1F486.png</file>
|
||||
<file>emojione/1F487.png</file>
|
||||
<file>emojione/1F488.png</file>
|
||||
<file>emojione/1F489.png</file>
|
||||
<file>emojione/1F490.png</file>
|
||||
<file>emojione/1F491.png</file>
|
||||
<file>emojione/1F492.png</file>
|
||||
<file>emojione/1F493.png</file>
|
||||
<file>emojione/1F494.png</file>
|
||||
<file>emojione/1F495.png</file>
|
||||
<file>emojione/1F496.png</file>
|
||||
<file>emojione/1F497.png</file>
|
||||
<file>emojione/1F498.png</file>
|
||||
<file>emojione/1F499.png</file>
|
||||
<file>emojione/1F574.png</file>
|
||||
<file>emojione/1F575.png</file>
|
||||
<file>emojione/1F595.png</file>
|
||||
<file>emojione/1F596.png</file>
|
||||
<file>emojione/1F597.png</file>
|
||||
<file>emojione/1F598.png</file>
|
||||
<file>emojione/1F599.png</file>
|
||||
<file>emojione/1F600.png</file>
|
||||
<file>emojione/1F601.png</file>
|
||||
<file>emojione/1F602.png</file>
|
||||
<file>emojione/1F603.png</file>
|
||||
<file>emojione/1F604.png</file>
|
||||
<file>emojione/1F605.png</file>
|
||||
<file>emojione/1F606.png</file>
|
||||
<file>emojione/1F607.png</file>
|
||||
<file>emojione/1F608.png</file>
|
||||
<file>emojione/1F609.png</file>
|
||||
<file>emojione/1F610.png</file>
|
||||
<file>emojione/1F611.png</file>
|
||||
<file>emojione/1F612.png</file>
|
||||
<file>emojione/1F613.png</file>
|
||||
<file>emojione/1F614.png</file>
|
||||
<file>emojione/1F615.png</file>
|
||||
<file>emojione/1F616.png</file>
|
||||
<file>emojione/1F617.png</file>
|
||||
<file>emojione/1F618.png</file>
|
||||
<file>emojione/1F619.png</file>
|
||||
<file>emojione/1F620.png</file>
|
||||
<file>emojione/1F621.png</file>
|
||||
<file>emojione/1F622.png</file>
|
||||
<file>emojione/1F623.png</file>
|
||||
<file>emojione/1F624.png</file>
|
||||
<file>emojione/1F625.png</file>
|
||||
<file>emojione/1F626.png</file>
|
||||
<file>emojione/1F627.png</file>
|
||||
<file>emojione/1F628.png</file>
|
||||
<file>emojione/1F629.png</file>
|
||||
<file>emojione/1F630.png</file>
|
||||
<file>emojione/1F631.png</file>
|
||||
<file>emojione/1F632.png</file>
|
||||
<file>emojione/1F633.png</file>
|
||||
<file>emojione/1F634.png</file>
|
||||
<file>emojione/1F635.png</file>
|
||||
<file>emojione/1F636.png</file>
|
||||
<file>emojione/1F637.png</file>
|
||||
<file>emojione/1F638.png</file>
|
||||
<file>emojione/1F639.png</file>
|
||||
<file>emojione/1F640.png</file>
|
||||
<file>emojione/1F641.png</file>
|
||||
<file>emojione/1F642.png</file>
|
||||
<file>emojione/1F645.png</file>
|
||||
<file>emojione/1F646.png</file>
|
||||
<file>emojione/1F647.png</file>
|
||||
<file>emojione/1F648.png</file>
|
||||
<file>emojione/1F649.png</file>
|
||||
<file>emojione/1F680.png</file>
|
||||
<file>emojione/1F681.png</file>
|
||||
<file>emojione/1F682.png</file>
|
||||
<file>emojione/1F683.png</file>
|
||||
<file>emojione/1F684.png</file>
|
||||
<file>emojione/1F685.png</file>
|
||||
<file>emojione/1F686.png</file>
|
||||
<file>emojione/1F687.png</file>
|
||||
<file>emojione/1F688.png</file>
|
||||
<file>emojione/1F689.png</file>
|
||||
<file>emojione/1F690.png</file>
|
||||
<file>emojione/1F691.png</file>
|
||||
<file>emojione/1F692.png</file>
|
||||
<file>emojione/1F693.png</file>
|
||||
<file>emojione/1F694.png</file>
|
||||
<file>emojione/1F695.png</file>
|
||||
<file>emojione/1F696.png</file>
|
||||
<file>emojione/1F697.png</file>
|
||||
<file>emojione/1F698.png</file>
|
||||
<file>emojione/1F699.png</file>
|
||||
<file>emojione/2B1B.png</file>
|
||||
<file>emojione/2B1C.png</file>
|
||||
<file>emojione/2B05.png</file>
|
||||
<file>emojione/2B06.png</file>
|
||||
<file>emojione/2B07.png</file>
|
||||
<file>emojione/2B50.png</file>
|
||||
<file>emojione/2B55.png</file>
|
||||
<file>emojione/21A9.png</file>
|
||||
<file>emojione/21AA.png</file>
|
||||
<file>emojione/23E9.png</file>
|
||||
<file>emojione/23EA.png</file>
|
||||
<file>emojione/23EB.png</file>
|
||||
<file>emojione/23EC.png</file>
|
||||
<file>emojione/23F0.png</file>
|
||||
<file>emojione/23F3.png</file>
|
||||
<file>emojione/24C2.png</file>
|
||||
<file>emojione/25AA.png</file>
|
||||
<file>emojione/25AB.png</file>
|
||||
<file>emojione/25B6.png</file>
|
||||
<file>emojione/25C0.png</file>
|
||||
<file>emojione/25FB.png</file>
|
||||
<file>emojione/25FC.png</file>
|
||||
<file>emojione/25FD.png</file>
|
||||
<file>emojione/25FE.png</file>
|
||||
<file>emojione/26A0.png</file>
|
||||
<file>emojione/26A1.png</file>
|
||||
<file>emojione/26AA.png</file>
|
||||
<file>emojione/26AB.png</file>
|
||||
<file>emojione/26BD.png</file>
|
||||
<file>emojione/26BE.png</file>
|
||||
<file>emojione/26C4.png</file>
|
||||
<file>emojione/26C5.png</file>
|
||||
<file>emojione/26CE.png</file>
|
||||
<file>emojione/26D4.png</file>
|
||||
<file>emojione/26EA.png</file>
|
||||
<file>emojione/26F2.png</file>
|
||||
<file>emojione/26F3.png</file>
|
||||
<file>emojione/26F5.png</file>
|
||||
<file>emojione/26FA.png</file>
|
||||
<file>emojione/26FD.png</file>
|
||||
<file>emojione/27A1.png</file>
|
||||
<file>emojione/27B0.png</file>
|
||||
<file>emojione/27BF.png</file>
|
||||
<file>emojione/203C.png</file>
|
||||
<file>emojione/231A.png</file>
|
||||
<file>emojione/231B.png</file>
|
||||
<file>emojione/260E.png</file>
|
||||
<file>emojione/261D.png</file>
|
||||
<file>emojione/263A.png</file>
|
||||
<file>emojione/264A.png</file>
|
||||
<file>emojione/264B.png</file>
|
||||
<file>emojione/264C.png</file>
|
||||
<file>emojione/264D.png</file>
|
||||
<file>emojione/264E.png</file>
|
||||
<file>emojione/264F.png</file>
|
||||
<file>emojione/267B.png</file>
|
||||
<file>emojione/267F.png</file>
|
||||
<file>emojione/270A.png</file>
|
||||
<file>emojione/270B.png</file>
|
||||
<file>emojione/270C.png</file>
|
||||
<file>emojione/270F.png</file>
|
||||
<file>emojione/274C.png</file>
|
||||
<file>emojione/274E.png</file>
|
||||
<file>emojione/303D.png</file>
|
||||
<file>emojione/2049.png</file>
|
||||
<file>emojione/2600.png</file>
|
||||
<file>emojione/2601.png</file>
|
||||
<file>emojione/2611.png</file>
|
||||
<file>emojione/2614.png</file>
|
||||
<file>emojione/2615.png</file>
|
||||
<file>emojione/2708.png</file>
|
||||
<file>emojione/2744.png</file>
|
||||
<file>emojione/2764.png</file>
|
||||
<file>emojione/2934.png</file>
|
||||
<file>emojione/2935.png</file>
|
||||
<file>emojione/3030.png</file>
|
||||
<file>emojione/3297.png</file>
|
||||
<file>emojione/3299.png</file>
|
||||
<file>emojione/1f910.png</file>
|
||||
<file>emojione/1f911.png</file>
|
||||
<file>emojione/1f912.png</file>
|
||||
<file>emojione/1f913.png</file>
|
||||
<file>emojione/1f914.png</file>
|
||||
<file>emojione/1f915.png</file>
|
||||
<file>emojione/1f916.png</file>
|
||||
<file>emojione/1f643.png</file>
|
||||
<file>emojione/emotes.acs</file>
|
||||
</qresource>
|
||||
</RCC>
|
BIN
retroshare-gui/src/gui/emojione/0023-20E3.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
retroshare-gui/src/gui/emojione/002a-20e3.png
Normal file
After Width: | Height: | Size: 987 B |
BIN
retroshare-gui/src/gui/emojione/0030-20E3.png
Normal file
After Width: | Height: | Size: 866 B |
BIN
retroshare-gui/src/gui/emojione/0031-20E3.png
Normal file
After Width: | Height: | Size: 656 B |
BIN
retroshare-gui/src/gui/emojione/0032-20E3.png
Normal file
After Width: | Height: | Size: 899 B |
BIN
retroshare-gui/src/gui/emojione/0033-20E3.png
Normal file
After Width: | Height: | Size: 967 B |
BIN
retroshare-gui/src/gui/emojione/0034-20E3.png
Normal file
After Width: | Height: | Size: 786 B |
BIN
retroshare-gui/src/gui/emojione/0035-20E3.png
Normal file
After Width: | Height: | Size: 923 B |
BIN
retroshare-gui/src/gui/emojione/0036-20E3.png
Normal file
After Width: | Height: | Size: 961 B |
BIN
retroshare-gui/src/gui/emojione/0037-20E3.png
Normal file
After Width: | Height: | Size: 782 B |
BIN
retroshare-gui/src/gui/emojione/0038-20E3.png
Normal file
After Width: | Height: | Size: 1002 B |
BIN
retroshare-gui/src/gui/emojione/0039-20E3.png
Normal file
After Width: | Height: | Size: 976 B |
BIN
retroshare-gui/src/gui/emojione/00A9.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
retroshare-gui/src/gui/emojione/00AE.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
retroshare-gui/src/gui/emojione/1F004.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
retroshare-gui/src/gui/emojione/1F0CF.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
retroshare-gui/src/gui/emojione/1F170.png
Normal file
After Width: | Height: | Size: 689 B |
BIN
retroshare-gui/src/gui/emojione/1F171.png
Normal file
After Width: | Height: | Size: 710 B |
BIN
retroshare-gui/src/gui/emojione/1F17E.png
Normal file
After Width: | Height: | Size: 881 B |
BIN
retroshare-gui/src/gui/emojione/1F17F.png
Normal file
After Width: | Height: | Size: 672 B |