merged with upstream/master

This commit is contained in:
csoler 2016-05-01 15:22:13 -04:00
commit 70648398e2
39 changed files with 1086 additions and 584 deletions

View File

@ -1,5 +1,40 @@
retroshare06 (0.6.0-1.XXXXXX~YYYYYY) YYYYYY; urgency=low retroshare06 (0.6.0-1.XXXXXX~YYYYYY) YYYYYY; urgency=low
0dc43c3 csoler Sat, 23 Apr 2016 08:29:53 -0400 Merge pull request #338 from Nyfor/master
5e94c77 Nyfor Mon, 4 Apr 2016 12:07:09 +0200 Fixed compilation for Clang.
d696f72 csoler Fri, 22 Apr 2016 20:38:07 -0400 fixed compilation
acd059b csoler Fri, 22 Apr 2016 18:49:42 -0400 removed potential memory leak in TransfersDialog
52cf66a csoler Fri, 22 Apr 2016 17:55:15 -0400 fixed memory leak in SubscribeToolButton menu
55e8087 csoler Fri, 22 Apr 2016 17:30:55 -0400 added missing free for public keys used in envelop encryption
10230df csoler Fri, 22 Apr 2016 16:50:43 -0400 added missing SSL shutdown when replacing existing connection
5261c3c csoler Thu, 21 Apr 2016 22:23:07 -0400 prevented turtle to not deleting a config item when it is not cast
e9fa9eb csoler Thu, 21 Apr 2016 22:07:50 -0400 removed tricky memory leak in chat lobbies due to handling of partial messages
7aea6e5 csoler Thu, 21 Apr 2016 22:07:10 -0400 removed some debug info
eca83fd csoler Thu, 21 Apr 2016 19:54:50 -0400 removed some debug info
fba3d37 csoler Thu, 21 Apr 2016 19:47:34 -0400 fixed memory leak after receiving RsNxsItem deserialised from decrypted memory
0d3ff0e csoler Thu, 21 Apr 2016 19:46:47 -0400 fixed possible uninitialised memory read in memory decryption return
0c711a4 csoler Thu, 21 Apr 2016 19:41:21 -0400 added missing calls to EVP_CIPHER_CTX_cleanup() to release memory after decryption, causing memory
3fae108 csoler Thu, 21 Apr 2016 12:58:48 -0400 removed div by zero in transfers dialog
0572492 csoler Wed, 20 Apr 2016 21:20:47 -0400 severely reduced packet grouping, which limited the effectiveness of QoS
d6ae71e csoler Wed, 20 Apr 2016 20:21:29 -0400 removed pointer to QStringList in QHash, causing memory loss
aba3d2f csoler Wed, 20 Apr 2016 18:24:02 -0400 removed memory leak due to zeroing (on purpose!) a data chunk in GRouter before deleting it
d017771 csoler Wed, 20 Apr 2016 18:08:26 -0400 fixed missing sendTime in distant chat, causing inconsistent display in GUI
80a9fec csoler Tue, 19 Apr 2016 22:18:25 -0400 Merge pull request #353 from crhode/master
39553a6 csoler Tue, 19 Apr 2016 21:58:30 -0400 removed debug info
5645e44 Manuel Davis Tue, 19 Apr 2016 11:32:56 -0500 Change regular expression(s) for identifying hotlinks in feral text.
8be53dd Manuel Davis Tue, 19 Apr 2016 11:11:58 -0500 Improve inserting placemark in ChatLobby.
26af7c9 csoler Sun, 17 Apr 2016 22:58:48 -0400 changed heart beat limit to a larger value. Apparently too tight a value causes disconnections due
c14c240 csoler Sun, 17 Apr 2016 00:51:45 -0400 fixed update of circles GUI using a timer. This is not optimal, and should be replaced by a proper
3000f94 csoler Sat, 16 Apr 2016 22:44:06 -0400 separated subscribe status from wether we are part of a circle or not. Still needs update of GUI
b861aa9 csoler Sat, 16 Apr 2016 17:10:36 -0400 Merge pull request #352 from AsamK/trailing_semicolon
e7ec204 AsamK Sat, 16 Apr 2016 20:40:24 +0200 Add trailing semi-colon to MimeType in .desktop files
fa8a585 csoler Fri, 15 Apr 2016 18:25:53 -0400 removed some debug info
d642934 csoler Fri, 15 Apr 2016 18:25:41 -0400 increased frequency of update for banned PGP nodes
-- Cyril Soler <csoler@users.sourceforge.net> Sun, 24 Apr 2016 12:00:00 -0500
retroshare06 (0.6.0-1.20160415.26574fd9~trusty) trusty; urgency=low
2552b55 defnax Fri, 15 Apr 2016 20:32:00 +0200 Merge branch 'master' of https://github.com/RetroShare/RetroShare 2552b55 defnax Fri, 15 Apr 2016 20:32:00 +0200 Merge branch 'master' of https://github.com/RetroShare/RetroShare
85942f4 defnax Fri, 15 Apr 2016 20:30:32 +0200 improving the create circle layout 85942f4 defnax Fri, 15 Apr 2016 20:30:32 +0200 improving the create circle layout
cb6c2c9 csoler Thu, 14 Apr 2016 23:49:55 -0400 Merge pull request #350 from csoler/v0.6-Circles cb6c2c9 csoler Thu, 14 Apr 2016 23:49:55 -0400 Merge pull request #350 from csoler/v0.6-Circles

View File

@ -15,19 +15,75 @@ INCLUDEPATH += ../../libretroshare/src
unix { unix {
webui_files.path = "$${DATA_DIR}/webui" webui_files.path = "$${DATA_DIR}/webui"
webui_files.files = webui/* webui_files.files = webui/app.js webui/app.css webui/index.html
INSTALLS += webui_files INSTALLS += webui_files
webui_img_files.path = "$${DATA_DIR}/webui/img" webui_img_files.path = "$${DATA_DIR}/webui/img"
webui_img_files.files = ../../retroshare-gui/src/gui/images/logo/logo_splash.png webui_img_files.files = ../../retroshare-gui/src/gui/images/logo/logo_splash.png
INSTALLS += webui_img_files INSTALLS += webui_img_files
create_webfiles.commands = sh $$_PRO_FILE_PWD_/webui-src/make-src/build.sh $$_PRO_FILE_PWD_ #create_webfiles.commands = sh $$_PRO_FILE_PWD_/webui-src/make-src/build.sh $$_PRO_FILE_PWD_
QMAKE_EXTRA_TARGETS += create_webfiles #QMAKE_EXTRA_TARGETS += create_webfiles
PRE_TARGETDEPS += create_webfiles #POST_TARGETDEPS += create_webfiles
# create dummy files #QMAKE_POST_LINK=sh $$_PRO_FILE_PWD_/webui-src/make-src/build.sh $$_PRO_FILE_PWD_
system(webui-src/make-src/init.sh .)
WEBUI_SRC_SCRIPT = webui-src/make-src/build.sh
WEBUI_SRC_HTML = $$WEBUI_SRC_SCRIPT
WEBUI_SRC_HTML += webui-src/app/assets/index.html
WEBUI_SRC_JS = $$WEBUI_SRC_SCRIPT
WEBUI_SRC_JS += webui-src/app/accountselect.js
WEBUI_SRC_JS += webui-src/app/adddownloads.js
WEBUI_SRC_JS += webui-src/app/addidentity.js
WEBUI_SRC_JS += webui-src/app/addpeer.js
WEBUI_SRC_JS += webui-src/app/chat.js
WEBUI_SRC_JS += webui-src/app/createlogin.js
WEBUI_SRC_JS += webui-src/app/downloads.js
WEBUI_SRC_JS += webui-src/app/forums.js
WEBUI_SRC_JS += webui-src/app/home.js
WEBUI_SRC_JS += webui-src/app/identities.js
WEBUI_SRC_JS += webui-src/app/main.js
WEBUI_SRC_JS += webui-src/app/menudef.js
WEBUI_SRC_JS += webui-src/app/menu.js
WEBUI_SRC_JS += webui-src/app/mithril.js
WEBUI_SRC_JS += webui-src/app/mithril.min.js
WEBUI_SRC_JS += webui-src/app/peers.js
WEBUI_SRC_JS += webui-src/app/retroshare.js
WEBUI_SRC_JS += webui-src/app/search.js
WEBUI_SRC_JS += webui-src/app/searchresult.js
WEBUI_SRC_JS += webui-src/app/servicecontrol.js
WEBUI_SRC_JS += webui-src/app/settings.js
WEBUI_SRC_JS += webui-src/app/waiting.js
WEBUI_SRC_CSS = $$WEBUI_SRC_SCRIPT
WEBUI_SRC_CSS += webui-src/app/green-black.scss
WEBUI_SRC_CSS += webui-src/app/_reset.scss
WEBUI_SRC_CSS += webui-src/app/_chat.sass
WEBUI_SRC_CSS += webui-src/app/main.sass
create_webfiles_html.output = webui/index.html
create_webfiles_html.input = WEBUI_SRC_HTML
create_webfiles_html.commands = sh $$_PRO_FILE_PWD_/webui-src/make-src/build.sh $$_PRO_FILE_PWD_ index.html .
create_webfiles_html.variable_out = OBJECTS
create_webfiles_html.CONFIG = combine no_link
create_webfiles_js.output = webui/app.js
create_webfiles_js.input = WEBUI_SRC_JS
create_webfiles_js.commands = sh $$_PRO_FILE_PWD_/webui-src/make-src/build.sh $$_PRO_FILE_PWD_ app.js .
create_webfiles_js.variable_out = OBJECTS
create_webfiles_js.CONFIG = combine no_link
create_webfiles_css.output = webui/app.css
create_webfiles_css.input = WEBUI_SRC_CSS
create_webfiles_css.commands = sh $$_PRO_FILE_PWD_/webui-src/make-src/build.sh $$_PRO_FILE_PWD_ app.css .
create_webfiles_css.variable_out = OBJECTS
create_webfiles_css.CONFIG = combine no_link
QMAKE_EXTRA_COMPILERS += create_webfiles_html create_webfiles_js create_webfiles_css
} }
win32{ win32{
@ -44,9 +100,10 @@ win32{
MAKE_SRC=$$PRO_PATH\\webui-src\\make-src MAKE_SRC=$$PRO_PATH\\webui-src\\make-src
} }
create_webfiles.commands = $$MAKE_SRC\\build.bat $$PRO_PATH #create_webfiles.commands = $$MAKE_SRC\\build.bat $$PRO_PATH
QMAKE_EXTRA_TARGETS += create_webfiles #QMAKE_EXTRA_TARGETS += create_webfiles
PRE_TARGETDEPS += create_webfiles #PRE_TARGETDEPS += create_webfiles
QMAKE_POST_LINK=$$MAKE_SRC\\build.bat $$PRO_PATH
# create dummy files # create dummy files
system($$MAKE_SRC\\init.bat .) system($$MAKE_SRC\\init.bat .)

View File

@ -2,7 +2,7 @@
# create webfiles from sources at compile time (works without npm/node.js) # create webfiles from sources at compile time (works without npm/node.js)
if [ "$1" = "" ];then if [ "$1" = "" ]; then
publicdest=../../webui publicdest=../../webui
src=.. src=..
else else
@ -10,34 +10,53 @@ else
src=$1/webui-src src=$1/webui-src
fi fi
if [ -d "$publicdest" ]; then if [ "$2" = "" ]; then
echo remove existing $publicdest
rm $publicdest -R if [ -d "$publicdest" ]; then
echo remove existing $publicdest
rm $publicdest -R
fi
fi fi
echo mkdir $publicdest if [ ! -d "$publicdest" ]; then
mkdir $publicdest echo mkdir $publicdest
mkdir $publicdest
fi
echo building app.js if [ "$2" = "" ]||[ "$2" = "app.js" ]; then
echo - copy template.js ... echo building app.js
cp $src/make-src/template.js $publicdest/app.js echo - copy template.js ...
cp $src/make-src/template.js $publicdest/app.js
for filename in $src/app/*.js; do for filename in $src/app/*.js; do
fname=$(basename "$filename") fname=$(basename "$filename")
fname="${fname%.*}" fname="${fname%.*}"
echo - adding $fname ... echo - adding $fname ...
echo require.register\(\"$fname\", function\(exports, require, module\) { >> $publicdest/app.js echo require.register\(\"$fname\", function\(exports, require, module\) { >> $publicdest/app.js
cat $filename >> $publicdest/app.js cat $filename >> $publicdest/app.js
echo >> $publicdest/app.js echo >> $publicdest/app.js
echo }\)\; >> $publicdest/app.js echo }\)\; >> $publicdest/app.js
done done
fi
echo building app.css if [ "$2" = "" ]||[ "$2" = "app.css" ]; then
cat $src/app/green-black.scss >> $publicdest/app.css echo building app.css
cat $src/make-src/main.css >> $publicdest/app.css cat $src/app/green-black.scss >> $publicdest/app.css
cat $src/make-src/chat.css >> $publicdest/app.css cat $src/make-src/main.css >> $publicdest/app.css
cat $src/make-src/chat.css >> $publicdest/app.css
fi
echo copy index.html if [ "$2" = "" ]||[ "$2" = "index.html" ]; then
cp $src/app/assets/index.html $publicdest/index.html echo copy index.html
cp $src/app/assets/index.html $publicdest/index.html
fi
if [ "$2" != "" ]&&[ "$3" != "" ]; then
if [ ! -d "$3/webui" ]; then
echo mkdir $3/webui
mkdir $3/webui
fi
echo copy $2 nach $3/webui/$2
cp $publicdest/$2 $3/webui/$2
fi
echo build.sh complete echo build.sh complete

View File

@ -264,9 +264,12 @@ bool DistantChatService::initiateDistantChatConnexion(const RsGxsId& to_gxs_id,
RsChatMsgItem *item = new RsChatMsgItem; RsChatMsgItem *item = new RsChatMsgItem;
item->message = "[Starting distant chat. Please wait for secure tunnel to be established]" ; item->message = "[Starting distant chat. Please wait for secure tunnel to be established]" ;
item->chatFlags = RS_CHAT_FLAG_PRIVATE ; item->chatFlags = RS_CHAT_FLAG_PRIVATE ;
item->sendTime = time(NULL) ;
item->PeerId(RsPeerId(tunnel_id)) ; item->PeerId(RsPeerId(tunnel_id)) ;
handleRecvChatMsgItem(item) ; handleRecvChatMsgItem(item) ;
delete item ; // item is replaced by NULL if partial, but this is not the case here.
return true ; return true ;
} }

View File

@ -63,7 +63,7 @@ public:
// derived in p3ChatService, so as to pass down some info // derived in p3ChatService, so as to pass down some info
virtual void handleIncomingItem(RsItem *) = 0; virtual void handleIncomingItem(RsItem *) = 0;
virtual bool handleRecvChatMsgItem(RsChatMsgItem *ci)=0 ; virtual bool handleRecvChatMsgItem(RsChatMsgItem *& ci)=0 ;
bool handleOutgoingItem(RsChatItem *) ; bool handleOutgoingItem(RsChatItem *) ;
bool handleRecvItem(RsChatItem *) ; bool handleRecvItem(RsChatItem *) ;

View File

@ -424,11 +424,6 @@ void DistributedChatService::checkSizeAndSendLobbyMessage(RsChatItem *msg)
sendChatItem(msg) ; sendChatItem(msg) ;
} }
bool DistributedChatService::locked_checkAndRebuildPartialLobbyMessage(RsChatLobbyMsgItem *ci)
{
return true ;
}
bool DistributedChatService::handleRecvItem(RsChatItem *item) bool DistributedChatService::handleRecvItem(RsChatItem *item)
{ {
switch(item->PacketSubType()) switch(item->PacketSubType())

View File

@ -90,7 +90,6 @@ class DistributedChatService
void addToSaveList(std::list<RsItem*>& list) const ; void addToSaveList(std::list<RsItem*>& list) const ;
bool processLoadListItem(const RsItem *item) ; bool processLoadListItem(const RsItem *item) ;
bool locked_checkAndRebuildPartialLobbyMessage(RsChatLobbyMsgItem *) ;
void checkSizeAndSendLobbyMessage(RsChatItem *) ; void checkSizeAndSendLobbyMessage(RsChatItem *) ;
bool sendLobbyChat(const ChatLobbyId &lobby_id, const std::string&) ; bool sendLobbyChat(const ChatLobbyId &lobby_id, const std::string&) ;

View File

@ -428,7 +428,14 @@ bool p3ChatService::sendChat(ChatId destination, std::string msg)
return true; return true;
} }
bool p3ChatService::locked_checkAndRebuildPartialMessage(RsChatMsgItem *ci) // This method might take control over the memory, or modify it, possibly adding missing parts.
// This function looks weird because it cannot duplicate the message since it does not know
// what type of object it is and the duplicate method of lobby messages is reserved for
// ChatLobby bouncing objects.
//
// Returns false if the item shouldn't be used (and replaced to NULL)
bool p3ChatService::locked_checkAndRebuildPartialMessage(RsChatMsgItem *& ci)
{ {
// Check is the item is ending an incomplete item. // Check is the item is ending an incomplete item.
// //
@ -445,13 +452,16 @@ bool p3ChatService::locked_checkAndRebuildPartialMessage(RsChatMsgItem *ci)
ci->message = it->second->message + ci->message ; ci->message = it->second->message + ci->message ;
ci->chatFlags |= it->second->chatFlags ; ci->chatFlags |= it->second->chatFlags ;
// always remove existing partial. The compound message is in ci now.
delete it->second ; delete it->second ;
_pendingPartialMessages.erase(it) ;
if(!ci_is_incomplete)
_pendingPartialMessages.erase(it) ;
} }
// now decide what to do: if ci is incomplete, store it and replace the pointer with NULL
// if complete, return it.
if(ci_is_incomplete) if(ci_is_incomplete)
{ {
#ifdef CHAT_DEBUG #ifdef CHAT_DEBUG
@ -459,7 +469,8 @@ bool p3ChatService::locked_checkAndRebuildPartialMessage(RsChatMsgItem *ci)
#endif #endif
// The item is a partial message. Push it, and wait for the rest. // The item is a partial message. Push it, and wait for the rest.
// //
_pendingPartialMessages[ci->PeerId()] = ci ; _pendingPartialMessages[ci->PeerId()] = ci ; // cannot use duplicate() here
ci = NULL ; // takes memory ownership over ci
return false ; return false ;
} }
else else
@ -503,8 +514,10 @@ void p3ChatService::handleIncomingItem(RsItem *item)
// //
RsChatMsgItem *ci = dynamic_cast<RsChatMsgItem*>(item) ; RsChatMsgItem *ci = dynamic_cast<RsChatMsgItem*>(item) ;
if(ci != NULL) if(ci != NULL)
{ {
if(! handleRecvChatMsgItem(ci)) handleRecvChatMsgItem(ci);
if(ci)
delete ci ; delete ci ;
return ; // don't delete! It's handled by handleRecvChatMsgItem in some specific cases only. return ; // don't delete! It's handled by handleRecvChatMsgItem in some specific cases only.
@ -665,7 +678,7 @@ bool p3ChatService::checkForMessageSecurity(RsChatMsgItem *ci)
return true ; return true ;
} }
bool p3ChatService::handleRecvChatMsgItem(RsChatMsgItem *ci) bool p3ChatService::handleRecvChatMsgItem(RsChatMsgItem *& ci)
{ {
time_t now = time(NULL); time_t now = time(NULL);
std::string name; std::string name;
@ -674,15 +687,8 @@ bool p3ChatService::handleRecvChatMsgItem(RsChatMsgItem *ci)
{ {
RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/ RsStackMutex stack(mChatMtx); /********** STACK LOCKED MTX ******/
// This crap is because chat lobby messages use a different method for chunking messages using an additional if(!locked_checkAndRebuildPartialMessage(ci)) // we make sure this call does not take control over the memory
// subpacket ID, and a list of lobbies. We cannot just collapse the two because it would make the normal chat return true ; // message is a subpart of an existing message. So everything ok, but we need to return.
// (and chat lobbies) not backward compatible.
if(!DistributedChatService::locked_checkAndRebuildPartialLobbyMessage(dynamic_cast<RsChatLobbyMsgItem*>(ci)))
return true ;
if(!locked_checkAndRebuildPartialMessage(ci))
return true ;
} }
// Check for security. This avoids bombing messages, and so on. // Check for security. This avoids bombing messages, and so on.

View File

@ -205,7 +205,8 @@ private:
void receiveStateString(const RsPeerId& id,const std::string& s) ; void receiveStateString(const RsPeerId& id,const std::string& s) ;
/// methods for handling various Chat items. /// methods for handling various Chat items.
bool handleRecvChatMsgItem(RsChatMsgItem *item) ; // returns false if the item should be deleted. virtual bool handleRecvChatMsgItem(RsChatMsgItem *&item) ; // NULL-ifies the item if memory ownership is taken
void handleRecvChatStatusItem(RsChatStatusItem *item) ; void handleRecvChatStatusItem(RsChatStatusItem *item) ;
void handleRecvChatAvatarItem(RsChatAvatarItem *item) ; void handleRecvChatAvatarItem(RsChatAvatarItem *item) ;
@ -220,7 +221,8 @@ private:
void checkSizeAndSendMessage(RsChatMsgItem *item) ; // keep for compatibility for a few weeks. void checkSizeAndSendMessage(RsChatMsgItem *item) ; // keep for compatibility for a few weeks.
/// Called when a RsChatMsgItem is received. The item may be collapsed with any waiting partial chat item from the same peer. /// Called when a RsChatMsgItem is received. The item may be collapsed with any waiting partial chat item from the same peer.
bool locked_checkAndRebuildPartialMessage(RsChatMsgItem *) ; /// if so, the chat item will be turned to NULL
bool locked_checkAndRebuildPartialMessage(RsChatMsgItem *&) ;
RsChatAvatarItem *makeOwnAvatarItem() ; RsChatAvatarItem *makeOwnAvatarItem() ;
RsChatStatusItem *makeOwnCustomStateStringItem() ; RsChatStatusItem *makeOwnCustomStateStringItem() ;

View File

@ -613,7 +613,6 @@ RsGRouterAbstractMsgItem *GRouterDataInfo::addDataChunk(RsGRouterTransactionChun
{ {
RsItem *data_item = RsGRouterSerialiser().deserialise(incoming_data_buffer->chunk_data,&incoming_data_buffer->chunk_size) ; RsItem *data_item = RsGRouterSerialiser().deserialise(incoming_data_buffer->chunk_data,&incoming_data_buffer->chunk_size) ;
incoming_data_buffer->chunk_data = NULL;
delete incoming_data_buffer; delete incoming_data_buffer;
incoming_data_buffer = NULL ; incoming_data_buffer = NULL ;

View File

@ -225,20 +225,13 @@ private:
void handleLowLevelTransactionAckItem(RsGRouterTransactionAcknItem*) ; void handleLowLevelTransactionAckItem(RsGRouterTransactionAcknItem*) ;
static Sha1CheckSum computeDataItemHash(RsGRouterGenericDataItem *data_item); static Sha1CheckSum computeDataItemHash(RsGRouterGenericDataItem *data_item);
#ifdef __APPLE__
public:
#endif
class nullstream: public std::ostream {};
std::ostream& grouter_debug() const std::ostream& grouter_debug() const
{ {
static nullstream null ; static std::ostream null(0);
return _debug_enabled?(std::cerr):null; return _debug_enabled?(std::cerr):null;
} }
#ifdef __APPLE__
private:
#endif
void routePendingObjects() ; void routePendingObjects() ;
void handleTunnels() ; void handleTunnels() ;
void autoWash() ; void autoWash() ;
@ -364,5 +357,3 @@ private:
uint64_t _random_salt ; uint64_t _random_salt ;
}; };
template<typename T> p3GRouter::nullstream& operator<<(p3GRouter::nullstream& ns,const T&) { return ns ; }

View File

@ -44,13 +44,12 @@ static RsGxsId getRsaKeyFingerprint(RSA *pubkey)
int lenn = BN_num_bytes(pubkey -> n); int lenn = BN_num_bytes(pubkey -> n);
int lene = BN_num_bytes(pubkey -> e); int lene = BN_num_bytes(pubkey -> e);
unsigned char *tmp = new unsigned char[lenn+lene]; RsTemporaryMemory tmp(lenn+lene) ;
BN_bn2bin(pubkey -> n, tmp); BN_bn2bin(pubkey -> n, tmp);
BN_bn2bin(pubkey -> e, &tmp[lenn]); BN_bn2bin(pubkey -> e, &tmp[lenn]);
Sha1CheckSum s = RsDirUtil::sha1sum(tmp,lenn+lene) ; Sha1CheckSum s = RsDirUtil::sha1sum(tmp,lenn+lene) ;
delete[] tmp ;
// Copy first CERTSIGNLEN bytes from the hash of the public modulus and exponent // Copy first CERTSIGNLEN bytes from the hash of the public modulus and exponent
// We should not be using strings here, but a real ID. To be done later. // We should not be using strings here, but a real ID. To be done later.
@ -363,35 +362,39 @@ bool GxsSecurity::validateNxsMsg(const RsNxsMsg& msg, const RsTlvKeySignature& s
RsGxsMessageId msgId = msgMeta.mMsgId, origMsgId = msgMeta.mOrigMsgId; RsGxsMessageId msgId = msgMeta.mMsgId, origMsgId = msgMeta.mOrigMsgId;
msgMeta.mOrigMsgId.clear(); msgMeta.mOrigMsgId.clear();
msgMeta.mMsgId.clear(); msgMeta.mMsgId.clear();
int signOk = 0 ;
uint32_t metaDataLen = msgMeta.serial_size(); {
uint32_t allMsgDataLen = metaDataLen + msg.msg.bin_len; EVP_PKEY *signKey = EVP_PKEY_new();
char* metaData = new char[metaDataLen]; EVP_PKEY_assign_RSA(signKey, rsakey);
char* allMsgData = new char[allMsgDataLen]; // msgData + metaData EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
msgMeta.serialise(metaData, &metaDataLen); uint32_t metaDataLen = msgMeta.serial_size();
uint32_t allMsgDataLen = metaDataLen + msg.msg.bin_len;
// copy msg data and meta in allmsgData buffer RsTemporaryMemory metaData(metaDataLen) ;
memcpy(allMsgData, msg.msg.bin_data, msg.msg.bin_len); RsTemporaryMemory allMsgData(allMsgDataLen) ;
memcpy(allMsgData+(msg.msg.bin_len), metaData, metaDataLen);
delete[] metaData ; if(!metaData || !allMsgData)
return false ;
msgMeta.serialise(metaData, &metaDataLen);
EVP_PKEY *signKey = EVP_PKEY_new(); // copy msg data and meta in allmsgData buffer
EVP_PKEY_assign_RSA(signKey, rsakey); memcpy(allMsgData, msg.msg.bin_data, msg.msg.bin_len);
memcpy(allMsgData+(msg.msg.bin_len), metaData, metaDataLen);
/* calc and check signature */ /* calc and check signature */
EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
EVP_VerifyInit(mdctx, EVP_sha1()); EVP_VerifyInit(mdctx, EVP_sha1());
EVP_VerifyUpdate(mdctx, allMsgData, allMsgDataLen); EVP_VerifyUpdate(mdctx, allMsgData, allMsgDataLen);
int signOk = EVP_VerifyFinal(mdctx, sigbuf, siglen, signKey);
delete[] allMsgData ; signOk = EVP_VerifyFinal(mdctx, sigbuf, siglen, signKey);
/* clean up */ /* clean up */
EVP_PKEY_free(signKey); EVP_PKEY_free(signKey);
EVP_MD_CTX_destroy(mdctx); EVP_MD_CTX_destroy(mdctx);
}
msgMeta.mOrigMsgId = origMsgId; msgMeta.mOrigMsgId = origMsgId;
msgMeta.mMsgId = msgId; msgMeta.mMsgId = msgId;
@ -425,6 +428,8 @@ bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, u
// [--- Encrypted session key length ---|--- Encrypted session key ---|--- IV ---|---- Encrypted data ---] // [--- Encrypted session key length ---|--- Encrypted session key ---|--- IV ---|---- Encrypted data ---]
// //
out = NULL ;
RSA *tmpkey = ::extractPublicKey(key) ; RSA *tmpkey = ::extractPublicKey(key) ;
RSA *rsa_publish_pub = RSAPublicKey_dup(tmpkey) ; RSA *rsa_publish_pub = RSAPublicKey_dup(tmpkey) ;
RSA_free(tmpkey) ; RSA_free(tmpkey) ;
@ -509,7 +514,7 @@ bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, u
// move to end // move to end
out_offset += out_currOffset; out_offset += out_currOffset;
// make sure offset has not gone passed valid memory bounds // make sure offset has not gone passed valid memory bounds
if(out_offset > max_outlen) if(out_offset > max_outlen)
{ {
@ -521,6 +526,8 @@ bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, u
// free encrypted key data // free encrypted key data
free(ek); free(ek);
EVP_CIPHER_CTX_cleanup(&ctx);
outlen = out_offset; outlen = out_offset;
return true; return true;
} }
@ -538,11 +545,12 @@ bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, u
// //
out = NULL ; out = NULL ;
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
std::vector<EVP_PKEY *> public_keys(keys.size(),NULL);
try try
{ {
std::vector<EVP_PKEY *> public_keys(keys.size(),NULL);
for(uint32_t i=0;i<keys.size();++i) for(uint32_t i=0;i<keys.size();++i)
{ {
RSA *tmpkey = ::extractPublicKey(keys[i]) ; RSA *tmpkey = ::extractPublicKey(keys[i]) ;
@ -561,9 +569,7 @@ bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, u
} }
} }
EVP_CIPHER_CTX ctx;
unsigned char iv[EVP_MAX_IV_LENGTH]; unsigned char iv[EVP_MAX_IV_LENGTH];
EVP_CIPHER_CTX_init(&ctx);
std::vector<unsigned char *> ek(keys.size(),NULL) ; std::vector<unsigned char *> ek(keys.size(),NULL) ;
std::vector<int> eklen(keys.size(),0) ; std::vector<int> eklen(keys.size(),0) ;
@ -587,6 +593,11 @@ bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, u
if(!EVP_SealInit(&ctx, EVP_aes_128_cbc(), ek.data(), eklen.data(), iv, public_keys.data(), keys.size())) if(!EVP_SealInit(&ctx, EVP_aes_128_cbc(), ek.data(), eklen.data(), iv, public_keys.data(), keys.size()))
return false; return false;
// now we can release the encryption keys
for(uint32_t i=0;i<public_keys.size();++i)
EVP_PKEY_free(public_keys[i]) ;
public_keys.clear() ;
int total_ek_size = MULTI_ENCRYPTION_FORMAT_v001_ENCRYPTED_KEY_SIZE * keys.size() ; int total_ek_size = MULTI_ENCRYPTION_FORMAT_v001_ENCRYPTED_KEY_SIZE * keys.size() ;
int max_outlen = MULTI_ENCRYPTION_FORMAT_v001_HEADER_SIZE + MULTI_ENCRYPTION_FORMAT_v001_NUMBER_OF_KEYS_SIZE + total_ek_size + EVP_MAX_IV_LENGTH + (inlen + cipher_block_size) ; int max_outlen = MULTI_ENCRYPTION_FORMAT_v001_HEADER_SIZE + MULTI_ENCRYPTION_FORMAT_v001_NUMBER_OF_KEYS_SIZE + total_ek_size + EVP_MAX_IV_LENGTH + (inlen + cipher_block_size) ;
@ -653,15 +664,23 @@ bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, u
if(ek[i]) free(ek[i]); if(ek[i]) free(ek[i]);
outlen = out_offset; outlen = out_offset;
EVP_CIPHER_CTX_cleanup(&ctx);
return true; return true;
} }
catch(std::exception& e) catch(std::exception& e)
{ {
std::cerr << "(EE) Exception caught while encrypting: " << e.what() << std::endl; std::cerr << "(EE) Exception caught while encrypting: " << e.what() << std::endl;
EVP_CIPHER_CTX_cleanup(&ctx);
if(out) free(out) ; if(out) free(out) ;
out = NULL ; out = NULL ;
for(uint32_t i=0;i<public_keys.size();++i)
EVP_PKEY_free(public_keys[i]) ;
public_keys.clear() ;
return false ; return false ;
} }
} }
@ -675,6 +694,7 @@ bool GxsSecurity::decrypt(uint8_t *& out, uint32_t & outlen, const uint8_t *in,
// //
// This method can be used to decrypt multi-encrypted data, if passing he correct encrypted key block (corresponding to the given key) // This method can be used to decrypt multi-encrypted data, if passing he correct encrypted key block (corresponding to the given key)
out = NULL ;
#ifdef GXS_SECURITY_DEBUG #ifdef GXS_SECURITY_DEBUG
std::cerr << "GxsSecurity::decrypt() " << std::endl; std::cerr << "GxsSecurity::decrypt() " << std::endl;
#endif #endif
@ -767,6 +787,7 @@ bool GxsSecurity::decrypt(uint8_t *& out, uint32_t & outlen, const uint8_t *in,
outlen += out_currOffset; outlen += out_currOffset;
free(ek); free(ek);
EVP_CIPHER_CTX_cleanup(&ctx);
return true; return true;
} }
@ -783,9 +804,13 @@ bool GxsSecurity::decrypt(uint8_t *& out, uint32_t & outlen, const uint8_t *in,
#ifdef DISTRIB_DEBUG #ifdef DISTRIB_DEBUG
std::cerr << "GxsSecurity::decrypt() " << std::endl; std::cerr << "GxsSecurity::decrypt() " << std::endl;
#endif #endif
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
try try
{ {
out = NULL ;
// check that the input block has a valid format. // check that the input block has a valid format.
uint32_t offset = 0 ; uint32_t offset = 0 ;
@ -826,8 +851,6 @@ bool GxsSecurity::decrypt(uint8_t *& out, uint32_t & outlen, const uint8_t *in,
// decrypt // decrypt
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
bool succeed = false; bool succeed = false;
for(uint32_t j=0;j<keys.size() && !succeed;++j) for(uint32_t j=0;j<keys.size() && !succeed;++j)
@ -855,6 +878,9 @@ bool GxsSecurity::decrypt(uint8_t *& out, uint32_t & outlen, const uint8_t *in,
{ {
succeed = EVP_OpenInit(&ctx, EVP_aes_128_cbc(),in + encrypted_keys_offset + i*MULTI_ENCRYPTION_FORMAT_v001_ENCRYPTED_KEY_SIZE , MULTI_ENCRYPTION_FORMAT_v001_ENCRYPTED_KEY_SIZE, in+IV_offset, privateKey); succeed = EVP_OpenInit(&ctx, EVP_aes_128_cbc(),in + encrypted_keys_offset + i*MULTI_ENCRYPTION_FORMAT_v001_ENCRYPTED_KEY_SIZE , MULTI_ENCRYPTION_FORMAT_v001_ENCRYPTED_KEY_SIZE, in+IV_offset, privateKey);
if(!succeed)
EVP_CIPHER_CTX_cleanup(&ctx);
#ifdef GXS_SECURITY_DEBUG #ifdef GXS_SECURITY_DEBUG
std::cerr << " encrypted key at offset " << encrypted_keys_offset + i*MULTI_ENCRYPTION_FORMAT_v001_ENCRYPTED_KEY_SIZE << ": " << succeed << std::endl; std::cerr << " encrypted key at offset " << encrypted_keys_offset + i*MULTI_ENCRYPTION_FORMAT_v001_ENCRYPTED_KEY_SIZE << ": " << succeed << std::endl;
#endif #endif
@ -890,6 +916,7 @@ bool GxsSecurity::decrypt(uint8_t *& out, uint32_t & outlen, const uint8_t *in,
#ifdef GXS_SECURITY_DEBUG #ifdef GXS_SECURITY_DEBUG
std::cerr << " successfully decrypted block of size " << outlen << std::endl; std::cerr << " successfully decrypted block of size " << outlen << std::endl;
#endif #endif
EVP_CIPHER_CTX_cleanup(&ctx);
return true; return true;
} }
catch(std::exception& e) catch(std::exception& e)
@ -905,6 +932,7 @@ bool GxsSecurity::decrypt(uint8_t *& out, uint32_t & outlen, const uint8_t *in,
out = NULL ; out = NULL ;
} }
EVP_CIPHER_CTX_cleanup(&ctx);
return false; return false;
} }
} }

View File

@ -61,7 +61,7 @@ static const uint32_t INDEX_AUTHEN_ADMIN = 0x00000040; // admin key
#define GXS_MASK "GXS_MASK_HACK" #define GXS_MASK "GXS_MASK_HACK"
#define GEN_EXCH_DEBUG 1 //#define GEN_EXCH_DEBUG 1
#define MSG_CLEANUP_PERIOD 60*5 // 5 minutes #define MSG_CLEANUP_PERIOD 60*5 // 5 minutes
#define INTEGRITY_CHECK_PERIOD 60*30 // 30 minutes #define INTEGRITY_CHECK_PERIOD 60*30 // 30 minutes

View File

@ -1626,8 +1626,10 @@ void RsGxsNetService::recvNxsItemQueue()
GXSNETDEBUG_P_(item->PeerId()) << " decrypted item " << std::endl; GXSNETDEBUG_P_(item->PeerId()) << " decrypted item " << std::endl;
#endif #endif
} }
#ifdef NXS_NET_DEBUG_7
else else
std::cerr << "(EE) Could not decrypt incoming encrypted NXS item. Probably a friend subscribed to a circle-restricted group." << std::endl; GXSNETDEBUG_P_(item->PeerId()) << " (EE) Could not decrypt incoming encrypted NXS item. Probably a friend subscribed to a circle-restricted group." << std::endl;
#endif
} }
switch(ni->PacketSubType()) switch(ni->PacketSubType())
@ -1638,7 +1640,8 @@ void RsGxsNetService::recvNxsItemQueue()
case RS_PKT_SUBTYPE_NXS_GRP_PUBLISH_KEY_ITEM:handleRecvPublishKeys (dynamic_cast<RsNxsGroupPublishKeyItem*>(ni)) ; break ; case RS_PKT_SUBTYPE_NXS_GRP_PUBLISH_KEY_ITEM:handleRecvPublishKeys (dynamic_cast<RsNxsGroupPublishKeyItem*>(ni)) ; break ;
default: default:
std::cerr << "Unhandled item subtype " << (uint32_t) ni->PacketSubType() << " in RsGxsNetService: " << std::endl; break; if(ni->PacketSubType() != RS_PKT_SUBTYPE_NXS_ENCRYPTED_DATA_ITEM)
std::cerr << "Unhandled item subtype " << (uint32_t) ni->PacketSubType() << " in RsGxsNetService: " << std::endl; break;
} }
delete item ; delete item ;
} }
@ -3861,7 +3864,9 @@ bool RsGxsNetService::decryptSingleNxsItem(const RsNxsEncryptedDataItem *encrypt
if(!GxsSecurity::decrypt(decrypted_mem,decrypted_len, (uint8_t*)encrypted_item->encrypted_data.bin_data,encrypted_item->encrypted_data.bin_len,private_keys)) if(!GxsSecurity::decrypt(decrypted_mem,decrypted_len, (uint8_t*)encrypted_item->encrypted_data.bin_data,encrypted_item->encrypted_data.bin_len,private_keys))
{ {
std::cerr << "Failed! Cannot decrypt this item." << std::endl; #ifdef NXS_NET_DEBUG_7
GXSNETDEBUG_P_(encrypted_item->PeerId()) << " Failed! Cannot decrypt this item." << std::endl;
#endif
decrypted_mem = NULL ; // for safety decrypted_mem = NULL ; // for safety
return false ; return false ;
} }
@ -3876,6 +3881,7 @@ bool RsGxsNetService::decryptSingleNxsItem(const RsNxsEncryptedDataItem *encrypt
if(decrypted_mem!=NULL) if(decrypted_mem!=NULL)
{ {
ditem = RsNxsSerialiser(mServType).deserialise(decrypted_mem,&decrypted_len) ; ditem = RsNxsSerialiser(mServType).deserialise(decrypted_mem,&decrypted_len) ;
free(decrypted_mem) ;
if(ditem != NULL) if(ditem != NULL)
{ {

View File

@ -153,7 +153,7 @@ int pqiperson::tick()
#endif #endif
//if lastHeartbeatReceived is 0, it might be not activated so don't do a net reset. //if lastHeartbeatReceived is 0, it might be not activated so don't do a net reset.
if ( active && time(NULL) > lastHeartbeatReceived + HEARTBEAT_REPEAT_TIME * 5) if ( active && time(NULL) > lastHeartbeatReceived + HEARTBEAT_REPEAT_TIME * 20)
{ {
int ageLastIncoming = time(NULL) - activepqi->getLastIncomingTS(); int ageLastIncoming = time(NULL) - activepqi->getLastIncomingTS();

View File

@ -6,6 +6,8 @@
#include "pqiqos.h" #include "pqiqos.h"
const uint32_t pqiQoS::MAX_PACKET_COUNTER_VALUE = (1 << 24) ;
pqiQoS::pqiQoS(uint32_t nb_levels,float alpha) pqiQoS::pqiQoS(uint32_t nb_levels,float alpha)
: _item_queues(nb_levels),_alpha(alpha) : _item_queues(nb_levels),_alpha(alpha)
{ {
@ -14,6 +16,7 @@ pqiQoS::pqiQoS(uint32_t nb_levels,float alpha)
float c = 1.0f ; float c = 1.0f ;
float inc = alpha ; float inc = alpha ;
_nb_items = 0 ; _nb_items = 0 ;
_id_counter = 0 ;
for(int i=((int)nb_levels)-1;i>=0;--i,c *= alpha) for(int i=((int)nb_levels)-1;i>=0;--i,c *= alpha)
{ {
@ -44,7 +47,7 @@ void pqiQoS::print() const
std::cerr << std::endl; std::cerr << std::endl;
} }
void pqiQoS::in_rsItem(void *ptr,int priority) void pqiQoS::in_rsItem(void *ptr,int size,int priority)
{ {
if(uint32_t(priority) >= _item_queues.size()) if(uint32_t(priority) >= _item_queues.size())
{ {
@ -52,8 +55,11 @@ void pqiQoS::in_rsItem(void *ptr,int priority)
priority = _item_queues.size()-1 ; priority = _item_queues.size()-1 ;
} }
_item_queues[priority].push(ptr) ; _item_queues[priority].push(ptr,size,_id_counter++) ;
++_nb_items ; ++_nb_items ;
if(_id_counter >= MAX_PACKET_COUNTER_VALUE)
_id_counter = 0 ;
} }
// int pqiQoS::gatherStatistics(std::vector<uint32_t>& per_service_count,std::vector<uint32_t>& per_priority_count) const // int pqiQoS::gatherStatistics(std::vector<uint32_t>& per_service_count,std::vector<uint32_t>& per_priority_count) const
@ -80,7 +86,7 @@ void pqiQoS::in_rsItem(void *ptr,int priority)
// } // }
void *pqiQoS::out_rsItem() void *pqiQoS::out_rsItem(uint32_t max_slice_size, uint32_t& size, bool& starts, bool& ends, uint32_t& packet_id)
{ {
// Go through the queues. Increment counters. // Go through the queues. Increment counters.
@ -105,11 +111,21 @@ void *pqiQoS::out_rsItem()
if(last >= 0) if(last >= 0)
{ {
assert(_nb_items > 0) ; assert(_nb_items > 0) ;
--_nb_items ;
return _item_queues[last].pop(); // now chop a slice of this item
void *res = _item_queues[last].slice(max_slice_size,size,starts,ends,packet_id) ;
if(ends)
--_nb_items ;
return res ;
} }
else else
return NULL ; return NULL ;
} }

View File

@ -36,75 +36,148 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <iostream>
#include <vector> #include <vector>
#include <list> #include <list>
#include <util/rsmemory.h>
class pqiQoS class pqiQoS
{ {
public:
pqiQoS(uint32_t max_levels,float alpha) ;
struct ItemRecord
{
void *data ;
uint32_t current_offset ;
uint32_t size ;
uint32_t id ;
};
class ItemQueue
{
public: public:
pqiQoS(uint32_t max_levels,float alpha) ; ItemQueue()
class ItemQueue
{ {
public: _item_count =0 ;
ItemQueue() }
{ void *pop()
_item_count =0 ; {
} if(_items.empty())
void *pop() return NULL ;
{
if(_items.empty())
return NULL ;
void *item = _items.front() ; void *item = _items.front().data ;
_items.pop_front() ; _items.pop_front() ;
--_item_count ; --_item_count ;
return item ; return item ;
} }
void push(void *item) void *slice(uint32_t max_size,uint32_t& size,bool& starts,bool& ends,uint32_t& packet_id)
{ {
_items.push_back(item) ; if(_items.empty())
++_item_count ; return NULL ;
}
uint32_t size() const { return _item_count ; } ItemRecord& rec(_items.front()) ;
packet_id = rec.id ;
float _threshold ; // readily get rid of the item if it can be sent as a whole
float _counter ;
float _inc ;
uint32_t _item_count ;
std::list<void*> _items ;
};
// This function pops items from the queue, y order of priority if(rec.current_offset == 0 && rec.size < max_size)
// {
void *out_rsItem() ; starts = true ;
ends = true ;
size = rec.size ;
// This function is used to queue items. return pop() ;
// }
void in_rsItem(void *item,int priority) ; starts = (rec.current_offset == 0) ;
ends = (rec.current_offset + max_size >= rec.size) ;
void print() const ; if(rec.size <= rec.current_offset)
uint64_t qos_queue_size() const { return _nb_items ; } {
std::cerr << "(EE) severe error in slicing in QoS." << std::endl;
pop() ;
return NULL ;
}
// kills all waiting items. size = std::min(max_size, uint32_t((int)rec.size - (int)rec.current_offset)) ;
void clear() ; void *mem = rs_malloc(size) ;
// get some stats about what's going on. service_packets will contain the number of if(!mem)
// packets per service, and queue_sizes will contain the size of the different priority queues. {
std::cerr << "(EE) memory allocation error in QoS." << std::endl;
pop() ;
return NULL ;
}
//int gatherStatistics(std::vector<uint32_t>& per_service_count,std::vector<uint32_t>& per_priority_count) const ; memcpy(mem,&((unsigned char*)rec.data)[rec.current_offset],size) ;
void computeTotalItemSize() const ; if(ends) // we're taking the whole stuff. So we can delete the entry.
int debug_computeTotalItemSize() const ; {
private: free(rec.data) ;
// This vector stores the lists of items with equal priorities. _items.pop_front() ;
// }
std::vector<ItemQueue> _item_queues ; else
float _alpha ; rec.current_offset += size ; // by construction, !ends implies rec.current_offset < rec.size
uint64_t _nb_items ;
return mem ;
}
void push(void *item,uint32_t size,uint32_t id)
{
ItemRecord rec ;
rec.data = item ;
rec.current_offset = 0 ;
rec.size = size ;
rec.id = id ;
_items.push_back(rec) ;
}
uint32_t size() const { return _item_count ; }
float _threshold ;
float _counter ;
float _inc ;
uint32_t _item_count ;
std::list<ItemRecord> _items ;
};
// This function pops items from the queue, y order of priority
//
void *out_rsItem(uint32_t max_slice_size,uint32_t& size,bool& starts,bool& ends,uint32_t& packet_id) ;
// This function is used to queue items.
//
void in_rsItem(void *item, int size, int priority) ;
void print() const ;
uint64_t qos_queue_size() const { return _nb_items ; }
// kills all waiting items.
void clear() ;
// get some stats about what's going on. service_packets will contain the number of
// packets per service, and queue_sizes will contain the size of the different priority queues.
//int gatherStatistics(std::vector<uint32_t>& per_service_count,std::vector<uint32_t>& per_priority_count) const ;
void computeTotalItemSize() const ;
int debug_computeTotalItemSize() const ;
private:
// This vector stores the lists of items with equal priorities.
//
std::vector<ItemQueue> _item_queues ;
float _alpha ;
uint64_t _nb_items ;
uint32_t _id_counter ;
static const uint32_t MAX_PACKET_COUNTER_VALUE ;
}; };

View File

@ -50,12 +50,12 @@ int pqiQoSstreamer::getQueueSize(bool in)
// return pqiQoS::gatherStatistics(per_service_count,per_priority_count) ; // return pqiQoS::gatherStatistics(per_service_count,per_priority_count) ;
//} //}
void pqiQoSstreamer::locked_storeInOutputQueue(void *ptr,int priority) void pqiQoSstreamer::locked_storeInOutputQueue(void *ptr,int size,int priority)
{ {
_total_item_size += getRsItemSize(ptr) ; _total_item_size += size ;
++_total_item_count ; ++_total_item_count ;
pqiQoS::in_rsItem(ptr,priority) ; pqiQoS::in_rsItem(ptr,size,priority) ;
} }
void pqiQoSstreamer::locked_clear_out_queue() void pqiQoSstreamer::locked_clear_out_queue()
@ -65,14 +65,16 @@ void pqiQoSstreamer::locked_clear_out_queue()
_total_item_count = 0 ; _total_item_count = 0 ;
} }
void *pqiQoSstreamer::locked_pop_out_data() void *pqiQoSstreamer::locked_pop_out_data(uint32_t max_slice_size, uint32_t& size, bool& starts, bool& ends, uint32_t& packet_id)
{ {
void *out = pqiQoS::out_rsItem() ; void *out = pqiQoS::out_rsItem(max_slice_size,size,starts,ends,packet_id) ;
if(out != NULL) if(out != NULL)
{ {
_total_item_size -= getRsItemSize(out) ; _total_item_size -= getRsItemSize(out) ;
--_total_item_count ;
if(ends)
--_total_item_count ;
} }
return out ; return out ;

View File

@ -36,11 +36,11 @@ class pqiQoSstreamer: public pqithreadstreamer, public pqiQoS
static const uint32_t PQI_QOS_STREAMER_MAX_LEVELS = 10 ; static const uint32_t PQI_QOS_STREAMER_MAX_LEVELS = 10 ;
static const float PQI_QOS_STREAMER_ALPHA ; static const float PQI_QOS_STREAMER_ALPHA ;
virtual void locked_storeInOutputQueue(void *ptr,int priority) ; virtual void locked_storeInOutputQueue(void *ptr, int size, int priority) ;
virtual int locked_out_queue_size() const { return _total_item_count ; } virtual int locked_out_queue_size() const { return _total_item_count ; }
virtual void locked_clear_out_queue() ; virtual void locked_clear_out_queue() ;
virtual int locked_compute_out_pkt_size() const { return _total_item_size ; } virtual int locked_compute_out_pkt_size() const { return _total_item_size ; }
virtual void *locked_pop_out_data() ; virtual void *locked_pop_out_data(uint32_t max_slice_size,uint32_t& size,bool& starts,bool& ends,uint32_t& packet_id);
//virtual int locked_gatherStatistics(std::vector<uint32_t>& per_service_count,std::vector<uint32_t>& per_priority_count) const; // extracting data. //virtual int locked_gatherStatistics(std::vector<uint32_t>& per_service_count,std::vector<uint32_t>& per_priority_count) const; // extracting data.

View File

@ -1074,6 +1074,12 @@ int pqissl::Initiate_SSL_Connection()
"pqissl::Initiate_SSL_Connection() SSL Connection Okay"); "pqissl::Initiate_SSL_Connection() SSL Connection Okay");
#endif #endif
if(ssl_connection != NULL)
{
SSL_shutdown(ssl_connection);
SSL_free(ssl_connection) ;
}
ssl_connection = ssl; ssl_connection = ssl;
net_internal_SSL_set_fd(ssl, sockfd); net_internal_SSL_set_fd(ssl, sockfd);
@ -1851,7 +1857,11 @@ bool pqissl::moretoread(uint32_t usec)
#endif #endif
return 1; return 1;
} }
else else if(SSL_pending(ssl_connection) > 0)
{
return 1 ;
}
else
{ {
#ifdef PQISSL_DEBUG #ifdef PQISSL_DEBUG
rslog(RSL_DEBUG_ALL, pqisslzone, rslog(RSL_DEBUG_ALL, pqisslzone,

View File

@ -30,6 +30,7 @@
#include "util/rsdebug.h" #include "util/rsdebug.h"
#include "util/rsstring.h" #include "util/rsstring.h"
#include "util/rsprint.h" #include "util/rsprint.h"
#include "util/rsscopetimer.h"
#include "pqi/pqistreamer.h" #include "pqi/pqistreamer.h"
#include "rsserver/p3face.h" #include "rsserver/p3face.h"
@ -38,15 +39,29 @@
const int pqistreamerzone = 8221; const int pqistreamerzone = 8221;
static const int PQISTREAM_ABS_MAX = 100000000; /* 100 MB/sec (actually per loop) */ static const int PQISTREAM_ABS_MAX = 100000000; /* 100 MB/sec (actually per loop) */
static const int PQISTREAM_AVG_PERIOD = 5; // update speed estimate every 5 seconds static const int PQISTREAM_AVG_PERIOD = 5; // update speed estimate every 5 seconds
static const float PQISTREAM_AVG_FRAC = 0.8; // for bandpass filter over speed estimate. static const float PQISTREAM_AVG_FRAC = 0.8; // for bandpass filter over speed estimate.
static const int PQISTREAM_OPTIMAL_PACKET_SIZE = 512; // It is believed that this value should be lower than TCP slices and large enough as compare to encryption padding.
// most importantly, it should be constant, so as to allow correct QoS.
static const int PQISTREAM_SLICE_FLAG_STARTS = 0x01; //
static const int PQISTREAM_SLICE_FLAG_ENDS = 0x02; // these flags should be kept in the range 0x01-0x08
static const int PQISTREAM_SLICE_PROTOCOL_VERSION_ID_01 = 0x10; // Protocol version ID. Should hold on the 4 lower bits.
static const int PQISTREAM_PARTIAL_PACKET_HEADER_SIZE = 8; // Same size than normal header, to make the code simpler.
static const int PQISTREAM_PACKET_SLICING_PROBE_DELAY = 60; // send every 60 secs.
// This is a probe packet, that won't deserialise (it's empty) but will not cause problems to old peers either, since they will ignore
// it. This packet however will be understood by new peers as a signal to enable packet slicing. This should go when all peers use the
// same protocol.
static uint8_t PACKET_SLICING_PROBE_BYTES[8] = { 0x02, 0xaa, 0xbb, 0xcc, 0x00, 0x00, 0x00, 0x08 } ;
/* This removes the print statements (which hammer pqidebug) */ /* This removes the print statements (which hammer pqidebug) */
/*** /***
#define RSITEM_DEBUG 1 #define RSITEM_DEBUG 1
#define DEBUG_TRANSFERS 1 #define DEBUG_TRANSFERS 1
#define DEBUG_PQISTREAMER 1 #define DEBUG_PQISTREAMER 1
#define DEBUG_PACKET_SLICING 1
***/ ***/
#ifdef DEBUG_TRANSFERS #ifdef DEBUG_TRANSFERS
@ -64,6 +79,9 @@ pqistreamer::pqistreamer(RsSerialiser *rss, const RsPeerId& id, BinInterface *bi
{ {
RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/
mAcceptsPacketSlicing = false ; // by default. Will be turned into true when everyone's ready.
mLastSentPacketSlicingProbe = 0 ;
mAvgLastUpdate = mCurrReadTS = mCurrSentTS = time(NULL); mAvgLastUpdate = mCurrReadTS = mCurrSentTS = time(NULL);
mIncomingSize = 0 ; mIncomingSize = 0 ;
@ -95,7 +113,9 @@ pqistreamer::pqistreamer(RsSerialiser *rss, const RsPeerId& id, BinInterface *bi
pqistreamer::~pqistreamer() pqistreamer::~pqistreamer()
{ {
RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/ RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/
#ifdef DEBUG_PQISTREAMER
std::cerr << "Closing pqistreamer." << std::endl;
#endif
pqioutput(PQL_DEBUG_ALL, pqistreamerzone, "pqistreamer::~pqistreamer() Destruction!"); pqioutput(PQL_DEBUG_ALL, pqistreamerzone, "pqistreamer::~pqistreamer() Destruction!");
if (mBio_flags & BIN_FLAGS_NO_CLOSE) if (mBio_flags & BIN_FLAGS_NO_CLOSE)
@ -185,8 +205,8 @@ void pqistreamer::updateRates()
{ {
int64_t diff = int64_t(t) - int64_t(mAvgLastUpdate) ; int64_t diff = int64_t(t) - int64_t(mAvgLastUpdate) ;
float avgReadpSec = getRate(true) * PQISTREAM_AVG_FRAC + (1.0 - PQISTREAM_AVG_FRAC) * mAvgReadCount/(1000.0 * float(diff)); float avgReadpSec = getRate(true ) * PQISTREAM_AVG_FRAC + (1.0 - PQISTREAM_AVG_FRAC) * mAvgReadCount/(1000.0 * float(diff));
float avgSentpSec = getRate(false) * PQISTREAM_AVG_FRAC + (1.0 - PQISTREAM_AVG_FRAC) * mAvgSentCount/(1000.0 * float(diff)); float avgSentpSec = getRate(false) * PQISTREAM_AVG_FRAC + (1.0 - PQISTREAM_AVG_FRAC) * mAvgSentCount/(1000.0 * float(diff));
#ifdef DEBUG_PQISTREAMER #ifdef DEBUG_PQISTREAMER
std::cerr << "Peer " << PeerId() << ": Current speed estimates: " << avgReadpSec << " / " << avgSentpSec << std::endl; std::cerr << "Peer " << PeerId() << ": Current speed estimates: " << avgReadpSec << " / " << avgSentpSec << std::endl;
@ -256,6 +276,7 @@ int pqistreamer::tick_send(uint32_t timeout)
{ {
handleoutgoing_locked(); handleoutgoing_locked();
} }
return 1; return 1;
} }
@ -278,7 +299,7 @@ int pqistreamer::status()
return 0; return 0;
} }
void pqistreamer::locked_storeInOutputQueue(void *ptr,int) void pqistreamer::locked_storeInOutputQueue(void *ptr,int,int)
{ {
mOutPkts.push_back(ptr); mOutPkts.push_back(ptr);
} }
@ -316,7 +337,7 @@ int pqistreamer::queue_outpqi_locked(RsItem *pqi,uint32_t& pktsize)
if (mRsSerialiser->serialise(pqi, ptr, &pktsize)) if (mRsSerialiser->serialise(pqi, ptr, &pktsize))
{ {
locked_storeInOutputQueue(ptr,pqi->priority_level()) ; locked_storeInOutputQueue(ptr,pktsize,pqi->priority_level()) ;
if (!(mBio_flags & BIN_FLAGS_NO_DELETE)) if (!(mBio_flags & BIN_FLAGS_NO_DELETE))
{ {
@ -399,6 +420,33 @@ time_t pqistreamer::getLastIncomingTS()
return mLastIncomingTs; return mLastIncomingTs;
} }
// Packet slicing:
//
// Old : 02 0014 03 00000026 [data, 26 bytes] => [version 1B] [service 2B][subpacket 1B] [size 4B]
// New2: pp ff xxxxxxxx ssss [data, sss bytes] => [protocol version 1B] [flags 1B] [2^32 packet count] [2^16 size]
//
// Encode protocol on 1.0 Bytes ( 8 bits)
// Encode flags on 1.0 Bytes ( 8 bits)
// 0x01 => incomplete packet continued after
// 0x02 => packet ending a previously incomplete packet
//
// Encode packet ID on 4.0 Bytes (32 bits) => packet counter = [0...2^32]
// Encode size on 2.0 Bytes (16 bits) => 65536 // max slice size = 65536
//
// Backward compatibility:
// * send one packet with service + subpacket = aabbcc. Old peers will silently ignore such packets. Full packet header is: 02aabbcc 00000008
// * if received, mark the peer as able to decode the new packet type
// In pqiQoS:
// - limit packet grouping to max size 512.
// - new peers need to read flux, and properly extract partial sizes, and combine packets based on packet counter.
// - on sending, RS grabs slices of max size 1024 from pqiQoS. If smaller, possibly pack them together.
// pqiQoS keeps track of sliced packets and makes sure the output is consistent:
// * when a large packet needs to be send, only takes a slice and return it, and update the remaining part
// * always consider priority when taking new slices => a newly arrived fast packet will always get through.
//
// Max slice size should be customisable, depending on bandwidth. To be tested...
//
int pqistreamer::handleoutgoing_locked() int pqistreamer::handleoutgoing_locked()
{ {
#ifdef DEBUG_PQISTREAMER #ifdef DEBUG_PQISTREAMER
@ -417,6 +465,10 @@ int pqistreamer::handleoutgoing_locked()
{ {
/* if we are not active - clear anything in the queues. */ /* if we are not active - clear anything in the queues. */
locked_clear_out_queue() ; locked_clear_out_queue() ;
#ifdef DEBUG_PACKET_SLICING
std::cerr << "(II) Switching off packet slicing." << std::endl;
#endif
mAcceptsPacketSlicing = false ;
/* also remove the pending packets */ /* also remove the pending packets */
if (mPkt_wpending) if (mPkt_wpending)
@ -440,62 +492,116 @@ int pqistreamer::handleoutgoing_locked()
if ((!(mBio->cansend(0))) || (maxbytes < sentbytes)) if ((!(mBio->cansend(0))) || (maxbytes < sentbytes))
{ {
#ifdef DEBUG_TRANSFERS #ifdef DEBUG_PACKET_SLICING
if (maxbytes < sentbytes) if (maxbytes < sentbytes)
{ std::cerr << "pqistreamer::handleoutgoing_locked() Stopped sending: bio not ready. maxbytes=" << maxbytes << ", sentbytes=" << sentbytes << std::endl;
std::cerr << "pqistreamer::handleoutgoing_locked() Stopped sending sentbytes > maxbytes. Sent " << sentbytes << " bytes ";
std::cerr << std::endl;
}
else else
{ std::cerr << "pqistreamer::handleoutgoing_locked() Stopped sending: sentbytes=" << sentbytes << ", max=" << maxbytes << std::endl;
std::cerr << "pqistreamer::handleoutgoing_locked() Stopped sending at cansend() is false";
std::cerr << std::endl;
}
#endif #endif
return 0; return 0;
} }
#define GROUP_OUTGOING_PACKETS 1 // send a out_pkt., else send out_data. unless there is a pending packet. The strategy is to
#define PACKET_GROUPING_SIZE_LIMIT 32768 // - grab as many packets as possible while below the optimal packet size, so as to allow some packing and decrease encryption padding overhead (suposeddly)
// send a out_pkt., else send out_data. unless // - limit packets size to OPTIMAL_PACKET_SIZE when sending big packets so as to keep as much QoS as possible.
// there is a pending packet.
if (!mPkt_wpending) if (!mPkt_wpending)
#ifdef GROUP_OUTGOING_PACKETS
{
void *dta;
mPkt_wpending_size = 0 ;
int k=0;
while(mPkt_wpending_size < (uint32_t)maxbytes && mPkt_wpending_size < PACKET_GROUPING_SIZE_LIMIT && (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() ; void *dta;
mPkt_wpending_size = 0 ;
int k=0;
if(dta != NULL) // Checks for inserting a packet slicing probe. We do that to send the other peer the information that packet slicing can be used.
{ // if so, we enable it for the session. This should be removed (because it's unnecessary) when all users have switched to the new version.
mPkt_wpending = dta ; time_t now = time(NULL) ;
mPkt_wpending_size = getRsItemSize(dta);
} if((!mAcceptsPacketSlicing) && now > mLastSentPacketSlicingProbe + PQISTREAM_PACKET_SLICING_PROBE_DELAY)
} {
#ifdef DEBUG_PACKET_SLICING
std::cerr << "(II) Inserting packet slicing probe in traffic" << std::endl;
#endif #endif
mPkt_wpending_size = 8 ;
mPkt_wpending = rs_malloc(8) ;
memcpy(mPkt_wpending,PACKET_SLICING_PROBE_BYTES,8) ;
mLastSentPacketSlicingProbe = now ;
}
uint32_t slice_size=0;
bool slice_starts=true ;
bool slice_ends=true ;
uint32_t slice_packet_id=0 ;
do
{
int desired_packet_size = mAcceptsPacketSlicing?PQISTREAM_OPTIMAL_PACKET_SIZE:(getRsPktMaxSize());
dta = locked_pop_out_data(desired_packet_size,slice_size,slice_starts,slice_ends,slice_packet_id) ;
if(!dta)
break ;
if(slice_starts && slice_ends) // good old method. Send the packet as is, since it's a full packet.
{
#ifdef DEBUG_PACKET_SLICING
std::cerr << "sending full slice, old style. Size=" << slice_size << std::endl;
#endif
mPkt_wpending = realloc(mPkt_wpending,slice_size+mPkt_wpending_size) ;
memcpy( &((char*)mPkt_wpending)[mPkt_wpending_size],dta,slice_size) ;
free(dta);
mPkt_wpending_size += slice_size ;
++k ;
}
else // partial packet. We make a special header for it and insert it in the stream
{
if(slice_size > 0xffff || !mAcceptsPacketSlicing)
{
std::cerr << "(EE) protocol error in pqitreamer: slice size is too large and cannot be encoded." ;
free(mPkt_wpending) ;
mPkt_wpending_size = 0;
return -1 ;
}
#ifdef DEBUG_PACKET_SLICING
std::cerr << "sending partial slice, packet ID=" << std::hex << slice_packet_id << std::dec << ", size=" << slice_size << std::endl;
#endif
mPkt_wpending = realloc(mPkt_wpending,slice_size+mPkt_wpending_size+PQISTREAM_PARTIAL_PACKET_HEADER_SIZE) ;
memcpy( &((char*)mPkt_wpending)[mPkt_wpending_size+PQISTREAM_PARTIAL_PACKET_HEADER_SIZE],dta,slice_size) ;
free(dta);
// New2: pp ff xxxxxxxx ssss [data, sss bytes] => [flags 1B] [protocol version 1B] [2^32 packet count] [2^16 size]
uint8_t partial_flags = 0 ;
if(slice_starts) partial_flags |= PQISTREAM_SLICE_FLAG_STARTS ;
if(slice_ends ) partial_flags |= PQISTREAM_SLICE_FLAG_ENDS ;
((char*)mPkt_wpending)[mPkt_wpending_size+0x00] = PQISTREAM_SLICE_PROTOCOL_VERSION_ID_01 ;
((char*)mPkt_wpending)[mPkt_wpending_size+0x01] = partial_flags ;
((char*)mPkt_wpending)[mPkt_wpending_size+0x02] = uint8_t(slice_packet_id >> 24) & 0xff ;
((char*)mPkt_wpending)[mPkt_wpending_size+0x03] = uint8_t(slice_packet_id >> 16) & 0xff ;
((char*)mPkt_wpending)[mPkt_wpending_size+0x04] = uint8_t(slice_packet_id >> 8) & 0xff ;
((char*)mPkt_wpending)[mPkt_wpending_size+0x05] = uint8_t(slice_packet_id >> 0) & 0xff ;
((char*)mPkt_wpending)[mPkt_wpending_size+0x06] = uint8_t(slice_size >> 8) & 0xff ;
((char*)mPkt_wpending)[mPkt_wpending_size+0x07] = uint8_t(slice_size >> 0) & 0xff ;
mPkt_wpending_size += slice_size + PQISTREAM_PARTIAL_PACKET_HEADER_SIZE;
++k ;
}
}
while(mPkt_wpending_size < (uint32_t)maxbytes && mPkt_wpending_size < PQISTREAM_OPTIMAL_PACKET_SIZE ) ;
#ifdef DEBUG_PQISTREAMER
if(k > 1)
std::cerr << "Packed " << k << " packets into " << mPkt_wpending_size << " bytes." << std::endl;
#endif
}
if (mPkt_wpending) if (mPkt_wpending)
{ {
// write packet. // write packet.
#ifdef DEBUG_PQISTREAMER #ifdef DEBUG_PQISTREAMER
std::cout << "Sending Out Pkt of size " << mPkt_wpending_size << " !" << std::endl; std::cout << "Sending Out Pkt of size " << mPkt_wpending_size << " !" << std::endl;
#endif #endif
int ss=0; int ss=0;
@ -507,12 +613,19 @@ int pqistreamer::handleoutgoing_locked()
// std::cerr << out << std::endl ; // std::cerr << out << std::endl ;
pqioutput(PQL_DEBUG_BASIC, pqistreamerzone, out); pqioutput(PQL_DEBUG_BASIC, pqistreamerzone, out);
#endif #endif
std::cerr << PeerId() << ": sending failed. Only " << ss << " bytes sent over " << mPkt_wpending_size << std::endl;
// pkt_wpending will kept til next time. // pkt_wpending will kept til next time.
// ensuring exactly the same data is written (openSSL requirement). // ensuring exactly the same data is written (openSSL requirement).
return -1; return -1;
} }
#ifdef DEBUG_PQISTREAMER
else
std::cerr << PeerId() << ": sent " << ss << " bytes " << std::endl;
#endif
++nsent; ++nsent;
outSentBytes_locked(mPkt_wpending_size); // this is the only time where we know exactly what was sent. outSentBytes_locked(mPkt_wpending_size); // this is the only time where we know exactly what was sent.
#ifdef DEBUG_TRANSFERS #ifdef DEBUG_TRANSFERS
@ -541,309 +654,405 @@ int pqistreamer::handleoutgoing_locked()
*/ */
int pqistreamer::handleincoming_locked() int pqistreamer::handleincoming_locked()
{ {
int readbytes = 0; int readbytes = 0;
static const int max_failed_read_attempts = 2000 ; static const int max_failed_read_attempts = 2000 ;
#ifdef DEBUG_PQISTREAMER #ifdef DEBUG_PQISTREAMER
pqioutput(PQL_DEBUG_ALL, pqistreamerzone, "pqistreamer::handleincoming_locked()"); pqioutput(PQL_DEBUG_ALL, pqistreamerzone, "pqistreamer::handleincoming_locked()");
#endif #endif
if(!(mBio->isactive())) if(!(mBio->isactive()))
{ {
mReading_state = reading_state_initial ; mReading_state = reading_state_initial ;
free_rpend_locked(); free_rpend_locked();
return 0; return 0;
} }
else else
allocate_rpend_locked(); allocate_rpend_locked();
// enough space to read any packet. // enough space to read any packet.
int maxlen = mPkt_rpend_size; int maxlen = mPkt_rpend_size;
void *block = mPkt_rpending; void *block = mPkt_rpending;
// initial read size: basic packet. // initial read size: basic packet.
int blen = getRsPktBaseSize(); int blen = getRsPktBaseSize(); // this is valid for both packet slices and normal un-sliced packets (same header size)
int maxin = inAllowedBytes_locked(); int maxin = inAllowedBytes_locked();
#ifdef DEBUG_PQISTREAMER #ifdef DEBUG_PQISTREAMER
std::cerr << "[" << (void*)pthread_self() << "] " << "reading state = " << mReading_state << std::endl ; std::cerr << "[" << (void*)pthread_self() << "] " << "reading state = " << mReading_state << std::endl ;
#endif #endif
switch(mReading_state) switch(mReading_state)
{ {
case reading_state_initial: /*std::cerr << "jumping to start" << std::endl; */ goto start_packet_read ; case reading_state_initial: /*std::cerr << "jumping to start" << std::endl; */ goto start_packet_read ;
case reading_state_packet_started: /*std::cerr << "jumping to middle" << std::endl;*/ goto continue_packet ; case reading_state_packet_started: /*std::cerr << "jumping to middle" << std::endl;*/ goto continue_packet ;
} }
start_packet_read: start_packet_read:
{ // scope to ensure variable visibility { // scope to ensure variable visibility
// read the basic block (minimum packet size) // read the basic block (minimum packet size)
int tmplen; int tmplen;
#ifdef DEBUG_PQISTREAMER #ifdef DEBUG_PQISTREAMER
std::cerr << "[" << (void*)pthread_self() << "] " << "starting packet" << std::endl ; std::cerr << "[" << (void*)pthread_self() << "] " << "starting packet" << std::endl ;
#endif #endif
memset(block,0,blen) ; // reset the block, to avoid uninitialized memory reads. memset(block,0,blen) ; // reset the block, to avoid uninitialized memory reads.
if (blen != (tmplen = mBio->readdata(block, blen))) if (blen != (tmplen = mBio->readdata(block, blen)))
{ {
pqioutput(PQL_DEBUG_BASIC, pqistreamerzone, "pqistreamer::handleincoming() Didn't read BasePkt!"); pqioutput(PQL_DEBUG_BASIC, pqistreamerzone, "pqistreamer::handleincoming() Didn't read BasePkt!");
// error.... (either blocked or failure) // error.... (either blocked or failure)
if (tmplen == 0) if (tmplen == 0)
{ {
#ifdef DEBUG_PQISTREAMER #ifdef DEBUG_PQISTREAMER
// most likely blocked! // most likely blocked!
pqioutput(PQL_DEBUG_BASIC, pqistreamerzone, "pqistreamer::handleincoming() read blocked"); pqioutput(PQL_DEBUG_BASIC, pqistreamerzone, "pqistreamer::handleincoming() read blocked");
std::cerr << "[" << (void*)pthread_self() << "] " << "given up 1" << std::endl ; std::cerr << "[" << (void*)pthread_self() << "] " << "given up 1" << std::endl ;
#endif #endif
return 0; return 0;
} }
else if (tmplen < 0) else if (tmplen < 0)
{ {
// Most likely it is that the packet is pending but could not be read by pqissl because of stream flow. // Most likely it is that the packet is pending but could not be read by pqissl because of stream flow.
// So we return without an error, and leave the machine state in 'start_read'. // So we return without an error, and leave the machine state in 'start_read'.
// //
//pqioutput(PQL_WARNING, pqistreamerzone, "pqistreamer::handleincoming() Error in bio read"); //pqioutput(PQL_WARNING, pqistreamerzone, "pqistreamer::handleincoming() Error in bio read");
#ifdef DEBUG_PQISTREAMER #ifdef DEBUG_PQISTREAMER
std::cerr << "[" << (void*)pthread_self() << "] " << "given up 2, state = " << mReading_state << std::endl ; std::cerr << "[" << (void*)pthread_self() << "] " << "given up 2, state = " << mReading_state << std::endl ;
#endif #endif
return 0; return 0;
} }
else // tmplen > 0 else // tmplen > 0
{ {
// strange case....This should never happen as partial reads are handled by pqissl below. // strange case....This should never happen as partial reads are handled by pqissl below.
#ifdef DEBUG_PQISTREAMER #ifdef DEBUG_PQISTREAMER
std::string out = "pqistreamer::handleincoming() Incomplete "; std::string out = "pqistreamer::handleincoming() Incomplete ";
rs_sprintf_append(out, "(Strange) read of %d bytes", tmplen); rs_sprintf_append(out, "(Strange) read of %d bytes", tmplen);
pqioutput(PQL_ALERT, pqistreamerzone, out); pqioutput(PQL_ALERT, pqistreamerzone, out);
std::cerr << "[" << (void*)pthread_self() << "] " << "given up 3" << std::endl ; std::cerr << "[" << (void*)pthread_self() << "] " << "given up 3" << std::endl ;
#endif #endif
return -1; return -1;
} }
} }
#ifdef DEBUG_PQISTREAMER #ifdef DEBUG_PQISTREAMER
std::cerr << "[" << (void*)pthread_self() << "] " << "block 0 : " << (int)(((unsigned char*)block)[0]) << " " << (int)(((unsigned char*)block)[1]) << " " << (int)(((unsigned char*)block)[2]) << " " std::cerr << "[" << (void*)pthread_self() << "] " << "block 0 : " << RsUtil::BinToHex(block,8) << std::endl;
<< (int)(((unsigned char*)block)[3]) << " "
<< (int)(((unsigned char*)block)[4]) << " "
<< (int)(((unsigned char*)block)[5]) << " "
<< (int)(((unsigned char*)block)[6]) << " "
<< (int)(((unsigned char*)block)[7]) << " " << std::endl ;
#endif #endif
readbytes += blen; readbytes += blen;
mReading_state = reading_state_packet_started ; mReading_state = reading_state_packet_started ;
mFailed_read_attempts = 0 ; // reset failed read, as the packet has been totally read. mFailed_read_attempts = 0 ; // reset failed read, as the packet has been totally read.
}
// Check for packet slicing probe (04/26/2016). To be removed when everyone uses it.
if(!memcmp(block,PACKET_SLICING_PROBE_BYTES,8))
{
mAcceptsPacketSlicing = true ;
#ifdef DEBUG_PACKET_SLICING
std::cerr << "(II) Enabling packet slicing!" << std::endl;
#endif
}
}
continue_packet: continue_packet:
{ {
// workout how much more to read. // workout how much more to read.
int extralen = getRsItemSize(block) - blen;
bool is_partial_packet = false ;
bool is_packet_starting = (((char*)block)[1] == PQISTREAM_SLICE_FLAG_STARTS) ; // STARTS and ENDS flags are actually never combined.
bool is_packet_ending = (((char*)block)[1] == PQISTREAM_SLICE_FLAG_ENDS) ;
bool is_packet_middle = (((char*)block)[1] == 0x00) ;
uint32_t extralen =0;
uint32_t slice_packet_id =0;
if( ((char*)block)[0] == PQISTREAM_SLICE_PROTOCOL_VERSION_ID_01 && ( is_packet_starting || is_packet_middle || is_packet_ending))
{
extralen = (uint32_t(((uint8_t*)block)[6]) << 8 ) + (uint32_t(((uint8_t*)block)[7]));
slice_packet_id = (uint32_t(((uint8_t*)block)[2]) << 24) + (uint32_t(((uint8_t*)block)[3]) << 16) + (uint32_t(((uint8_t*)block)[4]) << 8) + (uint32_t(((uint8_t*)block)[5]) << 0);
#ifdef DEBUG_PACKET_SLICING
std::cerr << "Reading partial packet from mem block " << RsUtil::BinToHex((char*)block,8) << ": packet_id=" << std::hex << slice_packet_id << std::dec << ", len=" << extralen << std::endl;
#endif
is_partial_packet = true ;
mAcceptsPacketSlicing = true ; // this is needed
}
else
extralen = getRsItemSize(block) - blen; // old style packet type
#ifdef DEBUG_PQISTREAMER #ifdef DEBUG_PQISTREAMER
std::cerr << "[" << (void*)pthread_self() << "] " << "continuing packet getRsItemSize(block) = " << getRsItemSize(block) << std::endl ; std::cerr << "[" << (void*)pthread_self() << "] " << "continuing packet getRsItemSize(block) = " << getRsItemSize(block) << std::endl ;
std::cerr << "[" << (void*)pthread_self() << "] " << "continuing packet extralen = " << extralen << std::endl ; std::cerr << "[" << (void*)pthread_self() << "] " << "continuing packet extralen = " << extralen << std::endl ;
std::cerr << "[" << (void*)pthread_self() << "] " << "continuing packet state=" << mReading_state << std::endl ; std::cerr << "[" << (void*)pthread_self() << "] " << "continuing packet state=" << mReading_state << std::endl ;
std::cerr << "[" << (void*)pthread_self() << "] " << "block 1 : " << (int)(((unsigned char*)block)[0]) << " " << (int)(((unsigned char*)block)[1]) << " " << (int)(((unsigned char*)block)[2]) << " " << (int)(((unsigned char*)block)[3]) << " " std::cerr << "[" << (void*)pthread_self() << "] " << "block 1 : " << RsUtil::BinToHex(block,8) << std::endl;
<< (int)(((unsigned char*)block)[4]) << " "
<< (int)(((unsigned char*)block)[5]) << " "
<< (int)(((unsigned char*)block)[6]) << " "
<< (int)(((unsigned char*)block)[7]) << " " << std::endl ;
#endif #endif
if (extralen > maxlen - blen) if (extralen > maxlen - blen)
{ {
pqioutput(PQL_ALERT, pqistreamerzone, "ERROR: Read Packet too Big!"); pqioutput(PQL_ALERT, pqistreamerzone, "ERROR: Read Packet too Big!");
p3Notify *notify = RsServer::notify(); p3Notify *notify = RsServer::notify();
if (notify) if (notify)
{ {
std::string title = std::string title =
"Warning: Bad Packet Read"; "Warning: Bad Packet Read";
std::string msg; std::string msg;
msg = " **** WARNING **** \n"; msg = " **** WARNING **** \n";
msg += "Retroshare has caught a BAD Packet Read"; msg += "Retroshare has caught a BAD Packet Read";
msg += "\n"; msg += "\n";
msg += "This is normally caused by connecting to an"; msg += "This is normally caused by connecting to an";
msg += " OLD version of Retroshare"; msg += " OLD version of Retroshare";
msg += "\n"; msg += "\n";
rs_sprintf_append(msg, "(M:%d B:%d E:%d)\n", maxlen, blen, extralen); rs_sprintf_append(msg, "(M:%d B:%d E:%d)\n", maxlen, blen, extralen);
msg += "\n"; msg += "\n";
rs_sprintf_append(msg, "block = %d %d %d %d %d %d %d %d\n", msg += "block = " ;
(int)(((unsigned char*)block)[0]), msg += RsUtil::BinToHex((char*)block,8);
(int)(((unsigned char*)block)[1]),
(int)(((unsigned char*)block)[2]),
(int)(((unsigned char*)block)[3]),
(int)(((unsigned char*)block)[4]),
(int)(((unsigned char*)block)[5]),
(int)(((unsigned char*)block)[6]),
(int)(((unsigned char*)block)[7])) ;
msg += "\n";
msg += "Please get your friends to upgrade to the latest version";
msg += "\n";
msg += "\n";
msg += "If you are sure the error was not caused by an old version";
msg += "\n";
msg += "Please report the problem to Retroshare's developers";
msg += "\n";
notify->AddLogMessage(0, RS_SYS_WARNING, title, msg); msg += "\n";
msg += "Please get your friends to upgrade to the latest version";
msg += "\n";
msg += "\n";
msg += "If you are sure the error was not caused by an old version";
msg += "\n";
msg += "Please report the problem to Retroshare's developers";
msg += "\n";
std::cerr << "pqistreamer::handle_incoming() ERROR: Read Packet too Big" << std::endl; notify->AddLogMessage(0, RS_SYS_WARNING, title, msg);
std::cerr << msg;
std::cerr << std::endl;
} std::cerr << "pqistreamer::handle_incoming() ERROR: Read Packet too Big" << std::endl;
mBio->close(); std::cerr << msg;
mReading_state = reading_state_initial ; // restart at state 1. std::cerr << std::endl;
mFailed_read_attempts = 0 ;
return -1;
// Used to exit now! exit(1); }
} mBio->close();
mReading_state = reading_state_initial ; // restart at state 1.
mFailed_read_attempts = 0 ;
return -1;
if (extralen > 0) // Used to exit now! exit(1);
{ }
void *extradata = (void *) (((char *) block) + blen);
int tmplen ;
// Don't reset the block now! If pqissl is in the middle of a multiple-chunk if (extralen > 0)
// packet (larger than 16384 bytes), and pqistreamer jumped directly yo {
// continue_packet:, then readdata is going to write after the beginning of void *extradata = (void *) (((char *) block) + blen);
// extradata, yet not exactly at start -> the start of the packet would be wiped out. int tmplen ;
//
// so, don't do that:
// memset( extradata,0,extralen ) ;
if (extralen != (tmplen = mBio->readdata(extradata, extralen))) // Don't reset the block now! If pqissl is in the middle of a multiple-chunk
{ // packet (larger than 16384 bytes), and pqistreamer jumped directly yo
// continue_packet:, then readdata is going to write after the beginning of
// extradata, yet not exactly at start -> the start of the packet would be wiped out.
//
// so, don't do that:
// memset( extradata,0,extralen ) ;
if (extralen != (tmplen = mBio->readdata(extradata, extralen)))
{
#ifdef DEBUG_PQISTREAMER #ifdef DEBUG_PQISTREAMER
if(tmplen > 0) if(tmplen > 0)
std::cerr << "[" << (void*)pthread_self() << "] " << "Incomplete packet read ! This is a real problem ;-)" << std::endl ; std::cerr << "[" << (void*)pthread_self() << "] " << "Incomplete packet read ! This is a real problem ;-)" << std::endl ;
#endif #endif
if(++mFailed_read_attempts > max_failed_read_attempts) if(++mFailed_read_attempts > max_failed_read_attempts)
{ {
std::string out; std::string out;
rs_sprintf(out, "Error Completing Read (read %d/%d)", tmplen, extralen); rs_sprintf(out, "Error Completing Read (read %d/%d)", tmplen, extralen);
std::cerr << out << std::endl ; std::cerr << out << std::endl ;
pqioutput(PQL_ALERT, pqistreamerzone, out); pqioutput(PQL_ALERT, pqistreamerzone, out);
p3Notify *notify = RsServer::notify(); p3Notify *notify = RsServer::notify();
if (notify) if (notify)
{ {
std::string title = "Warning: Error Completing Read"; std::string title = "Warning: Error Completing Read";
std::string msgout; std::string msgout;
msgout = " **** WARNING **** \n"; msgout = " **** WARNING **** \n";
msgout += "Retroshare has experienced an unexpected Read ERROR"; msgout += "Retroshare has experienced an unexpected Read ERROR";
msgout += "\n"; msgout += "\n";
rs_sprintf_append(msgout, "(M:%d B:%d E:%d R:%d)\n", maxlen, blen, extralen, tmplen); rs_sprintf_append(msgout, "(M:%d B:%d E:%d R:%d)\n", maxlen, blen, extralen, tmplen);
msgout += "\n"; msgout += "\n";
msgout += "Note: this error might as well happen (rarely) when a peer disconnects in between a transmission of a large packet.\n"; msgout += "Note: this error might as well happen (rarely) when a peer disconnects in between a transmission of a large packet.\n";
msgout += "If it happens manny time, please contact the developers, and send them these numbers:"; msgout += "If it happens manny time, please contact the developers, and send them these numbers:";
msgout += "\n"; msgout += "\n";
rs_sprintf_append(msgout, "block = %d %d %d %d %d %d %d %d\n", msgout += "block = " ;
(int)(((unsigned char*)block)[0]), msgout += RsUtil::BinToHex((char*)block,8) + "\n" ;
(int)(((unsigned char*)block)[1]),
(int)(((unsigned char*)block)[2]),
(int)(((unsigned char*)block)[3]),
(int)(((unsigned char*)block)[4]),
(int)(((unsigned char*)block)[5]),
(int)(((unsigned char*)block)[6]),
(int)(((unsigned char*)block)[7]));
//notify->AddSysMessage(0, RS_SYS_WARNING, title, msgout.str()); std::cerr << msgout << std::endl;
}
std::cerr << msgout << std::endl; mBio->close();
} mReading_state = reading_state_initial ; // restart at state 1.
mFailed_read_attempts = 0 ;
mBio->close(); return -1;
mReading_state = reading_state_initial ; // restart at state 1. }
mFailed_read_attempts = 0 ; else
return -1; {
}
else
{
#ifdef DEBUG_PQISTREAMER #ifdef DEBUG_PQISTREAMER
std::cerr << "[" << (void*)pthread_self() << "] " << "given up 5, state = " << mReading_state << std::endl ; std::cerr << "[" << (void*)pthread_self() << "] " << "given up 5, state = " << mReading_state << std::endl ;
#endif #endif
return 0 ; // this is just a SSL_WANT_READ error. Don't panic, we'll re-try the read soon. return 0 ; // this is just a SSL_WANT_READ error. Don't panic, we'll re-try the read soon.
// we assume readdata() returned either -1 or the complete read size. // we assume readdata() returned either -1 or the complete read size.
} }
} }
#ifdef DEBUG_PQISTREAMER #ifdef DEBUG_PQISTREAMER
std::cerr << "[" << (void*)pthread_self() << "] " << "continuing packet state=" << mReading_state << std::endl ; std::cerr << "[" << (void*)pthread_self() << "] " << "continuing packet state=" << mReading_state << std::endl ;
std::cerr << "[" << (void*)pthread_self() << "] " << "block 2 : " << (int)(((unsigned char*)extradata)[0]) << " " << (int)(((unsigned char*)extradata)[1]) << " " << (int)(((unsigned char*)extradata)[2]) << " " << (int)(((unsigned char*)extradata)[3]) << " " std::cerr << "[" << (void*)pthread_self() << "] " << "block 2 : " << RsUtil::BinToHex(extradata,8) << std::endl;
<< (int)(((unsigned char*)extradata)[4]) << " "
<< (int)(((unsigned char*)extradata)[5]) << " "
<< (int)(((unsigned char*)extradata)[6]) << " "
<< (int)(((unsigned char*)extradata)[7]) << " " << std::endl ;
#endif #endif
mFailed_read_attempts = 0 ; mFailed_read_attempts = 0 ;
readbytes += extralen; readbytes += extralen;
} }
// create packet, based on header. // create packet, based on header.
#ifdef DEBUG_PQISTREAMER #ifdef DEBUG_PQISTREAMER
{ {
std::string out; std::string out;
rs_sprintf(out, "Read Data Block -> Incoming Pkt(%d)", blen + extralen); rs_sprintf(out, "Read Data Block -> Incoming Pkt(%d)", blen + extralen);
//std::cerr << out ; //std::cerr << out ;
pqioutput(PQL_DEBUG_BASIC, pqistreamerzone, out); pqioutput(PQL_DEBUG_BASIC, pqistreamerzone, out);
} }
#endif #endif
// std::cerr << "Deserializing packet of size " << pktlen <<std::endl ; uint32_t pktlen = blen+extralen ;
uint32_t pktlen = blen+extralen ;
#ifdef DEBUG_PQISTREAMER #ifdef DEBUG_PQISTREAMER
std::cerr << "[" << (void*)pthread_self() << "] " << "deserializing. Size=" << pktlen << std::endl ; std::cerr << "[" << (void*)pthread_self() << "] " << RsUtil::BinToHex((char*)block,8) << "...: deserializing. Size=" << pktlen << std::endl ;
#endif #endif
RsItem *pkt ;
RsItem *pkt = mRsSerialiser->deserialise(block, &pktlen); if(is_partial_packet)
{
#ifdef DEBUG_PACKET_SLICING
std::cerr << "Inputing partial packet " << RsUtil::BinToHex((char*)block,8) << std::endl;
#endif
pkt = addPartialPacket(block,pktlen,slice_packet_id,is_packet_starting,is_packet_ending) ;
}
else
pkt = mRsSerialiser->deserialise(block, &pktlen);
if ((pkt != NULL) && (0 < handleincomingitem_locked(pkt,pktlen))) if ((pkt != NULL) && (0 < handleincomingitem_locked(pkt,pktlen)))
{ {
#ifdef DEBUG_PQISTREAMER #ifdef DEBUG_PQISTREAMER
pqioutput(PQL_DEBUG_BASIC, pqistreamerzone, "Successfully Read a Packet!"); pqioutput(PQL_DEBUG_BASIC, pqistreamerzone, "Successfully Read a Packet!");
#endif #endif
inReadBytes_locked(pktlen); // only count deserialised packets, because that's what is actually been transfered. inReadBytes_locked(pktlen); // only count deserialised packets, because that's what is actually been transfered.
} }
else else if (!is_partial_packet)
{ {
#ifdef DEBUG_PQISTREAMER #ifdef DEBUG_PQISTREAMER
pqioutput(PQL_ALERT, pqistreamerzone, "Failed to handle Packet!"); pqioutput(PQL_ALERT, pqistreamerzone, "Failed to handle Packet!");
#endif #endif
std::cerr << "Incoming Packet could not be deserialised:" << std::endl; std::cerr << "Incoming Packet could not be deserialised:" << std::endl;
std::cerr << " Incoming peer id: " << PeerId() << std::endl; std::cerr << " Incoming peer id: " << PeerId() << std::endl;
if(pktlen >= 8) if(pktlen >= 8)
std::cerr << " Packet header : " << RsUtil::BinToHex((unsigned char*)block,8) << std::endl; std::cerr << " Packet header : " << RsUtil::BinToHex((unsigned char*)block,8) << std::endl;
if(pktlen > 8) if(pktlen > 8)
std::cerr << " Packet data : " << RsUtil::BinToHex((unsigned char*)block+8,std::min(50u,pktlen-8)) << ((pktlen>58)?"...":"") << std::endl; std::cerr << " Packet data : " << RsUtil::BinToHex((unsigned char*)block+8,std::min(50u,pktlen-8)) << ((pktlen>58)?"...":"") << std::endl;
} }
mReading_state = reading_state_initial ; // restart at state 1. mReading_state = reading_state_initial ; // restart at state 1.
mFailed_read_attempts = 0 ; // reset failed read, as the packet has been totally read. mFailed_read_attempts = 0 ; // reset failed read, as the packet has been totally read.
} }
if(maxin > readbytes && mBio->moretoread(0)) if(maxin > readbytes && mBio->moretoread(0))
goto start_packet_read ; goto start_packet_read ;
#ifdef DEBUG_TRANSFERS #ifdef DEBUG_TRANSFERS
if (readbytes >= maxin) if (readbytes >= maxin)
{ {
std::cerr << "pqistreamer::handleincoming() Stopped reading as readbytes >= maxin. Read " << readbytes << " bytes "; std::cerr << "pqistreamer::handleincoming() Stopped reading as readbytes >= maxin. Read " << readbytes << " bytes ";
std::cerr << std::endl; std::cerr << std::endl;
} }
#endif #endif
return 0; return 0;
} }
RsItem *pqistreamer::addPartialPacket(const void *block,uint32_t len,uint32_t slice_packet_id,bool is_packet_starting,bool is_packet_ending)
{
#ifdef DEBUG_PACKET_SLICING
std::cerr << "Receiving partial packet. size=" << len << ", ID=" << std::hex << slice_packet_id << std::dec << ", starting:" << is_packet_starting << ", ending:" << is_packet_ending ;
#endif
if(is_packet_starting && is_packet_ending)
{
std::cerr << " (EE) unexpected situation: both starting and ending" << std::endl;
return NULL ;
}
uint32_t slice_length = len - PQISTREAM_PARTIAL_PACKET_HEADER_SIZE ;
unsigned char *slice_data = &((unsigned char*)block)[PQISTREAM_PARTIAL_PACKET_HEADER_SIZE] ;
std::map<uint32_t,PartialPacketRecord>::iterator it = mPartialPackets.find(slice_packet_id) ;
if(it == mPartialPackets.end())
{
// make sure we really have a starting packet. Otherwise this is an error.
if(!is_packet_starting)
{
std::cerr << " (EE) non starting packet has no record. Dropping" << std::endl;
return NULL ;
}
PartialPacketRecord& rec = mPartialPackets[slice_packet_id] ;
rec.mem = rs_malloc(slice_length) ;
if(!rec.mem)
{
std::cerr << " (EE) Cannot allocate memory for slice of size " << slice_length << std::endl;
return NULL ;
}
memcpy(rec.mem, slice_data, slice_length) ; ;
rec.size = slice_length ;
#ifdef DEBUG_PACKET_SLICING
std::cerr << " => stored in new record (size=" << rec.size << std::endl;
#endif
return NULL ; // no need to check for ending
}
else
{
PartialPacketRecord& rec = it->second ;
if(is_packet_starting)
{
std::cerr << "(WW) dropping unfinished existing packet that gets to be replaced by new starting packet." << std::endl;
free(rec.mem);
rec.size = 0 ;
}
// make sure this is a continuing packet, otherwise this is an error.
rec.mem = realloc(rec.mem, rec.size + slice_length) ;
memcpy( &((char*)rec.mem)[rec.size],slice_data,slice_length) ;
rec.size += slice_length ;
#ifdef DEBUG_PACKET_SLICING
std::cerr << " => added to existing record size=" << rec.size ;
#endif
if(is_packet_ending)
{
#ifdef DEBUG_PACKET_SLICING
std::cerr << " => deserialising: mem=" << RsUtil::BinToHex((char*)rec.mem,std::min(8u,rec.size)) << std::endl;
#endif
RsItem *item = mRsSerialiser->deserialise(rec.mem, &rec.size);
free(rec.mem) ;
mPartialPackets.erase(it) ;
return item ;
}
else
{
#ifdef DEBUG_PACKET_SLICING
std::cerr << std::endl;
#endif
return NULL ;
}
}
}
/* BandWidth Management Assistance */ /* BandWidth Management Assistance */
@ -1074,8 +1283,13 @@ int pqistreamer::locked_gatherStatistics(std::list<RSTrafficClue>& out_lst,std::
return 1 ; return 1 ;
} }
void *pqistreamer::locked_pop_out_data() void *pqistreamer::locked_pop_out_data(uint32_t max_slice_size,uint32_t& size,bool& starts,bool& ends,uint32_t& packet_id)
{ {
size = 0 ;
starts = true ;
ends = true ;
packet_id = 0 ;
void *res = NULL ; void *res = NULL ;
if (!mOutPkts.empty()) if (!mOutPkts.empty())
@ -1089,3 +1303,5 @@ void *pqistreamer::locked_pop_out_data()
} }
return res ; return res ;
} }

View File

@ -40,6 +40,12 @@
// The interface does not handle connection, just communication. // The interface does not handle connection, just communication.
// possible bioflags: BIN_FLAGS_NO_CLOSE | BIN_FLAGS_NO_DELETE // possible bioflags: BIN_FLAGS_NO_CLOSE | BIN_FLAGS_NO_DELETE
struct PartialPacketRecord
{
void *mem ;
uint32_t size ;
};
class pqistreamer: public PQInterface class pqistreamer: public PQInterface
{ {
public: public:
@ -71,13 +77,12 @@ class pqistreamer: public PQInterface
// These methods are redefined in pqiQoSstreamer // These methods are redefined in pqiQoSstreamer
// //
virtual void locked_storeInOutputQueue(void *ptr,int priority) ; virtual void locked_storeInOutputQueue(void *ptr, int size, int priority) ;
virtual int locked_out_queue_size() const ; virtual int locked_out_queue_size() const ;
virtual void locked_clear_out_queue() ; virtual void locked_clear_out_queue() ;
virtual int locked_compute_out_pkt_size() const ; virtual int locked_compute_out_pkt_size() const ;
virtual void *locked_pop_out_data() ; virtual void *locked_pop_out_data(uint32_t max_slice_size,uint32_t& size,bool& starts,bool& ends,uint32_t& packet_id);
//virtual int locked_gatherStatistics(std::vector<uint32_t>& per_service_count,std::vector<uint32_t>& per_priority_count) const; // extracting data. virtual int locked_gatherStatistics(std::list<RSTrafficClue>& outqueue_stats,std::list<RSTrafficClue>& inqueue_stats); // extracting data.
virtual int locked_gatherStatistics(std::list<RSTrafficClue>& outqueue_stats,std::list<RSTrafficClue>& inqueue_stats); // extracting data.
void updateRates() ; void updateRates() ;
@ -156,7 +161,12 @@ class pqistreamer: public PQInterface
std::list<RSTrafficClue> mCurrentStatsChunk_Out ; std::list<RSTrafficClue> mCurrentStatsChunk_Out ;
time_t mStatisticsTimeStamp ; time_t mStatisticsTimeStamp ;
void locked_addTrafficClue(const RsItem *pqi, uint32_t pktsize, std::list<RSTrafficClue> &lst); bool mAcceptsPacketSlicing ;
time_t mLastSentPacketSlicingProbe ;
void locked_addTrafficClue(const RsItem *pqi, uint32_t pktsize, std::list<RSTrafficClue> &lst);
RsItem *addPartialPacket(const void *block, uint32_t len, uint32_t slice_packet_id,bool packet_starting,bool packet_ending);
std::map<uint32_t,PartialPacketRecord> mPartialPackets ;
}; };
#endif //MRK_PQI_STREAMER_HEADER #endif //MRK_PQI_STREAMER_HEADER

View File

@ -69,8 +69,12 @@ static double getCurrentTS()
return cts; return cts;
} }
const double RsServer::minTimeDelta = 0.1; // 25; // These values should be tunable from the GUI, to offer a compromise between speed and CPU use.
const double RsServer::maxTimeDelta = 0.5; // In some cases (VOIP) it's likely that we will need to set them temporarily to a very low
// value, in order to favor a fast feedback
const double RsServer::minTimeDelta = 0.05; // 25;
const double RsServer::maxTimeDelta = 0.2;
const double RsServer::kickLimit = 0.15; const double RsServer::kickLimit = 0.15;
@ -138,7 +142,7 @@ void RsServer::data_tick()
double ts = getCurrentTS(); double ts = getCurrentTS();
double delta = ts - mLastts; double delta = ts - mLastts;
/* for the fast ticked stuff */ /* for the fast ticked stuff */
if (delta > mTimeDelta) if (delta > mTimeDelta)
{ {

View File

@ -366,11 +366,7 @@ int RsInit::InitRetroShare(int argcIgnored, char **argvIgnored, bool strictCheck
#ifdef LOCALNET_TESTING #ifdef LOCALNET_TESTING
>> parameter('R',"restrict-port" ,portRestrictions ,"port1-port2","Apply port restriction" ,false) >> parameter('R',"restrict-port" ,portRestrictions ,"port1-port2","Apply port restriction" ,false)
#endif #endif
#ifdef __APPLE__
>> help('h',"help","Display this Help") ; >> help('h',"help","Display this Help") ;
#else
>> help() ;
#endif
as.defaultErrorHandling(true) ; as.defaultErrorHandling(true) ;

View File

@ -96,6 +96,9 @@ const uint16_t RS_SERVICE_TYPE_PLUGIN_ARADO_ID = 0x2001;
const uint16_t RS_SERVICE_TYPE_PLUGIN_QCHESS_ID = 0x2002; const uint16_t RS_SERVICE_TYPE_PLUGIN_QCHESS_ID = 0x2002;
const uint16_t RS_SERVICE_TYPE_PLUGIN_FEEDREADER = 0x2003; const uint16_t RS_SERVICE_TYPE_PLUGIN_FEEDREADER = 0x2003;
// Reserved for packet slicing probes.
const uint16_t RS_SERVICE_TYPE_PACKET_SLICING_PROBE = 0xAABB;
// Nabu's services. // Nabu's services.
const uint16_t RS_SERVICE_TYPE_PLUGIN_FIDO_GW = 0xF1D0; const uint16_t RS_SERVICE_TYPE_PLUGIN_FIDO_GW = 0xF1D0;
const uint16_t RS_SERVICE_TYPE_PLUGIN_ZERORESERVE = 0xBEEF; const uint16_t RS_SERVICE_TYPE_PLUGIN_ZERORESERVE = 0xBEEF;

View File

@ -23,6 +23,8 @@
* *
*/ */
#include <iomanip>
#include "util/rsdir.h" #include "util/rsdir.h"
#include "retroshare/rsiface.h" #include "retroshare/rsiface.h"
#include "pqi/pqibin.h" #include "pqi/pqibin.h"
@ -38,7 +40,6 @@
* #define DEBUG_RTT 1 * #define DEBUG_RTT 1
****/ ****/
/* DEFINE INTERFACE POINTER! */ /* DEFINE INTERFACE POINTER! */
RsRtt *rsRtt = NULL; RsRtt *rsRtt = NULL;
@ -168,7 +169,7 @@ int p3rtt::sendPackets()
pt = mSentPingTime; pt = mSentPingTime;
} }
if (now - pt > RTT_PING_PERIOD) if (now >= pt+RTT_PING_PERIOD)
{ {
sendPingMeasurements(); sendPingMeasurements();
@ -190,19 +191,10 @@ void p3rtt::sendPingMeasurements()
mServiceCtrl->getPeersConnected(getServiceInfo().mServiceType, idList); mServiceCtrl->getPeersConnected(getServiceInfo().mServiceType, idList);
#ifdef DEBUG_RTT
std::cerr << "p3rtt::sendPingMeasurements() @ts: " << ts;
std::cerr << std::endl;
#endif
/* prepare packets */ /* prepare packets */
std::set<RsPeerId>::iterator it; std::set<RsPeerId>::iterator it;
for(it = idList.begin(); it != idList.end(); ++it) for(it = idList.begin(); it != idList.end(); ++it)
{ {
#ifdef DEBUG_RTT
std::cerr << "p3rtt::sendPingMeasurements() Pinging: " << *it;
std::cerr << std::endl;
#endif
double ts = getCurrentTS(); double ts = getCurrentTS();
/* create the packet */ /* create the packet */
@ -214,11 +206,8 @@ void p3rtt::sendPingMeasurements()
storePingAttempt(*it, ts, mCounter); storePingAttempt(*it, ts, mCounter);
#ifdef DEBUG_RTT #ifdef DEBUG_RTT
std::cerr << "p3rtt::sendPingMeasurements() With Packet:"; std::cerr << "p3rtt::sendPingMeasurements() Pinging: " << *it << " [" << pingPkt->mSeqNo << "," << std::hex << pingPkt->mPingTS << std::dec << "]" << std::endl;;
std::cerr << std::endl;
pingPkt->print(std::cerr, 10);
#endif #endif
sendItem(pingPkt); sendItem(pingPkt);
} }
@ -256,30 +245,28 @@ int p3rtt::handlePing(RsItem *item)
/* cast to right type */ /* cast to right type */
RsRttPingItem *ping = (RsRttPingItem *) item; RsRttPingItem *ping = (RsRttPingItem *) item;
double ts = getCurrentTS();
#ifdef DEBUG_RTT #ifdef DEBUG_RTT
std::cerr << "p3rtt::handlePing() Recvd Packet from: " << ping->PeerId(); std::cerr << "p3rtt::handlePing() from: " << ping->PeerId() << " - [" << ping->mSeqNo << "," << std::hex << ping->mPingTS << std::dec << "] " << std::endl;
std::cerr << std::endl; std::cerr << "incoming ping travel time: " << ts - convert64bitsToTs(ping->mPingTS) << std::endl;
#endif #endif
/* with a ping, we just respond as quickly as possible - they do all the analysis */ /* with a ping, we just respond as quickly as possible - they do all the analysis */
RsRttPongItem *pong = new RsRttPongItem(); RsRttPongItem *pong = new RsRttPongItem();
pong->PeerId(ping->PeerId()); pong->PeerId(ping->PeerId());
pong->mPingTS = ping->mPingTS; pong->mPingTS = ping->mPingTS;
pong->mSeqNo = ping->mSeqNo; pong->mSeqNo = ping->mSeqNo;
// add our timestamp. // add our timestamp.
double ts = getCurrentTS();
pong->mPongTS = convertTsTo64bits(ts); pong->mPongTS = convertTsTo64bits(ts);
static double mLastResponseToPong = 0.0 ;// bad stuff
#ifdef DEBUG_RTT #ifdef DEBUG_RTT
std::cerr << "p3rtt::handlePing() With Packet:"; std::cerr << "Delay since last response to PONG: " << ts - mLastResponseToPong << std::endl;
std::cerr << std::endl;
pong->print(std::cerr, 10);
#endif #endif
mLastResponseToPong = ts ;
sendItem(pong); sendItem(pong);
return true ; return true ;
} }
@ -291,9 +278,7 @@ int p3rtt::handlePong(RsItem *item)
RsRttPongItem *pong = (RsRttPongItem *) item; RsRttPongItem *pong = (RsRttPongItem *) item;
#ifdef DEBUG_RTT #ifdef DEBUG_RTT
std::cerr << "p3rtt::handlePong() Recvd Packet from: " << pong->PeerId(); std::cerr << "p3rtt::handlePong() from: " << pong->PeerId() << " - [" << pong->mSeqNo << "," << std::hex << pong->mPingTS << " -> " << pong->mPongTS << std::dec << "] "<< std::endl;
std::cerr << std::endl;
pong->print(std::cerr, 10);
#endif #endif
/* with a pong, we do the maths! */ /* with a pong, we do the maths! */
@ -305,21 +290,12 @@ int p3rtt::handlePong(RsItem *item)
double offset = pongTS - (recvTS - rtt / 2.0); // so to get to their time, we go ourTS + offset. double offset = pongTS - (recvTS - rtt / 2.0); // so to get to their time, we go ourTS + offset.
#ifdef DEBUG_RTT #ifdef DEBUG_RTT
std::cerr << "p3rtt::handlePong() Timing:"; std::cerr << "incoming pong travel time: " << recvTS - convert64bitsToTs(pong->mPongTS) << std::endl;
std::cerr << std::endl; std::cerr << " RTT analysis: pingTS: " << std::setprecision(16) << pingTS << ", pongTS: " << pongTS
std::cerr << "\tpingTS: " << pingTS; << ", recvTS: " << std::setprecision(16) << recvTS << " ==> rtt: " << rtt << ", offset: " << offset << std::endl;
std::cerr << std::endl;
std::cerr << "\tpongTS: " << pongTS;
std::cerr << std::endl;
std::cerr << "\trecvTS: " << recvTS;
std::cerr << std::endl;
std::cerr << "\t ==> rtt: " << rtt;
std::cerr << std::endl;
std::cerr << "\t ==> offset: " << offset;
std::cerr << std::endl;
#endif #endif
storePongResult(pong->PeerId(), pong->mSeqNo, pingTS, rtt, offset); storePongResult(pong->PeerId(), pong->mSeqNo, recvTS, rtt, offset);
return true ; return true ;
} }
@ -333,6 +309,9 @@ int p3rtt::storePingAttempt(const RsPeerId& id, double ts, uint32_t seqno)
/* find corresponding local data */ /* find corresponding local data */
RttPeerInfo *peerInfo = locked_GetPeerInfo(id); RttPeerInfo *peerInfo = locked_GetPeerInfo(id);
#ifdef DEBUG_RTT
std::cerr << "Delay since previous ping attempt: " << ts - peerInfo->mCurrentPingTS << std::endl;
#endif
peerInfo->mCurrentPingTS = ts; peerInfo->mCurrentPingTS = ts;
peerInfo->mCurrentPingCounter = seqno; peerInfo->mCurrentPingCounter = seqno;
@ -349,7 +328,7 @@ int p3rtt::storePingAttempt(const RsPeerId& id, double ts, uint32_t seqno)
int p3rtt::storePongResult(const RsPeerId& id, uint32_t counter, double ts, double rtt, double offset) int p3rtt::storePongResult(const RsPeerId& id, uint32_t counter, double recv_ts, double rtt, double offset)
{ {
RsStackMutex stack(mRttMtx); /****** LOCKED MUTEX *******/ RsStackMutex stack(mRttMtx); /****** LOCKED MUTEX *******/
@ -366,8 +345,12 @@ int p3rtt::storePongResult(const RsPeerId& id, uint32_t counter, double ts, doub
{ {
peerInfo->mCurrentPongRecvd = true; peerInfo->mCurrentPongRecvd = true;
} }
#ifdef DEBUG_RTT
if(!peerInfo->mPongResults.empty())
std::cerr << "Delay since last pong: " << recv_ts - peerInfo->mPongResults.back().mTS << std::endl;
#endif
peerInfo->mPongResults.push_back(RsRttPongResult(ts, rtt, offset)); peerInfo->mPongResults.push_back(RsRttPongResult(recv_ts, rtt, offset));
while(peerInfo->mPongResults.size() > MAX_PONG_RESULTS) while(peerInfo->mPongResults.size() > MAX_PONG_RESULTS)

View File

@ -84,7 +84,7 @@ virtual bool recvItem(RsItem *item); // Overloaded from p3FastService.
int handlePong(RsItem *item); int handlePong(RsItem *item);
int storePingAttempt(const RsPeerId& id, double ts, uint32_t mCounter); int storePingAttempt(const RsPeerId& id, double ts, uint32_t mCounter);
int storePongResult(const RsPeerId& id, uint32_t counter, double ts, double rtt, double offset); int storePongResult(const RsPeerId& id, uint32_t counter, double recv_ts, double rtt, double offset);
/*! /*!

View File

@ -726,7 +726,7 @@ bool p3turtle::loadList(std::list<RsItem*>& load)
} }
} }
delete vitem ; delete *it ;
} }
load.clear() ; load.clear() ;
return true ; return true ;

View File

@ -140,16 +140,11 @@ namespace
protected: protected:
inline OptionHolder(char s, inline OptionHolder(char s,
const char* l, const char* l,
const char* desc); const char* desc);
#ifdef __APPLE__
friend OptionHolder help(char s, friend OptionHolder help(char s,
const char* l, const char* l,
const char* desc); const char* desc);
#else
friend OptionHolder help(char s='h',
const char* l="help",
const char* desc="Display this help");
#endif
private: private:
std::string shortName_; std::string shortName_;
std::string longName_; std::string longName_;

View File

@ -13,7 +13,7 @@ void *rs_malloc(size_t size)
if(size > SAFE_MEMALLOC_THRESHOLD) if(size > SAFE_MEMALLOC_THRESHOLD)
{ {
std::cerr << "(EE) Memory allocation error. A chunk of size 0 was requested. Callstack:" << std::endl; std::cerr << "(EE) Memory allocation error. A chunk of size larger than " << SAFE_MEMALLOC_THRESHOLD << " was requested. Callstack:" << std::endl;
print_stacktrace() ; print_stacktrace() ;
return NULL ; return NULL ;
} }

View File

@ -219,8 +219,8 @@ TransfersDialog::TransfersDialog(QWidget *parent)
// workaround for Qt bug, should be solved in next Qt release 4.7.0 // workaround for Qt bug, should be solved in next Qt release 4.7.0
// http://bugreports.qt.nokia.com/browse/QTBUG-8270 // http://bugreports.qt.nokia.com/browse/QTBUG-8270
QShortcut *Shortcut = new QShortcut(QKeySequence (Qt::Key_Delete), ui.downloadList, 0, 0, Qt::WidgetShortcut); mShortcut = new QShortcut(QKeySequence (Qt::Key_Delete), ui.downloadList, 0, 0, Qt::WidgetShortcut);
connect(Shortcut, SIGNAL(activated()), this, SLOT( cancel ())); connect(mShortcut, SIGNAL(activated()), this, SLOT( cancel ()));
//Selection Setup //Selection Setup
selection = ui.downloadList->selectionModel(); selection = ui.downloadList->selectionModel();
@ -942,7 +942,8 @@ int TransfersDialog::addItem(int row, const FileInfo &fileInfo)
qlonglong completed = fileInfo.transfered; qlonglong completed = fileInfo.transfered;
qlonglong remaining = fileInfo.size - fileInfo.transfered; qlonglong remaining = fileInfo.size - fileInfo.transfered;
qlonglong downloadtime = (fileInfo.size - fileInfo.transfered) / (fileInfo.tfRate * 1024.0);
qlonglong downloadtime = (fileInfo.tfRate > 0)?( (fileInfo.size - fileInfo.transfered) / (fileInfo.tfRate * 1024.0) ) : 0 ;
qint64 qi64LastDL = fileInfo.lastTS ; //std::numeric_limits<qint64>::max(); qint64 qi64LastDL = fileInfo.lastTS ; //std::numeric_limits<qint64>::max();
if (qi64LastDL == 0) // file is complete, or any raison why the time has not been set properly if (qi64LastDL == 0) // file is complete, or any raison why the time has not been set properly
@ -1355,7 +1356,7 @@ void TransfersDialog::insertTransfers()
qlonglong fileSize = info.size; qlonglong fileSize = info.size;
qlonglong completed = pit->transfered; qlonglong completed = pit->transfered;
// double progress = (info.size > 0)?(pit->transfered * 100.0 / info.size):0.0; // double progress = (info.size > 0)?(pit->transfered * 100.0 / info.size):0.0;
qlonglong remaining = (info.size - pit->transfered) / (pit->tfRate * 1024.0); qlonglong remaining = (pit->tfRate>0)?((info.size - pit->transfered) / (pit->tfRate * 1024.0)):0;
// Estimate the completion. We need something more accurate, meaning that we need to // Estimate the completion. We need something more accurate, meaning that we need to
// transmit the completion info. // transmit the completion info.

View File

@ -31,6 +31,7 @@
#define IMAGE_TRANSFERS ":/icons/ktorrent_128.png" #define IMAGE_TRANSFERS ":/icons/ktorrent_128.png"
class QShortcut;
class DLListDelegate; class DLListDelegate;
class ULListDelegate; class ULListDelegate;
class QStandardItemModel; class QStandardItemModel;
@ -243,6 +244,8 @@ private:
QString downloads; QString downloads;
QString uploads; QString uploads;
QShortcut *mShortcut ;
/** Qt Designer generated object */ /** Qt Designer generated object */
Ui::TransfersDialog ui; Ui::TransfersDialog ui;

View File

@ -1725,7 +1725,11 @@ void ChatWidget::quote()
void ChatWidget::dropPlacemark() void ChatWidget::dropPlacemark()
{ {
ui->textBrowser->append("----------"); ui->textBrowser->moveCursor(QTextCursor::End); // *append* inserts text at end but with formatting in effect at
ui->textBrowser->append("----------"); // current cursor position, such as in the middle of a hotlink,
// which would be strange. This OTOH inserts text with
// formatting in effect on the last line, which may be strange
// or not.
} }
void ChatWidget::saveImage() void ChatWidget::saveImage()

View File

@ -10,6 +10,7 @@ SubscribeToolButton::SubscribeToolButton(QWidget *parent) :
{ {
mSubscribed = false; mSubscribed = false;
mMenu = NULL ;
setToolButtonStyle(Qt::ToolButtonTextBesideIcon); setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
#ifdef USE_MENUBUTTONPOPUP #ifdef USE_MENUBUTTONPOPUP
@ -46,14 +47,18 @@ void SubscribeToolButton::updateUi()
setIcon(QIcon(":/images/accepted16.png")); setIcon(QIcon(":/images/accepted16.png"));
setText(tr("Subscribed")); setText(tr("Subscribed"));
QMenu *menu = new QMenu; if(mMenu != NULL) // that's because setMenu does not give away memory ownership
menu->addAction(QIcon(":/images/cancel.png"), tr("Unsubscribe"), this, SLOT(unsubscribePrivate())); delete mMenu ;
mMenu = new QMenu;
mMenu->addAction(QIcon(":/images/cancel.png"), tr("Unsubscribe"), this, SLOT(unsubscribePrivate()));
if (!mSubscribedActions.empty()) { if (!mSubscribedActions.empty()) {
menu->addSeparator(); mMenu->addSeparator();
menu->addActions(mSubscribedActions); mMenu->addActions(mSubscribedActions);
} }
setMenu(menu);
setMenu(mMenu);
#ifndef USE_MENUBUTTONPOPUP #ifndef USE_MENUBUTTONPOPUP
disconnect(this, SIGNAL(clicked()), this, SLOT(subscribePrivate())); disconnect(this, SIGNAL(clicked()), this, SLOT(subscribePrivate()));

View File

@ -26,6 +26,7 @@ private:
private: private:
bool mSubscribed; bool mSubscribed;
QList<QAction*> mSubscribedActions; QList<QAction*> mSubscribedActions;
QMenu *mMenu ;
}; };
#endif // SUBSCRIBETOOLBUTTON_H #endif // SUBSCRIBETOOLBUTTON_H

View File

@ -259,7 +259,7 @@ void GraphWidget::keyPressEvent(QKeyEvent *event)
} }
} }
static void convolveWithGaussian(double *forceMap,int S,int /*s*/) static void convolveWithGaussian(double *forceMap,unsigned int S,int /*s*/)
{ {
static double *bf = NULL ; static double *bf = NULL ;
@ -267,8 +267,8 @@ static void convolveWithGaussian(double *forceMap,int S,int /*s*/)
{ {
bf = new double[S*S*2] ; bf = new double[S*S*2] ;
for(int i=0;i<S;++i) for(unsigned int i=0;i<S;++i)
for(int j=0;j<S;++j) for(unsigned int j=0;j<S;++j)
{ {
int x = (i<S/2)?i:(S-i) ; int x = (i<S/2)?i:(S-i) ;
int y = (j<S/2)?j:(S-j) ; int y = (j<S/2)?j:(S-j) ;
@ -284,8 +284,8 @@ static void convolveWithGaussian(double *forceMap,int S,int /*s*/)
unsigned long nn[2] = {S,S}; unsigned long nn[2] = {S,S};
fourn(&forceMap[-1],&nn[-1],2,1) ; fourn(&forceMap[-1],&nn[-1],2,1) ;
for(int i=0;i<S;++i) for(unsigned int i=0;i<S;++i)
for(int j=0;j<S;++j) for(unsigned int j=0;j<S;++j)
{ {
float a = forceMap[2*(i+S*j)]*bf[2*(i+S*j)] - forceMap[2*(i+S*j)+1]*bf[2*(i+S*j)+1] ; float a = forceMap[2*(i+S*j)]*bf[2*(i+S*j)] - forceMap[2*(i+S*j)+1]*bf[2*(i+S*j)+1] ;
float b = forceMap[2*(i+S*j)]*bf[2*(i+S*j)+1] + forceMap[2*(i+S*j)+1]*bf[2*(i+S*j)] ; float b = forceMap[2*(i+S*j)]*bf[2*(i+S*j)+1] + forceMap[2*(i+S*j)+1]*bf[2*(i+S*j)] ;
@ -296,7 +296,7 @@ static void convolveWithGaussian(double *forceMap,int S,int /*s*/)
fourn(&forceMap[-1],&nn[-1],2,-1) ; fourn(&forceMap[-1],&nn[-1],2,-1) ;
for(int i=0;i<S*S*2;++i) for(unsigned int i=0;i<S*S*2;++i)
forceMap[i] /= S*S; forceMap[i] /= S*S;
} }

View File

@ -362,21 +362,21 @@ Rshare::showUsageMessageBox()
out << "<table>"; out << "<table>";
//out << trow(tcol("-"ARG_HELP) + //out << trow(tcol("-"ARG_HELP) +
// tcol(tr("Displays this usage message and exits."))); // tcol(tr("Displays this usage message and exits.")));
out << trow(tcol("-"ARG_RESET) + out << trow(tcol("-" ARG_RESET) +
tcol(tr("Resets ALL stored RetroShare settings."))); tcol(tr("Resets ALL stored RetroShare settings.")));
out << trow(tcol("-"ARG_DATADIR" &lt;dir&gt;") + out << trow(tcol("-" ARG_DATADIR" &lt;dir&gt;") +
tcol(tr("Sets the directory RetroShare uses for data files."))); tcol(tr("Sets the directory RetroShare uses for data files.")));
out << trow(tcol("-"ARG_LOGFILE" &lt;file&gt;") + out << trow(tcol("-" ARG_LOGFILE" &lt;file&gt;") +
tcol(tr("Sets the name and location of RetroShare's logfile."))); tcol(tr("Sets the name and location of RetroShare's logfile.")));
out << trow(tcol("-"ARG_LOGLEVEL" &lt;level&gt;") + out << trow(tcol("-" ARG_LOGLEVEL" &lt;level&gt;") +
tcol(tr("Sets the verbosity of RetroShare's logging.") + tcol(tr("Sets the verbosity of RetroShare's logging.") +
"<br>[" + Log::logLevels().join("|") +"]")); "<br>[" + Log::logLevels().join("|") +"]"));
out << trow(tcol("-"ARG_GUISTYLE" &lt;style&gt;") + out << trow(tcol("-" ARG_GUISTYLE" &lt;style&gt;") +
tcol(tr("Sets RetroShare's interface style.") + tcol(tr("Sets RetroShare's interface style.") +
"<br>[" + QStyleFactory::keys().join("|") + "]")); "<br>[" + QStyleFactory::keys().join("|") + "]"));
out << trow(tcol("-"ARG_GUISTYLESHEET" &lt;stylesheet&gt;") + out << trow(tcol("-" ARG_GUISTYLESHEET" &lt;stylesheet&gt;") +
tcol(tr("Sets RetroShare's interface stylesheets."))); tcol(tr("Sets RetroShare's interface stylesheets.")));
out << trow(tcol("-"ARG_LANGUAGE" &lt;language&gt;") + out << trow(tcol("-" ARG_LANGUAGE" &lt;language&gt;") +
tcol(tr("Sets RetroShare's language.") + tcol(tr("Sets RetroShare's language.") +
"<br>[" + LanguageSupport::languageCodes().join("|") + "]")); "<br>[" + LanguageSupport::languageCodes().join("|") + "]"));
out << "</table>"; out << "</table>";

View File

@ -17,6 +17,10 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, * Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA. * Boston, MA 02110-1301, USA.
*
* ccr . 2016 Jan 30 . Change regular expression(s) for identifying
* . . hotlinks in feral text.
*
****************************************************************/ ****************************************************************/
#include <QApplication> #include <QApplication>
@ -56,7 +60,7 @@ protected:
public: public:
const EmbeddedType myType; const EmbeddedType myType;
QRegExp myRE; QList<QRegExp> myREs;
}; };
/** /**
@ -67,10 +71,42 @@ class EmbedInHtmlAhref : public EmbedInHtml
public: public:
EmbedInHtmlAhref() : EmbedInHtml(Ahref) EmbedInHtmlAhref() : EmbedInHtml(Ahref)
{ {
myRE.setPattern("(\\bretroshare://[^\\s]*)|(\\bhttps?://[^\\s]*)|(\\bfile://[^\\s]*)|(\\bwww\\.[^\\s]*)"); // myRE.setPattern("(\\bretroshare://[^\\s]*)|(\\bhttps?://[^\\s]*)|(\\bfile://[^\\s]*)|(\\bwww\\.[^\\s]*)");
}
};
// The following regular expressions for finding URLs in
// plain text are borrowed from *gnome-terminal*:
QString regPassCharset = "[-\\w,?;\\.:/!%$^*&~\\\"#']";
QString regHost = "[-\\w]+(\\.[-\\w]+)*";
QString regPort = "(?:\\:\\d{1,5})?";
QString regPathCharset = "[-\\w_$\\.+!*,;@&=?/~#%]";
QString regPathTermSet = "[^\\]'.}<>) \\t\\r\\n,\\\"]";
QStringList regSchemes;
// regSchemes.append("news:");
// regSchemes.append("telnet:");
// regSchemes.append("nntp:");
// regSchemes.append("file:/");
regSchemes.append("https?:");
// regSchemes.append("ftps?:");
// regSchemes.append("sftp:");
// regSchemes.append("webcal:");
regSchemes.append("retroshare:");
QString regScheme = "((?:" + regSchemes.join(")|(?:") + "))";
QString regUserPass = "[-\\w]+(?:%s+)?" % regPassCharset;
QString regUrlPath = "(?:(/" + regPathCharset + "+(?:[(]" + regPathCharset +"*[)])*" + regPathCharset + "*)*" + regPathTermSet + ")?";
QStringList regHotLinkFinders;
regHotLinkFinders.append(regScheme + "//(?:" + regUserPass + "@)?"+ regHost + regPort + regUrlPath);
// regHotLinkFinders.append("(?:(?:www)|(?:ftp))[-\\w]*\\." + regHost + regPort + regUrlPath);
// regHotLinkFinders.append("(?:(?:callto:)|(?:h323:)|(?:sip:))[-\\w][-\\w\\.]*(?:" + regPort + "/[a-z0-9]+)?@" + regHost);
// regHotLinkFinders.append("(?:mailto:)?[-\\w][-\\w\\.]*@[-\\w]+\\." + regHost);
// regHotLinkFinders.append("news:[\\w^_{|}~!\\\"#$%&'()*+,\\./;:=?`]+");
while (!regHotLinkFinders.isEmpty()) {
myREs.append(QRegExp(regHotLinkFinders.takeFirst(), Qt::CaseInsensitive));
};
}
};
/** /**
* This class is used to store information for embedding smileys into <img/> tags. * This class is used to store information for embedding smileys into <img/> tags.
* *
@ -134,7 +170,7 @@ void RsHtml::initEmoticons(const QHash< QString, QString >& hash)
*/ */
} }
newRE.chop(1); // remove last | newRE.chop(1); // remove last |
defEmbedImg.myRE.setPattern(newRE); defEmbedImg.myREs.append(QRegExp(newRE));
} }
bool RsHtml::canReplaceAnchor(QDomDocument &/*doc*/, QDomElement &/*element*/, const RetroShareLink &link) bool RsHtml::canReplaceAnchor(QDomDocument &/*doc*/, QDomElement &/*element*/, const RetroShareLink &link)
@ -243,7 +279,7 @@ void RsHtml::replaceAnchorWithImg(QDomDocument &doc, QDomElement &element, QText
* nodes. Any other kind of node is terminal. * nodes. Any other kind of node is terminal.
* *
* If the node is of type Text, its data is checked against the user-provided * If the node is of type Text, its data is checked against the user-provided
* regular expression. If there is a match, the text is cut in three parts: the * regular expression(s). If there is a match, the text is cut in three parts: the
* preceding part that will be inserted before, the part to be replaced, and the * preceding part that will be inserted before, the part to be replaced, and the
* following part which will be itself checked against the regular expression. * following part which will be itself checked against the regular expression.
* *
@ -252,13 +288,10 @@ void RsHtml::replaceAnchorWithImg(QDomDocument &doc, QDomElement &element, QText
* *
* @param[in] doc The whole DOM tree, necessary to create new nodes * @param[in] doc The whole DOM tree, necessary to create new nodes
* @param[in,out] currentElement The current node (which is of type Element) * @param[in,out] currentElement The current node (which is of type Element)
* @param[in] embedInfos The regular expression and the type of embedding to use * @param[in] embedInfos The regular expression(s) and the type of embedding to use
*/ */
void RsHtml::embedHtml(QTextDocument *textDocument, QDomDocument& doc, QDomElement& currentElement, EmbedInHtml& embedInfos, ulong flag) void RsHtml::embedHtml(QTextDocument *textDocument, QDomDocument& doc, QDomElement& currentElement, EmbedInHtml& embedInfos, ulong flag)
{ {
if(embedInfos.myRE.pattern().length() == 0) // we'll get stuck with an empty regexp
return;
QDomNodeList children = currentElement.childNodes(); QDomNodeList children = currentElement.childNodes();
for(uint index = 0; index < (uint)children.length(); index++) { for(uint index = 0; index < (uint)children.length(); index++) {
QDomNode node = children.item(index); QDomNode node = children.item(index);
@ -298,15 +331,20 @@ void RsHtml::embedHtml(QTextDocument *textDocument, QDomDocument& doc, QDomEleme
} }
} }
else if(node.isText()) { else if(node.isText()) {
// child is a text, we parse it // child is a text, we parse it
QString tempText = node.toText().data(); QString tempText = node.toText().data();
if(embedInfos.myRE.indexIn(tempText) == -1) for (int patNdx = 0; patNdx < embedInfos.myREs.size(); ++patNdx) {
QRegExp myRE = embedInfos.myREs.at(patNdx);
if(myRE.pattern().length() == 0) // we'll get stuck with an empty regexp
return;
if(myRE.indexIn(tempText) == -1)
continue; continue;
// there is at least one link inside, we start replacing // there is at least one link inside, we start replacing
int currentPos = 0; int currentPos = 0;
int nextPos = 0; int nextPos = 0;
while((nextPos = embedInfos.myRE.indexIn(tempText, currentPos)) != -1) { while((nextPos = myRE.indexIn(tempText, currentPos)) != -1) {
// if nextPos == 0 it means the text begins by a link // if nextPos == 0 it means the text begins by a link
if(nextPos > 0) { if(nextPos > 0) {
QDomText textPart = doc.createTextNode(tempText.mid(currentPos, nextPos - currentPos)); QDomText textPart = doc.createTextNode(tempText.mid(currentPos, nextPos - currentPos));
@ -320,10 +358,10 @@ void RsHtml::embedHtml(QTextDocument *textDocument, QDomDocument& doc, QDomEleme
case Ahref: case Ahref:
{ {
insertedTag = doc.createElement("a"); insertedTag = doc.createElement("a");
insertedTag.setAttribute("href", embedInfos.myRE.cap(0)); insertedTag.setAttribute("href", myRE.cap(0));
insertedTag.appendChild(doc.createTextNode(embedInfos.myRE.cap(0))); insertedTag.appendChild(doc.createTextNode(myRE.cap(0)));
RetroShareLink link(embedInfos.myRE.cap(0)); RetroShareLink link(myRE.cap(0));
if (link.valid()) { if (link.valid()) {
QString title = link.title(); QString title = link.title();
if (!title.isEmpty()) { if (!title.isEmpty()) {
@ -340,11 +378,11 @@ void RsHtml::embedHtml(QTextDocument *textDocument, QDomDocument& doc, QDomEleme
{ {
insertedTag = doc.createElement("img"); insertedTag = doc.createElement("img");
const EmbedInHtmlImg& embedImg = static_cast<const EmbedInHtmlImg&>(embedInfos); const EmbedInHtmlImg& embedImg = static_cast<const EmbedInHtmlImg&>(embedInfos);
// embedInfos.myRE.cap(0) may include spaces at the end/beginning -> trim! // myRE.cap(0) may include spaces at the end/beginning -> trim!
insertedTag.setAttribute("src", embedImg.smileys[embedInfos.myRE.cap(0).trimmed()]); insertedTag.setAttribute("src", embedImg.smileys[myRE.cap(0).trimmed()]);
/* /*
* NOTE * NOTE
* Trailing spaces are matched, too. This leads to embedInfos.myRE.matchedLength() being incorrect. * Trailing spaces are matched, too. This leads to myRE.matchedLength() being incorrect.
* This hack reduces nextPos by one so that the new value of currentPos is calculated corretly. * This hack reduces nextPos by one so that the new value of currentPos is calculated corretly.
* This is needed to match multiple smileys since the leading whitespace in front of a smiley is required! * This is needed to match multiple smileys since the leading whitespace in front of a smiley is required!
* *
@ -353,7 +391,7 @@ void RsHtml::embedHtml(QTextDocument *textDocument, QDomDocument& doc, QDomEleme
* NOTE * NOTE
* Preceding spaces are also matched and removed. * Preceding spaces are also matched and removed.
*/ */
if(embedInfos.myRE.cap(0).endsWith(' ')) if(myRE.cap(0).endsWith(' '))
nextPos--; nextPos--;
} }
break; break;
@ -362,7 +400,7 @@ void RsHtml::embedHtml(QTextDocument *textDocument, QDomDocument& doc, QDomEleme
currentElement.insertBefore(insertedTag, node); currentElement.insertBefore(insertedTag, node);
index++; index++;
currentPos = nextPos + embedInfos.myRE.matchedLength(); currentPos = nextPos + myRE.matchedLength();
} }
// text after the last link, only if there's one, don't touch the index // text after the last link, only if there's one, don't touch the index
@ -375,10 +413,18 @@ void RsHtml::embedHtml(QTextDocument *textDocument, QDomDocument& doc, QDomEleme
index--; index--;
currentElement.removeChild(node); currentElement.removeChild(node);
break;
// We'd better not expect that
// subsequent hotlink patterns
// wouldn't also match replacements
// we've already made. They might, so
// skip 'em to be safe.
};
} }
} }
} }
/** /**
* Save space and tab out of bracket that XML loose. * Save space and tab out of bracket that XML loose.
* *
@ -612,7 +658,7 @@ static void findBestColor(QString &val, qreal bglum, qreal desiredContrast)
*/ */
static void optimizeHtml(QDomDocument& doc static void optimizeHtml(QDomDocument& doc
, QDomElement& currentElement , QDomElement& currentElement
, QHash<QString, QStringList*> &stylesList , QHash<QString, QStringList> &stylesList
, QHash<QString, QString> &knownStyle) , QHash<QString, QString> &knownStyle)
{ {
if (doc.documentElement().namedItem("style").toElement().attributeNode("RSOptimized").isAttr()) { if (doc.documentElement().namedItem("style").toElement().attributeNode("RSOptimized").isAttr()) {
@ -631,10 +677,10 @@ static void optimizeHtml(QDomDocument& doc
QString keyvalue = pair.at(1); QString keyvalue = pair.at(1);
keyvalue.replace(";",""); keyvalue.replace(";","");
QStringList classUsingIt(pair.at(0).split(',')); QStringList classUsingIt(pair.at(0).split(','));
QStringList* exported = new QStringList(); QStringList exported ;
foreach (QString keyVal, classUsingIt) { foreach (QString keyVal, classUsingIt) {
if(!keyVal.trimmed().isEmpty()) { if(!keyVal.trimmed().isEmpty()) {
exported->append(keyVal.trimmed().replace(".","")); exported.append(keyVal.trimmed().replace(".",""));
} }
} }
@ -759,14 +805,10 @@ static void optimizeHtml(QDomDocument& doc
foreach (QString pair, styles) { foreach (QString pair, styles) {
pair.replace(" ",""); pair.replace(" ","");
if (!pair.isEmpty()) { if (!pair.isEmpty()) {
QStringList* stylesListItem = stylesList.value(pair); QStringList& stylesListItem = stylesList[pair];
if(!stylesListItem){
// If value doesn't exist create it
stylesListItem = new QStringList();
stylesList.insert(pair, stylesListItem);
}
//Add the new class to this value //Add the new class to this value
stylesListItem->push_back(className); stylesListItem.push_back(className);
} }
} }
} }
@ -800,7 +842,7 @@ static void optimizeHtml(QDomDocument& doc
* @param desiredMinimumFontSize: Minimum font size. * @param desiredMinimumFontSize: Minimum font size.
*/ */
static void styleCreate(QDomDocument& doc static void styleCreate(QDomDocument& doc
, QHash<QString, QStringList*> stylesList , QHash<QString, QStringList>& stylesList
, unsigned int flag , unsigned int flag
, qreal bglum , qreal bglum
, qreal desiredContrast , qreal desiredContrast
@ -840,12 +882,12 @@ static void styleCreate(QDomDocument& doc
QString style = ""; QString style = "";
QHashIterator<QString, QStringList*> it(stylesList); QHashIterator<QString, QStringList> it(stylesList);
while(it.hasNext()) { while(it.hasNext()) {
it.next(); it.next();
QStringList* classUsingIt = it.value(); const QStringList& classUsingIt ( it.value()) ;
bool first = true; bool first = true;
foreach(QString className, *classUsingIt) { foreach(QString className, classUsingIt) {
if (!className.trimmed().isEmpty()) { if (!className.trimmed().isEmpty()) {
style += QString(first?".":",.") + className;// + " "; style += QString(first?".":",.") + className;// + " ";
first = false; first = false;
@ -961,7 +1003,8 @@ void RsHtml::optimizeHtml(QString &text, unsigned int flag /*= 0*/
} }
QDomElement body = doc.documentElement(); QDomElement body = doc.documentElement();
QHash<QString, QStringList*> stylesList;
QHash<QString, QStringList> stylesList;
QHash<QString, QString> knownStyle; QHash<QString, QString> knownStyle;
::optimizeHtml(doc, body, stylesList, knownStyle); ::optimizeHtml(doc, body, stylesList, knownStyle);

View File

@ -85,12 +85,9 @@ int main(int argc, char **argv)
args >> parameter("docroot", docroot, "path", "Serve static files from this path.", false); args >> parameter("docroot", docroot, "path", "Serve static files from this path.", false);
// unfinished // unfinished
//args >> parameter("http-listen", listenAddress, "ipv6 address", "Listen only on the specified address.", false); //args >> parameter("http-listen", listenAddress, "ipv6 address", "Listen only on the specified address.", false);
args >> option("http-allow-all", allowAllIps, "allow connections from all IP adresses (default= localhost only)"); args >> option("http-allow-all", allowAllIps, "allow connections from all IP adresses (default= localhost only)");
#ifdef __APPLE__
args >> help('h',"help","Display this Help"); args >> help('h',"help","Display this Help");
#else
args >> help();
#endif
if (args.helpRequested()) if (args.helpRequested())
{ {
std::cerr << args.usage() << std::endl; std::cerr << args.usage() << std::endl;