Merge remote-tracking branch 'remotes/retroshare/master' into feature/msys2enhancements

This commit is contained in:
hunbernd 2020-06-19 22:48:43 +02:00
commit a5d23d0b3f
90 changed files with 2773 additions and 1593 deletions

View File

@ -1424,9 +1424,15 @@ int p3FileDatabase::SearchBoolExp(RsRegularExpression::Expression *exp, std::lis
return !results.empty() ;
}
bool p3FileDatabase::search(const RsFileHash &hash, FileSearchFlags hintflags, FileInfo &info) const
bool p3FileDatabase::search(
const RsFileHash &hash, FileSearchFlags hintflags, FileInfo &info) const
{
RS_STACK_MUTEX(mFLSMtx) ;
RS_STACK_MUTEX(mFLSMtx);
if( (hintflags & RS_FILE_HINTS_EXTRA) &&
mExtraFiles->search(hash, hintflags, info) )
return true;
if(hintflags & RS_FILE_HINTS_LOCAL)
{

View File

@ -4,7 +4,7 @@
* libretroshare: retroshare core library *
* *
* Copyright (C) 2008 Robert Fernie <retroshare@lunamutt.com> *
* Copyright (C) 2018-2019 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2018-2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -21,6 +21,9 @@
* *
*******************************************************************************/
#include <limits>
#include <system_error>
#ifdef WINDOWS_SYS
#include "util/rswin.h"
#endif
@ -245,12 +248,8 @@ bool ftExtraList::cleanupOldFiles()
/* remove items */
for(std::list<RsFileHash>::iterator rit = toRemove.begin(); rit != toRemove.end(); ++rit)
{
if (mFiles.end() != (it = mFiles.find(*rit)))
{
cleanupEntry(it->second.info.path, it->second.info.transfer_info_flags);
mFiles.erase(it);
}
mHashOfHash.erase(makeEncryptedHash(*rit)) ;
if (mFiles.end() != (it = mFiles.find(*rit))) mFiles.erase(it);
mHashOfHash.erase(makeEncryptedHash(*rit));
}
IndicateConfigChanged();
@ -258,46 +257,39 @@ bool ftExtraList::cleanupOldFiles()
return true;
}
bool ftExtraList::cleanupEntry(std::string /*path*/, TransferRequestFlags /*flags*/)
{
// if (flags & RS_FILE_CONFIG_CLEANUP_DELETE)
// {
// /* Delete the file? - not yet! */
// }
return true;
}
/***
* Hash file, and add to the files,
* file is removed after period.
**/
bool ftExtraList::hashExtraFile(
std::string path, uint32_t period, TransferRequestFlags flags )
{
#ifdef DEBUG_ELIST
std::cerr << "ftExtraList::hashExtraFile() path: " << path;
std::cerr << " period: " << period;
std::cerr << " flags: " << flags;
constexpr rstime_t max_int = std::numeric_limits<int>::max();
const rstime_t now = time(nullptr);
const rstime_t timeOut = now + period;
std::cerr << std::endl;
#endif
auto failure = [](std::string errMsg)
if(timeOut > max_int)
{
RsErr() << __PRETTY_FUNCTION__ << " " << errMsg << std::endl;
/* Under the hood period is stored as int FileInfo::age so we do this
* check here to detect 2038 year problem
* https://en.wikipedia.org/wiki/Year_2038_problem */
RsErr() << __PRETTY_FUNCTION__ << " period: " << period << " > "
<< max_int - now << std::errc::value_too_large << std::endl;
return false;
};
}
if(!RsDirUtil::fileExists(path))
return failure("file: " + path + "not found");
{
RsErr() << __PRETTY_FUNCTION__ << " path: " << path
<< std::errc::no_such_file_or_directory << std::endl;
return false;
}
if(RsDirUtil::checkDirectory(path))
return failure("Cannot add a directory: " + path + "as extra file");
{
RsErr() << __PRETTY_FUNCTION__ << " path: " << path
<< std::errc::is_a_directory << std::endl;
return false;
}
FileDetails details(path, period, flags);
details.info.age = static_cast<int>(time(nullptr) + period);
details.info.age = static_cast<int>(timeOut);
{
RS_STACK_MUTEX(extMutex);
@ -492,8 +484,7 @@ bool ftExtraList::loadList(std::list<RsItem *>& load)
if (ts > (rstime_t)fi->file.age)
{
/* to old */
cleanupEntry(fi->file.path, TransferRequestFlags(fi->flags));
/* too old */
delete (*it);
continue ;
}

View File

@ -60,7 +60,7 @@
#include "pqi/p3cfgmgr.h"
#include "util/rstime.h"
class FileDetails
class RS_DEPRECATED_FOR(FileInfo) FileDetails
{
public:
FileDetails()
@ -130,7 +130,11 @@ public:
* file is removed after period.
**/
bool hashExtraFile(std::string path, uint32_t period, TransferRequestFlags flags);
/**
* Hash file, and add to the files, file is removed after period.
*/
bool hashExtraFile(
std::string path, uint32_t period, TransferRequestFlags flags );
bool hashExtraFileDone(std::string path, FileInfo &info);
/***
@ -165,7 +169,6 @@ private:
/* Worker Functions */
void hashAFile();
bool cleanupOldFiles();
bool cleanupEntry(std::string path, TransferRequestFlags flags);
mutable RsMutex extMutex;

View File

@ -22,6 +22,8 @@
#include <algorithm>
#include <iostream>
#include <limits>
#include <system_error>
#include "crypto/chacha20.h"
//const int ftserverzone = 29539;
@ -293,7 +295,8 @@ bool ftServer::getFileData(const RsFileHash& hash, uint64_t offset, uint32_t& re
bool ftServer::alreadyHaveFile(const RsFileHash& hash, FileInfo &info)
{
return mFileDatabase->search(hash, RS_FILE_HINTS_LOCAL, info);
return mFileDatabase->search(
hash, RS_FILE_HINTS_EXTRA | RS_FILE_HINTS_LOCAL, info );
}
bool ftServer::FileRequest(
@ -819,6 +822,14 @@ bool ftServer::ExtraFileRemove(const RsFileHash& hash)
bool ftServer::ExtraFileHash(
std::string localpath, rstime_t period, TransferRequestFlags flags )
{
constexpr rstime_t uintmax = std::numeric_limits<uint32_t>::max();
if(period > uintmax)
{
RsErr() << __PRETTY_FUNCTION__ << " period: " << period << " > "
<< uintmax << std::errc::value_too_large << std::endl;
return false;
}
return mFtExtra->hashExtraFile(
localpath, static_cast<uint32_t>(period), flags );
}

View File

@ -651,6 +651,9 @@ bool GxsSecurity::encrypt(uint8_t *& out, uint32_t &outlen, const uint8_t *in, u
try
{
if(keys.empty())
throw std::runtime_error("EVP_SealInit will not be called with 0 keys. GxsSecurity::encrypt() was called with an empty set of destination keys!") ;
for(uint32_t i=0;i<keys.size();++i)
{
RSA *tmpkey = ::extractPublicKey(keys[i]) ;

View File

@ -110,8 +110,6 @@ const std::string RsGeneralDataService::MSG_META_STATUS = KEY_MSG_STATUS;
const uint32_t RsGeneralDataService::GXS_MAX_ITEM_SIZE = 1572864; // 1.5 Mbytes
static const uint32_t CACHE_ENTRY_GRACE_PERIOD = 600 ; // 10 minutes
static int addColumn(std::list<std::string> &list, const std::string &attribute)
{
list.push_back(attribute);
@ -123,7 +121,6 @@ RsDataService::RsDataService(const std::string &serviceDir, const std::string &d
: RsGeneralDataService(), mDbMutex("RsDataService"), mServiceDir(serviceDir), mDbName(dbName), mDbPath(mServiceDir + "/" + dbName), mServType(serviceType), mDb(NULL)
{
bool isNewDatabase = !RsDirUtil::fileExists(mDbPath);
mGrpMetaDataCache_ContainsAllDatabase = false ;
mDb = new RetroDb(mDbPath, RetroDb::OPEN_READWRITE_CREATE, key);
@ -488,8 +485,7 @@ bool RsDataService::finishReleaseUpdate(int release, bool result)
RsGxsGrpMetaData* RsDataService::locked_getGrpMeta(RetroCursor &c, int colOffset,bool use_cache)
{
#ifdef RS_DATA_SERVICE_DEBUG
std::cerr << "RsDataService::locked_getGrpMeta()";
std::cerr << std::endl;
std::cerr << "RsDataService::locked_getGrpMeta()" << std::endl;
#endif
bool ok = true;
@ -507,20 +503,13 @@ RsGxsGrpMetaData* RsDataService::locked_getGrpMeta(RetroCursor &c, int colOffset
RsGxsGroupId grpId(tempId) ;
if(use_cache)
{
auto it = mGrpMetaDataCache.find(grpId) ;
if(it != mGrpMetaDataCache.end())
grpMeta = it->second ;
else
{
grpMeta = new RsGxsGrpMetaData();
mGrpMetaDataCache[grpId] = grpMeta ;
}
}
grpMeta = mGrpMetaDataCache.getOrCreateMeta(grpId);
else
grpMeta = new RsGxsGrpMetaData();
if(!grpMeta->mGroupId.isNull()) // the grpMeta is already initialized because it comes from the cache
return grpMeta;
grpMeta->mGroupId = RsGxsGroupId(tempId);
c.getString(mColGrpMeta_NxsIdentity + colOffset, tempId);
grpMeta->mAuthorId = RsGxsId(tempId);
@ -653,24 +642,38 @@ RsNxsGrp* RsDataService::locked_getGroup(RetroCursor &c)
return NULL;
}
RsGxsMsgMetaData* RsDataService::locked_getMsgMeta(RetroCursor &c, int colOffset)
RsGxsMsgMetaData* RsDataService::locked_getMsgMeta(RetroCursor &c, int colOffset,bool use_cache)
{
RsGxsMsgMetaData* msgMeta = new RsGxsMsgMetaData();
bool ok = true;
uint32_t data_len = 0,
offset = 0;
char* data = NULL;
RsGxsGroupId group_id;
RsGxsMessageId msg_id;
std::string gId;
c.getString(mColMsgMeta_GrpId + colOffset, gId);
msgMeta->mGroupId = RsGxsGroupId(gId);
group_id = RsGxsGroupId(gId);
std::string temp;
c.getString(mColMsgMeta_MsgId + colOffset, temp);
msgMeta->mMsgId = RsGxsMessageId(temp);
msg_id = RsGxsMessageId(temp);
// without these, a msg is meaningless
ok &= (!msgMeta->mGroupId.isNull()) && (!msgMeta->mMsgId.isNull());
ok &= (!group_id.isNull()) && (!msg_id.isNull());
RsGxsMsgMetaData* msgMeta = nullptr;
if(use_cache)
msgMeta = mMsgMetaDataCache[group_id].getOrCreateMeta(msg_id);
else
msgMeta = new RsGxsMsgMetaData();
if(!msgMeta->mGroupId.isNull()) // we cannot do that because the cursor needs to advance. Is there a method to skip some data in the db?
return msgMeta;
msgMeta->mGroupId = group_id;
msgMeta->mMsgId = msg_id;
c.getString(mColMsgMeta_OrigMsgId + colOffset, temp);
msgMeta->mOrigMsgId = RsGxsMessageId(temp);
@ -704,7 +707,7 @@ RsGxsMsgMetaData* RsDataService::locked_getMsgMeta(RetroCursor &c, int colOffset
if(ok)
return msgMeta;
else
else if(!use_cache)
delete msgMeta;
return NULL;
@ -834,7 +837,8 @@ int RsDataService::storeMessage(const std::list<RsNxsMsg*>& msg)
// This is needed so that mLastPost is correctly updated in the group meta when it is re-loaded.
locked_clearGrpMetaCache(msgMetaPtr->mGroupId);
mGrpMetaDataCache.clear(msgMetaPtr->mGroupId);
mMsgMetaDataCache[msgMetaPtr->mGroupId].updateMeta(msgMetaPtr->mMsgId,*msgMetaPtr);
}
// finish transaction
@ -926,7 +930,7 @@ int RsDataService::storeGroup(const std::list<RsNxsGrp*>& grp)
cv.put(KEY_GRP_STATUS, (int32_t)grpMetaPtr->mGroupStatus);
cv.put(KEY_GRP_LAST_POST, (int32_t)grpMetaPtr->mLastPost);
locked_updateGrpMetaCache(*grpMetaPtr);
mGrpMetaDataCache.updateMeta(grpMetaPtr->mGroupId,*grpMetaPtr);
if (!mDb->sqlInsert(GRP_TABLE_NAME, "", cv))
{
@ -942,54 +946,6 @@ int RsDataService::storeGroup(const std::list<RsNxsGrp*>& grp)
return ret;
}
void RsDataService::locked_updateGrpMetaCache(const RsGxsGrpMetaData& meta)
{
auto it = mGrpMetaDataCache.find(meta.mGroupId) ;
if(it != mGrpMetaDataCache.end())
*(it->second) = meta ;
else
mGrpMetaDataCache[meta.mGroupId] = new RsGxsGrpMetaData(meta) ;
}
void RsDataService::locked_clearGrpMetaCache(const RsGxsGroupId& gid)
{
rstime_t now = time(NULL) ;
auto it = mGrpMetaDataCache.find(gid) ;
// We dont actually delete the item, because it might be used by a calling client.
// In this case, the memory will not be used for long, so we keep it into a list for a safe amount
// of time and delete it later. Using smart pointers here would be more elegant, but that would need
// to be implemented thread safe, which is difficult in this case.
if(it != mGrpMetaDataCache.end())
{
#ifdef RS_DATA_SERVICE_DEBUG
std::cerr << "(II) moving database cache entry " << (void*)(*it).second << " to dead list." << std::endl;
#endif
mOldCachedItems.push_back(std::make_pair(now,it->second)) ;
mGrpMetaDataCache.erase(it) ;
mGrpMetaDataCache_ContainsAllDatabase = false;
}
// We also take that opportunity to delete old entries.
auto it2(mOldCachedItems.begin());
while(it2!=mOldCachedItems.end() && (*it2).first + CACHE_ENTRY_GRACE_PERIOD < now)
{
#ifdef RS_DATA_SERVICE_DEBUG
std::cerr << "(II) deleting old GXS database cache entry " << (void*)(*it2).second << ", " << now - (*it2).first << " seconds old." << std::endl;
#endif
delete (*it2).second ;
it2 = mOldCachedItems.erase(it2) ;
}
}
int RsDataService::updateGroup(const std::list<RsNxsGrp *> &grp)
{
@ -1058,7 +1014,7 @@ int RsDataService::updateGroup(const std::list<RsNxsGrp *> &grp)
mDb->sqlUpdate(GRP_TABLE_NAME, "grpId='" + grpPtr->grpId.toStdString() + "'", cv);
locked_updateGrpMetaCache(*grpMetaPtr);
mGrpMetaDataCache.updateMeta(grpMetaPtr->mGroupId,*grpMetaPtr);
}
// finish transaction
bool ret = mDb->commitTransaction();
@ -1275,7 +1231,7 @@ void RsDataService::locked_retrieveMessages(RetroCursor *c, std::vector<RsNxsMsg
if(m){
if (metaOffset) {
m->metaData = locked_getMsgMeta(*c, metaOffset);
m->metaData = locked_getMsgMeta(*c, metaOffset,false);
}
msgs.push_back(m);
}
@ -1285,7 +1241,7 @@ void RsDataService::locked_retrieveMessages(RetroCursor *c, std::vector<RsNxsMsg
return;
}
int RsDataService::retrieveGxsMsgMetaData(const GxsMsgReq& reqIds, GxsMsgMetaResult &msgMeta)
int RsDataService::retrieveGxsMsgMetaData(const GxsMsgReq& reqIds, GxsMsgMetaResult& msgMeta)
{
RsStackMutex stack(mDbMutex);
@ -1294,52 +1250,65 @@ int RsDataService::retrieveGxsMsgMetaData(const GxsMsgReq& reqIds, GxsMsgMetaRes
int resultCount = 0;
#endif
GxsMsgReq::const_iterator mit = reqIds.begin();
for(; mit != reqIds.end(); ++mit)
for(auto mit(reqIds.begin()); mit != reqIds.end(); ++mit)
{
const RsGxsGroupId& grpId = mit->first;
const std::set<RsGxsMessageId>& msgIdV = mit->second;
// if vector empty then request all messages
const std::set<RsGxsMessageId>& msgIdV = mit->second;
std::vector<RsGxsMsgMetaData*> metaSet;
if(msgIdV.empty()){
RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, mMsgMetaColumns, KEY_GRP_ID+ "='" + grpId.toStdString() + "'", "");
t_MetaDataCache<RsGxsMessageId,RsGxsMsgMetaData>& cache(mMsgMetaDataCache[grpId]);
if (c)
{
locked_retrieveMsgMeta(c, metaSet);
if(msgIdV.empty())
{
if(cache.isCacheUpToDate())
cache.getFullMetaList(msgMeta[grpId]);
else
{
RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, mMsgMetaColumns, KEY_GRP_ID+ "='" + grpId.toStdString() + "'", "");
if (c)
{
locked_retrieveMsgMetaList(c, msgMeta[grpId]);
cache.setCacheUpToDate(true);
}
delete c;
}
#ifdef RS_DATA_SERVICE_DEBUG_CACHE
std::cerr << mDbName << ": Retrieving (all) Msg metadata grpId=" << grpId << ", " << std::dec << metaSet.size() << " messages" << std::endl;
std::cerr << mDbName << ": Retrieving (all) Msg metadata grpId=" << grpId << ", " << std::dec << metaSet.size() << " messages" << std::endl;
#endif
}
}else{
// request each grp
std::set<RsGxsMessageId>::const_iterator sit = msgIdV.begin();
for(; sit!=msgIdV.end(); ++sit){
const RsGxsMessageId& msgId = *sit;
RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, mMsgMetaColumns, KEY_GRP_ID+ "='" + grpId.toStdString()
+ "' AND " + KEY_MSG_ID + "='" + msgId.toStdString() + "'", "");
if (c)
{
locked_retrieveMsgMeta(c, metaSet);
#ifdef RS_DATA_SERVICE_DEBUG_CACHE
std::cerr << mDbName << ": Retrieving Msg metadata grpId=" << grpId << ", " << std::dec << metaSet.size() << " messages" << std::endl;
#endif
}
}
}
else
{
// request each msg meta
auto& metaSet(msgMeta[grpId]);
#ifdef RS_DATA_SERVICE_DEBUG_TIME
resultCount += metaSet.size();
for(auto sit(msgIdV.begin()); sit!=msgIdV.end(); ++sit)
{
const RsGxsMessageId& msgId = *sit;
RsGxsMsgMetaData *meta = cache.getMeta(msgId);
if(meta)
metaSet.push_back(meta);
else
{
RetroCursor* c = mDb->sqlQuery(MSG_TABLE_NAME, mMsgMetaColumns, KEY_GRP_ID+ "='" + grpId.toStdString() + "' AND " + KEY_MSG_ID + "='" + msgId.toStdString() + "'", "");
c->moveToFirst();
RsGxsMsgMetaData* meta = locked_getMsgMeta(*c, 0,true);
if(meta)
metaSet.push_back(meta);
delete c;
}
}
#ifdef RS_DATA_SERVICE_DEBUG_CACHE
std::cerr << mDbName << ": Retrieving Msg metadata grpId=" << grpId << ", " << std::dec << metaSet.size() << " messages" << std::endl;
#endif
msgMeta[grpId] = metaSet;
}
}
#ifdef RS_DATA_SERVICE_DEBUG_TIME
@ -1350,22 +1319,43 @@ int RsDataService::retrieveGxsMsgMetaData(const GxsMsgReq& reqIds, GxsMsgMetaRes
return 1;
}
void RsDataService::locked_retrieveMsgMeta(RetroCursor *c, std::vector<RsGxsMsgMetaData *> &msgMeta)
void RsDataService::locked_retrieveGrpMetaList(RetroCursor *c, std::map<RsGxsGroupId,RsGxsGrpMetaData *>& grpMeta)
{
if(!c)
{
RsErr() << __PRETTY_FUNCTION__ << ": attempt to retrieve Group Meta data from the DB with null cursor!" << std::endl;
return;
}
if(c)
{
bool valid = c->moveToFirst();
while(valid){
RsGxsMsgMetaData* m = locked_getMsgMeta(*c, 0);
bool valid = c->moveToFirst();
if(m != NULL)
msgMeta.push_back(m);
while(valid)
{
RsGxsGrpMetaData* m = locked_getGrpMeta(*c, 0,true);
valid = c->moveToNext();
}
delete c;
}
if(m)
grpMeta[m->mGroupId] = m;
valid = c->moveToNext();
}
}
void RsDataService::locked_retrieveMsgMetaList(RetroCursor *c, std::vector<const RsGxsMsgMetaData *>& msgMeta)
{
if(!c)
{
RsErr() << __PRETTY_FUNCTION__ << ": attempt to retrieve Msg Meta data from the DB with null cursor!" << std::endl;
return;
}
bool valid = c->moveToFirst();
while(valid){
const RsGxsMsgMetaData* m = locked_getMsgMeta(*c, 0,true);
if(m != NULL)
msgMeta.push_back(m);
valid = c->moveToNext();
}
}
int RsDataService::retrieveGxsGrpMetaData(RsGxsGrpMetaTemporaryMap& grp)
@ -1385,13 +1375,13 @@ int RsDataService::retrieveGxsGrpMetaData(RsGxsGrpMetaTemporaryMap& grp)
if(grp.empty())
{
if(mGrpMetaDataCache_ContainsAllDatabase) // grab all the stash from the cache, so as to avoid decryption costs.
if(mGrpMetaDataCache.isCacheUpToDate()) // grab all the stash from the cache, so as to avoid decryption costs.
{
#ifdef RS_DATA_SERVICE_DEBUG_CACHE
std::cerr << (void*)this << ": RsDataService::retrieveGxsGrpMetaData() retrieving all from cache!" << std::endl;
#endif
grp = mGrpMetaDataCache ;
mGrpMetaDataCache.getFullMetaList(grp) ;
}
else
{
@ -1402,93 +1392,103 @@ int RsDataService::retrieveGxsGrpMetaData(RsGxsGrpMetaTemporaryMap& grp)
RetroCursor* c = mDb->sqlQuery(GRP_TABLE_NAME, mGrpMetaColumns, "", "");
if(c)
if(c)
{
bool valid = c->moveToFirst();
locked_retrieveGrpMetaList(c,grp);
while(valid)
{
RsGxsGrpMetaData* g = locked_getGrpMeta(*c, 0,true);
if(g)
{
grp[g->mGroupId] = g;
#ifdef RS_DATA_SERVICE_DEBUG_CACHE
std::cerr << (void *)this << " " << mDbName << ": Retrieving (all) Grp metadata grpId=" << g->mGroupId << std::endl;
#endif
}
valid = c->moveToNext();
#ifdef RS_DATA_SERVICE_DEBUG_TIME
++resultCount;
#endif
}
delete c;
mGrpMetaDataCache.setCacheUpToDate(true);
}
delete c;
#ifdef RS_DATA_SERVICE_DEBUG_TIME
resultCount += grp.size();
#endif
mGrpMetaDataCache_ContainsAllDatabase = true ;
// if(c)
// {
// bool valid = c->moveToFirst();
//
// while(valid)
// {
// RsGxsGrpMetaData* g = locked_getGrpMeta(*c, 0,true);
//
// if(g)
// {
// grp[g->mGroupId] = g;
//#ifdef RS_DATA_SERVICE_DEBUG_CACHE
// std::cerr << (void *)this << " " << mDbName << ": Retrieving (all) Grp metadata grpId=" << g->mGroupId << std::endl;
//#endif
// }
// valid = c->moveToNext();
//
// }
// delete c;
// }
}
}
else
{
std::map<RsGxsGroupId, RsGxsGrpMetaData *>::iterator mit = grp.begin();
{
for(auto mit(grp.begin()); mit != grp.end(); ++mit)
{
RsGxsGrpMetaData *meta = mGrpMetaDataCache.getMeta(mit->first) ;
for(; mit != grp.end(); ++mit)
{
std::map<RsGxsGroupId, RsGxsGrpMetaData*>::const_iterator itt = mGrpMetaDataCache.find(mit->first) ;
if(itt != mGrpMetaDataCache.end())
{
if(meta)
grp[mit->first] = meta;
else
{
#ifdef RS_DATA_SERVICE_DEBUG_CACHE
std::cerr << mDbName << ": Retrieving Grp metadata grpId=" << mit->first << " from cache!" << std::endl;
#endif
grp[mit->first] = itt->second ;
}
else
{
#ifdef RS_DATA_SERVICE_DEBUG_CACHE
std::cerr << mDbName << ": Retrieving Grp metadata grpId=" << mit->first ;
std::cerr << mDbName << ": Retrieving Grp metadata grpId=" << mit->first ;
#endif
const RsGxsGroupId& grpId = mit->first;
RetroCursor* c = mDb->sqlQuery(GRP_TABLE_NAME, mGrpMetaColumns, "grpId='" + grpId.toStdString() + "'", "");
const RsGxsGroupId& grpId = mit->first;
RetroCursor* c = mDb->sqlQuery(GRP_TABLE_NAME, mGrpMetaColumns, "grpId='" + grpId.toStdString() + "'", "");
if(c)
{
bool valid = c->moveToFirst();
c->moveToFirst();
RsGxsGrpMetaData* meta = locked_getGrpMeta(*c, 0,true);
#ifdef RS_DATA_SERVICE_DEBUG_CACHE
if(!valid)
std::cerr << " Empty query! GrpId " << grpId << " is not in database" << std::endl;
#endif
while(valid)
{
RsGxsGrpMetaData* g = locked_getGrpMeta(*c, 0,true);
if(g)
{
grp[g->mGroupId] = g;
#ifdef RS_DATA_SERVICE_DEBUG_CACHE
std::cerr << ". Got it. Updating cache." << std::endl;
#endif
}
valid = c->moveToNext();
if(meta)
grp[mit->first] = meta;
#ifdef RS_DATA_SERVICE_DEBUG_TIME
++resultCount;
++resultCount;
#endif
}
delete c;
}
#ifdef RS_DATA_SERVICE_DEBUG_CACHE
else
std::cerr << ". not found!" << std::endl;
#endif
}
}
}
delete c;
// if(c)
// {
// bool valid = c->moveToFirst();
//
//#ifdef RS_DATA_SERVICE_DEBUG_CACHE
// if(!valid)
// std::cerr << " Empty query! GrpId " << grpId << " is not in database" << std::endl;
//#endif
// while(valid)
// {
// RsGxsGrpMetaData* g = locked_getGrpMeta(*c, 0,true);
//
// if(g)
// {
// grp[g->mGroupId] = g;
//#ifdef RS_DATA_SERVICE_DEBUG_CACHE
// std::cerr << ". Got it. Updating cache." << std::endl;
//#endif
// }
// valid = c->moveToNext();
//
//#ifdef RS_DATA_SERVICE_DEBUG_TIME
// ++resultCount;
//#endif
// }
// delete c;
// }
#ifdef RS_DATA_SERVICE_DEBUG_CACHE
else
std::cerr << ". not found!" << std::endl;
#endif
}
}
}
#ifdef RS_DATA_SERVICE_DEBUG_TIME
std::cerr << "RsDataService::retrieveGxsGrpMetaData() " << mDbName << ", Requests: " << requestedGroups << ", Results: " << resultCount << ", Time: " << timer.duration() << std::endl;
@ -1525,35 +1525,37 @@ int RsDataService::resetDataStore()
return 1;
}
int RsDataService::updateGroupMetaData(GrpLocMetaData &meta)
int RsDataService::updateGroupMetaData(const GrpLocMetaData& meta)
{
#ifdef RS_DATA_SERVICE_DEBUG_CACHE
std::cerr << (void*)this << ": Updating Grp Meta data: grpId = " << meta.grpId << std::endl;
#endif
RsStackMutex stack(mDbMutex);
RsGxsGroupId& grpId = meta.grpId;
const RsGxsGroupId& grpId = meta.grpId;
#ifdef RS_DATA_SERVICE_DEBUG_CACHE
std::cerr << (void*)this << ": erasing old entry from cache." << std::endl;
#endif
locked_clearGrpMetaCache(meta.grpId);
mGrpMetaDataCache.clear(meta.grpId);
return mDb->sqlUpdate(GRP_TABLE_NAME, KEY_GRP_ID+ "='" + grpId.toStdString() + "'", meta.val) ? 1 : 0;
}
int RsDataService::updateMessageMetaData(MsgLocMetaData &metaData)
int RsDataService::updateMessageMetaData(const MsgLocMetaData& metaData)
{
#ifdef RS_DATA_SERVICE_DEBUG_CACHE
std::cerr << (void*)this << ": Updating Msg Meta data: grpId = " << metaData.msgId.first << " msgId = " << metaData.msgId.second << std::endl;
#endif
RsStackMutex stack(mDbMutex);
RsGxsGroupId& grpId = metaData.msgId.first;
RsGxsMessageId& msgId = metaData.msgId.second;
return mDb->sqlUpdate(MSG_TABLE_NAME, KEY_GRP_ID+ "='" + grpId.toStdString()
+ "' AND " + KEY_MSG_ID + "='" + msgId.toStdString() + "'", metaData.val) ? 1 : 0;
const RsGxsGroupId& grpId = metaData.msgId.first;
const RsGxsMessageId& msgId = metaData.msgId.second;
mMsgMetaDataCache[grpId].clear(msgId);
return mDb->sqlUpdate(MSG_TABLE_NAME, KEY_GRP_ID+ "='" + grpId.toStdString() + "' AND " + KEY_MSG_ID + "='" + msgId.toStdString() + "'", metaData.val) ? 1 : 0;
}
int RsDataService::removeMsgs(const GxsMsgReq& msgIds)
@ -1678,13 +1680,13 @@ bool RsDataService::locked_removeMessageEntries(const GxsMsgReq& msgIds)
{
const RsGxsGroupId& grpId = mit->first;
const std::set<RsGxsMessageId>& msgsV = mit->second;
std::set<RsGxsMessageId>::const_iterator vit = msgsV.begin();
auto& cache(mMsgMetaDataCache[grpId]);
for(; vit != msgsV.end(); ++vit)
for(auto& msgId:msgsV)
{
const RsGxsMessageId& msgId = *vit;
mDb->sqlDelete(MSG_TABLE_NAME, KEY_GRP_ID+ "='" + grpId.toStdString()
+ "' AND " + KEY_MSG_ID + "='" + msgId.toStdString() + "'", "");
mDb->sqlDelete(MSG_TABLE_NAME, KEY_GRP_ID+ "='" + grpId.toStdString() + "' AND " + KEY_MSG_ID + "='" + msgId.toStdString() + "'", "");
cache.clear(msgId);
}
}
@ -1698,23 +1700,18 @@ bool RsDataService::locked_removeGroupEntries(const std::vector<RsGxsGroupId>& g
// start a transaction
bool ret = mDb->beginTransaction();
std::vector<RsGxsGroupId>::const_iterator vit = grpIds.begin();
for(; vit != grpIds.end(); ++vit)
for(auto grpId:grpIds)
{
const RsGxsGroupId& grpId = *vit;
mDb->sqlDelete(GRP_TABLE_NAME, KEY_GRP_ID+ "='" + grpId.toStdString() + "'", "");
// also remove the group meta from cache.
locked_clearGrpMetaCache(*vit) ;
mGrpMetaDataCache.clear(grpId) ;
}
ret &= mDb->commitTransaction();
mGrpMetaDataCache_ContainsAllDatabase = false ;
return ret;
}
uint32_t RsDataService::cacheSize() const {
return 0;
}
@ -1724,3 +1721,38 @@ int RsDataService::setCacheSize(uint32_t /* size */)
return 0;
}
void RsDataService::debug_printCacheSize() const
{
uint32_t nb_items,nb_items_on_deadlist;
uint64_t total_size,total_size_of_deadlist;
mGrpMetaDataCache.debug_computeSize(nb_items, nb_items_on_deadlist, total_size,total_size_of_deadlist);
RsDbg() << "Cache size: " << std::endl;
RsDbg() << " Groups: " << " total: " << nb_items << " (dead: " << nb_items_on_deadlist << "), size: " << total_size << " (Dead: " << total_size_of_deadlist << ")" << std::endl;
nb_items = 0,nb_items_on_deadlist = 0;
total_size = 0,total_size_of_deadlist = 0;
for(auto it:mMsgMetaDataCache)
{
uint32_t tmp_nb_items,tmp_nb_items_on_deadlist;
uint64_t tmp_total_size,tmp_total_size_of_deadlist;
it.second.debug_computeSize(tmp_nb_items, tmp_nb_items_on_deadlist, tmp_total_size,tmp_total_size_of_deadlist);
nb_items += tmp_nb_items;
nb_items_on_deadlist += tmp_nb_items_on_deadlist;
total_size += tmp_total_size;
total_size_of_deadlist += tmp_total_size_of_deadlist;
}
RsDbg() << " Msgs: " << " total: " << nb_items << " (dead: " << nb_items_on_deadlist << "), size: " << total_size << " (Dead: " << total_size_of_deadlist << ")" << std::endl;
}

View File

@ -35,6 +35,116 @@ public:
ContentValue cv;
};
template<class ID, class MetaDataClass> class t_MetaDataCache
{
public:
t_MetaDataCache() : mCache_ContainsAllMetas(false) {}
bool isCacheUpToDate() const { return mCache_ContainsAllMetas ; }
void setCacheUpToDate(bool b) { mCache_ContainsAllMetas = b; }
void getFullMetaList(std::map<ID,MetaDataClass*>& mp) const { mp = mMetas ; }
void getFullMetaList(std::vector<const MetaDataClass*>& mp) const { for(auto& m:mMetas) mp.push_back(m.second) ; }
MetaDataClass *getMeta(const ID& id)
{
auto itt = mMetas.find(id);
if(itt != mMetas.end())
return itt->second ;
else
return NULL;
}
MetaDataClass *getOrCreateMeta(const ID& id)
{
MetaDataClass *meta = nullptr;
auto it = mMetas.find(id) ;
if(it != mMetas.end())
{
#ifdef RS_DATA_SERVICE_DEBUG
RsDbg() << __PRETTY_FUNCTION__ << ": getting group meta " << grpId << " from cache." << std::endl;
#endif
meta = it->second ;
}
else
{
#ifdef RS_DATA_SERVICE_DEBUG
RsDbg() << __PRETTY_FUNCTION__ << ": group meta " << grpId << " not in cache. Loading it from DB..." << std::endl;
#endif
meta = new MetaDataClass();
mMetas[id] = meta ;
}
return meta;
}
void updateMeta(const ID& id,const MetaDataClass& meta)
{
auto it = mMetas.find(id) ;
if(it != mMetas.end())
*(it->second) = meta ;
else
mMetas[id] = new MetaDataClass(meta) ;
}
void clear(const ID& id)
{
rstime_t now = time(NULL) ;
auto it = mMetas.find(id) ;
// We dont actually delete the item, because it might be used by a calling client.
// In this case, the memory will not be used for long, so we keep it into a list for a safe amount
// of time and delete it later. Using smart pointers here would be more elegant, but that would need
// to be implemented thread safe, which is difficult in this case.
if(it != mMetas.end())
{
#ifdef RS_DATA_SERVICE_DEBUG
std::cerr << "(II) moving database cache entry " << (void*)(*it).second << " to dead list." << std::endl;
#endif
mOldCachedItems.push_back(std::make_pair(now,it->second)) ;
mMetas.erase(it) ;
mCache_ContainsAllMetas = false;
}
// We also take that opportunity to delete old entries.
auto it2(mOldCachedItems.begin());
while(it2!=mOldCachedItems.end() && (*it2).first + CACHE_ENTRY_GRACE_PERIOD < now)
{
#ifdef RS_DATA_SERVICE_DEBUG
std::cerr << "(II) deleting old GXS database cache entry " << (void*)(*it2).second << ", " << now - (*it2).first << " seconds old." << std::endl;
#endif
delete (*it2).second ;
it2 = mOldCachedItems.erase(it2) ;
}
}
void debug_computeSize(uint32_t& nb_items, uint32_t& nb_items_on_deadlist, uint64_t& total_size,uint64_t& total_size_of_deadlist) const
{
nb_items = mMetas.size();
nb_items_on_deadlist = mOldCachedItems.size();
total_size = 0;
total_size_of_deadlist = 0;
for(auto it:mMetas) total_size += it.second->serial_size();
for(auto it:mOldCachedItems) total_size_of_deadlist += it.second->serial_size();
}
private:
std::map<ID,MetaDataClass*> mMetas;
std::list<std::pair<rstime_t,MetaDataClass*> > mOldCachedItems ; // dead list, where items get deleted after being unused for a while. This is due to not using smart ptrs.
static const uint32_t CACHE_ENTRY_GRACE_PERIOD = 600 ; // Unused items are deleted 10 minutes after last usage.
bool mCache_ContainsAllMetas ;
};
class RsDataService : public RsGeneralDataService
{
public:
@ -147,13 +257,13 @@ public:
* @param metaData The meta data item to update
* @return error code
*/
int updateMessageMetaData(MsgLocMetaData& metaData);
int updateMessageMetaData(const MsgLocMetaData& metaData);
/*!
* @param metaData The meta data item to update
* @return error code
*/
int updateGroupMetaData(GrpLocMetaData& meta);
int updateGroupMetaData(const GrpLocMetaData &meta);
/*!
* Completely clear out data stored in
@ -174,6 +284,8 @@ public:
int updateGroupKeys(const RsGxsGroupId& grpId,const RsTlvSecurityKeySet& keys, uint32_t subscribe_flags) ;
void debug_printCacheSize() const;
private:
/*!
@ -194,15 +306,22 @@ private:
/*!
* Retrieves all the msg meta results from a cursor
* @param c cursor to result set
* @param metaSet message metadata retrieved from cursor are stored here
* @param msgMeta message metadata retrieved from cursor are stored here
*/
void locked_retrieveMsgMeta(RetroCursor* c, std::vector<RsGxsMsgMetaData*>& msgMeta);
void locked_retrieveMsgMetaList(RetroCursor* c, std::vector<const RsGxsMsgMetaData*>& msgMeta);
/*!
* Retrieves all the grp meta results from a cursor
* @param c cursor to result set
* @param grpMeta group metadata retrieved from cursor are stored here
*/
void locked_retrieveGrpMetaList(RetroCursor *c, std::map<RsGxsGroupId,RsGxsGrpMetaData *>& grpMeta);
/*!
* extracts a msg meta item from a cursor at its
* current position
*/
RsGxsMsgMetaData* locked_getMsgMeta(RetroCursor& c, int colOffset);
RsGxsMsgMetaData* locked_getMsgMeta(RetroCursor& c, int colOffset, bool use_cache);
/*!
* extracts a grp meta item from a cursor at its
@ -348,10 +467,8 @@ private:
void locked_clearGrpMetaCache(const RsGxsGroupId& gid);
void locked_updateGrpMetaCache(const RsGxsGrpMetaData& meta);
std::map<RsGxsGroupId,RsGxsGrpMetaData*> mGrpMetaDataCache ;
std::list<std::pair<rstime_t,RsGxsGrpMetaData*> > mOldCachedItems ;
bool mGrpMetaDataCache_ContainsAllDatabase ;
t_MetaDataCache<RsGxsGroupId,RsGxsGrpMetaData> mGrpMetaDataCache;
std::map<RsGxsGroupId,t_MetaDataCache<RsGxsMessageId,RsGxsMsgMetaData> > mMsgMetaDataCache;
};
#endif // RSDATASERVICE_H

View File

@ -239,12 +239,12 @@ public:
/*!
* @param metaData
*/
virtual int updateMessageMetaData(MsgLocMetaData& metaData) = 0;
virtual int updateMessageMetaData(const MsgLocMetaData& metaData) = 0;
/*!
* @param metaData
*/
virtual int updateGroupMetaData(GrpLocMetaData& meta) = 0;
virtual int updateGroupMetaData(const GrpLocMetaData& meta) = 0;
virtual int updateGroupKeys(const RsGxsGroupId& grpId,const RsTlvSecurityKeySet& keys,uint32_t subscribed_flags) = 0 ;

View File

@ -1274,18 +1274,18 @@ bool RsGenExchange::getMsgMeta(const uint32_t &token,
for(; mit != result.end(); ++mit)
{
std::vector<RsGxsMsgMetaData*>& metaV = mit->second;
std::vector<const RsGxsMsgMetaData*>& metaV = mit->second;
std::vector<RsMsgMetaData>& msgInfoV = msgInfo[mit->first];
std::vector<RsGxsMsgMetaData*>::iterator vit = metaV.begin();
std::vector<const RsGxsMsgMetaData*>::iterator vit = metaV.begin();
RsMsgMetaData meta;
for(; vit != metaV.end(); ++vit)
{
RsGxsMsgMetaData& m = *(*vit);
const RsGxsMsgMetaData& m = *(*vit);
meta = m;
msgInfoV.push_back(meta);
delete *vit;
//delete *vit;
}
metaV.clear();
}
@ -1302,18 +1302,18 @@ bool RsGenExchange::getMsgRelatedMeta(const uint32_t &token, GxsMsgRelatedMetaMa
for(; mit != result.end(); ++mit)
{
std::vector<RsGxsMsgMetaData*>& metaV = mit->second;
std::vector<const RsGxsMsgMetaData*>& metaV = mit->second;
std::vector<RsMsgMetaData>& msgInfoV = msgMeta[mit->first];
std::vector<RsGxsMsgMetaData*>::iterator vit = metaV.begin();
std::vector<const RsGxsMsgMetaData*>::iterator vit = metaV.begin();
RsMsgMetaData meta;
for(; vit != metaV.end(); ++vit)
{
RsGxsMsgMetaData& m = *(*vit);
const RsGxsMsgMetaData& m = *(*vit);
meta = m;
msgInfoV.push_back(meta);
delete *vit;
//delete *vit;
}
metaV.clear();
}
@ -2016,15 +2016,15 @@ void RsGenExchange::processMsgMetaChanges()
if(mit != result.end())
{
std::vector<RsGxsMsgMetaData*>& msgMetaV = mit->second;
std::vector<const RsGxsMsgMetaData*>& msgMetaV = mit->second;
if(!msgMetaV.empty())
{
RsGxsMsgMetaData* meta = *(msgMetaV.begin());
const RsGxsMsgMetaData* meta = *(msgMetaV.begin());
value = (meta->mMsgStatus & ~mask) | (mask & value);
changed = (static_cast<int64_t>(meta->mMsgStatus) != value);
m.val.put(RsGeneralDataService::MSG_META_STATUS, value);
delete meta;
//delete meta;
ok = true;
}
}

View File

@ -29,8 +29,8 @@
/* data types used throughout Gxs from netservice to genexchange */
typedef std::map<RsGxsGroupId, std::vector<RsGxsMsgMetaData*> > GxsMsgMetaResult;
typedef std::map<RsGxsGrpMsgIdPair, std::vector<RsGxsMsgMetaData*> > MsgRelatedMetaResult;
typedef std::map<RsGxsGroupId, std::vector<const RsGxsMsgMetaData*> > GxsMsgMetaResult;
typedef std::map<RsGxsGrpMsgIdPair, std::vector<const RsGxsMsgMetaData*> > MsgRelatedMetaResult;
// Default values that are used throughout GXS code

View File

@ -209,7 +209,7 @@ RsGxsMsgMetaData::~RsGxsMsgMetaData(){
return;
}
uint32_t RsGxsMsgMetaData::serial_size()
uint32_t RsGxsMsgMetaData::serial_size() const
{
uint32_t s = 8; // header size

View File

@ -48,6 +48,7 @@ public:
bool deserialise(void *data, uint32_t &pktsize);
bool serialise(void* data, uint32_t &pktsize, uint32_t api_version);
uint32_t serial_size(uint32_t api_version) const;
uint32_t serial_size() const { return serial_size(RS_GXS_GRP_META_DATA_CURRENT_API_VERSION); }
void clear();
void operator =(const RsGroupMetaData& rMeta);
@ -94,7 +95,7 @@ public:
~RsGxsMsgMetaData();
bool deserialise(void *data, uint32_t *size);
bool serialise(void* data, uint32_t *size);
uint32_t serial_size();
uint32_t serial_size() const;
void clear();
void operator =(const RsMsgMetaData& rMeta);

View File

@ -1028,7 +1028,7 @@ bool RsGxsDataAccess::getMsgMetaDataList( const GxsMsgReq& msgIds, const RsTokRe
//auto& filter( metaFilter[grpId] ); // does the initialization of metaFilter[grpId] and avoids further O(log(n)) calls
std::vector<RsGxsMsgMetaData*>& metaV = meta_it->second;
std::vector<const RsGxsMsgMetaData*>& metaV = meta_it->second;
if (onlyLatestMsgs) // if we only consider latest messages, we need to first filter out messages with "children"
{
@ -1062,7 +1062,7 @@ bool RsGxsDataAccess::getMsgMetaDataList( const GxsMsgReq& msgIds, const RsTokRe
for(uint32_t i=0;i<metaV.size();++i)
if(!keep[i])
{
delete metaV[i];
//delete metaV[i];
metaV[i] = nullptr;
}
}
@ -1122,20 +1122,20 @@ bool RsGxsDataAccess::getMsgMetaDataList( const GxsMsgReq& msgIds, const RsTokRe
for(uint32_t i=0;i<metaV.size();++i)
if(metaV[i] != nullptr)
{
RsGxsMsgMetaData* msgMeta = metaV[i];
const RsGxsMsgMetaData* msgMeta = metaV[i];
bool add = false;
/* if we are grabbing thread Head... then parentId == empty. */
if (onlyThreadHeadMsgs && !msgMeta->mParentId.isNull())
{
delete msgMeta;
//delete msgMeta;
metaV[i] = nullptr;
continue;
}
if (onlyOrigMsgs && !msgMeta->mOrigMsgId.isNull() && msgMeta->mMsgId != msgMeta->mOrigMsgId)
{
delete msgMeta;
//delete msgMeta;
metaV[i] = nullptr;
continue;
}
@ -1187,7 +1187,7 @@ bool RsGxsDataAccess::getMsgIdList( const GxsMsgReq& msgIds, const RsTokReqOptio
}
// delete meta data
cleanseMsgMetaMap(result);
//cleanseMsgMetaMap(result);
return true;
}
@ -1296,9 +1296,7 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req)
return true;
}
std::vector<RsGxsGrpMsgIdPair>::iterator vit_msgIds = req->mMsgIds.begin();
for(; vit_msgIds != req->mMsgIds.end(); ++vit_msgIds)
for(auto vit_msgIds(req->mMsgIds.begin()); vit_msgIds != req->mMsgIds.end(); ++vit_msgIds)
{
MsgMetaFilter filterMap;
@ -1310,8 +1308,8 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req)
GxsMsgReq msgIds;
msgIds.insert(std::make_pair(grpMsgIdPair.first, std::set<RsGxsMessageId>()));
mDataStore->retrieveGxsMsgMetaData(msgIds, result);
std::vector<RsGxsMsgMetaData*>& metaV = result[grpMsgIdPair.first];
std::vector<RsGxsMsgMetaData*>::iterator vit_meta;
std::vector<const RsGxsMsgMetaData*>& metaV = result[grpMsgIdPair.first];
std::vector<const RsGxsMsgMetaData*>::iterator vit_meta;
// msg id to relate to
const RsGxsMessageId& msgId = grpMsgIdPair.second;
@ -1319,10 +1317,11 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req)
std::set<RsGxsMessageId> outMsgIds;
RsGxsMsgMetaData* origMeta = nullptr;
const RsGxsMsgMetaData* origMeta = nullptr;
for(vit_meta = metaV.begin(); vit_meta != metaV.end(); ++vit_meta)
{
RsGxsMsgMetaData* meta = *vit_meta;
const RsGxsMsgMetaData* meta = *vit_meta;
if(msgId == meta->mMsgId)
{
@ -1337,12 +1336,11 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req)
RsDbg() << "RsGxsDataAccess::getMsgRelatedInfo(): Cannot find meta of msgId (to relate to)!"
<< std::endl;
#endif
cleanseMsgMetaMap(result);
return false;
}
const RsGxsMessageId& origMsgId = origMeta->mOrigMsgId;
std::map<RsGxsMessageId, RsGxsMsgMetaData*>& metaMap = filterMap[grpId];
std::map<RsGxsMessageId, const RsGxsMsgMetaData*>& metaMap = filterMap[grpId];
if (onlyLatestMsgs)
{
@ -1354,7 +1352,7 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req)
for(vit_meta = metaV.begin(); vit_meta != metaV.end(); ++vit_meta)
{
RsGxsMsgMetaData* meta = *vit_meta;
const RsGxsMsgMetaData* meta = *vit_meta;
// skip msgs that aren't children.
if (onlyChildMsgs)
@ -1422,11 +1420,11 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req)
/* first guess is potentially better than Orig (can't be worse!) */
rstime_t latestTs = 0;
RsGxsMessageId latestMsgId;
RsGxsMsgMetaData* latestMeta=nullptr;
const RsGxsMsgMetaData* latestMeta=nullptr;
for(vit_meta = metaV.begin(); vit_meta != metaV.end(); ++vit_meta)
{
RsGxsMsgMetaData* meta = *vit_meta;
const RsGxsMsgMetaData* meta = *vit_meta;
if (meta->mOrigMsgId == origMsgId)
{
@ -1446,7 +1444,7 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req)
{
for(vit_meta = metaV.begin(); vit_meta != metaV.end(); ++vit_meta)
{
RsGxsMsgMetaData* meta = *vit_meta;
const RsGxsMsgMetaData* meta = *vit_meta;
if (meta->mOrigMsgId == origMsgId)
{
@ -1482,8 +1480,6 @@ bool RsGxsDataAccess::getMsgRelatedInfo(MsgRelatedInfoReq *req)
outMsgIds.clear();
filteredOutMsgIds.clear();
cleanseMsgMetaMap(result);
}
return true;
}
@ -1496,7 +1492,7 @@ bool RsGxsDataAccess::getGroupStatistic(GroupStatisticRequest *req)
GxsMsgMetaResult metaResult;
mDataStore->retrieveGxsMsgMetaData(metaReq, metaResult);
const std::vector<RsGxsMsgMetaData*>& msgMetaV = metaResult[req->mGrpId];
const std::vector<const RsGxsMsgMetaData*>& msgMetaV = metaResult[req->mGrpId];
req->mGroupStatistic.mGrpId = req->mGrpId;
req->mGroupStatistic.mNumMsgs = msgMetaV.size();
@ -1514,7 +1510,7 @@ bool RsGxsDataAccess::getGroupStatistic(GroupStatisticRequest *req)
for(uint32_t i = 0; i < msgMetaV.size(); ++i)
{
RsGxsMsgMetaData* m = msgMetaV[i];
const RsGxsMsgMetaData* m = msgMetaV[i];
req->mGroupStatistic.mTotalSizeOfMsgs += m->mMsgSize + m->serial_size();
if(obsolete_msgs.find(m->mMsgId) != obsolete_msgs.end()) // skip obsolete messages.
@ -1540,7 +1536,7 @@ bool RsGxsDataAccess::getGroupStatistic(GroupStatisticRequest *req)
}
}
cleanseMsgMetaMap(metaResult);
//cleanseMsgMetaMap(metaResult);
return true;
}
@ -1595,21 +1591,19 @@ bool RsGxsDataAccess::getMsgIdList(MsgIdReq* req)
mDataStore->retrieveGxsMsgMetaData(req->mMsgIds, result);
GxsMsgMetaResult::iterator mit = result.begin(), mit_end = result.end();
for(; mit != mit_end; ++mit)
{
const RsGxsGroupId grpId = mit->first;
std::vector<RsGxsMsgMetaData*>& metaV = mit->second;
std::vector<RsGxsMsgMetaData*>::iterator vit = metaV.begin(),
std::vector<const RsGxsMsgMetaData*>& metaV = mit->second;
std::vector<const RsGxsMsgMetaData*>::iterator vit = metaV.begin(),
vit_end = metaV.end();
for(; vit != vit_end; ++vit)
{
RsGxsMsgMetaData* meta = *vit;
const RsGxsMsgMetaData* meta = *vit;
req->mMsgIdResult[grpId].insert(meta->mMsgId);
delete meta; // discard meta data mem
}
}
@ -1622,24 +1616,24 @@ bool RsGxsDataAccess::getMsgIdList(MsgIdReq* req)
return true;
}
void RsGxsDataAccess::cleanseMsgMetaMap(GxsMsgMetaResult& result)
{
GxsMsgMetaResult::iterator mit = result.begin();
for(; mit !=result.end(); ++mit)
{
std::vector<RsGxsMsgMetaData*>& msgMetaV = mit->second;
std::vector<RsGxsMsgMetaData*>::iterator vit = msgMetaV.begin();
for(; vit != msgMetaV.end(); ++vit)
{
delete *vit;
}
}
result.clear();
return;
}
// void RsGxsDataAccess::cleanseMsgMetaMap(GxsMsgMetaResult& result)
// {
// GxsMsgMetaResult::iterator mit = result.begin();
//
// for(; mit !=result.end(); ++mit)
// {
//
// std::vector<RsGxsMsgMetaData*>& msgMetaV = mit->second;
// std::vector<RsGxsMsgMetaData*>::iterator vit = msgMetaV.begin();
// for(; vit != msgMetaV.end(); ++vit)
// {
// delete *vit;
// }
// }
//
// result.clear();
// return;
// }
void RsGxsDataAccess::filterMsgIdList( GxsMsgIdResult& resultsMap, const RsTokReqOptions& opts, const MsgMetaFilter& msgMetas ) const
{
@ -1659,11 +1653,11 @@ void RsGxsDataAccess::filterMsgIdList( GxsMsgIdResult& resultsMap, const RsTokRe
for( std::set<RsGxsMessageId>::iterator msgIdIt = msgsIdSet.begin(); msgIdIt != msgsIdSet.end(); )
{
const RsGxsMessageId& msgId(*msgIdIt);
const std::map<RsGxsMessageId, RsGxsMsgMetaData*>& msgsMetaMap =
const std::map<RsGxsMessageId, const RsGxsMsgMetaData*>& msgsMetaMap =
cit->second;
bool keep = false;
std::map<RsGxsMessageId, RsGxsMsgMetaData*>::const_iterator msgsMetaMapIt;
std::map<RsGxsMessageId, const RsGxsMsgMetaData*>::const_iterator msgsMetaMapIt;
if( (msgsMetaMapIt = msgsMetaMap.find(msgId)) != msgsMetaMap.end() )
{

View File

@ -28,7 +28,7 @@
#include "rsgds.h"
typedef std::map< RsGxsGroupId, std::map<RsGxsMessageId, RsGxsMsgMetaData*> > MsgMetaFilter;
typedef std::map< RsGxsGroupId, std::map<RsGxsMessageId, const RsGxsMsgMetaData*> > MsgMetaFilter;
typedef std::map< RsGxsGroupId, RsGxsGrpMetaData* > GrpMetaFilter;
bool operator<(const std::pair<uint32_t,GxsRequest*>& p1,const std::pair<uint32_t,GxsRequest*>& p2);
@ -328,11 +328,11 @@ private:
*/
void tokenList(std::list<uint32_t> &tokens);
/*!
* Convenience function to delete the ids
* @param filter the meta filter to clean
*/
void cleanseMsgMetaMap(GxsMsgMetaResult& result);
// /*!
// * Convenience function to delete the ids
// * @param filter the meta filter to clean
// */
// void cleanseMsgMetaMap(GxsMsgMetaResult& result);
public:

View File

@ -953,7 +953,7 @@ void RsGxsNetService::handleRecvSyncGrpStatistics(RsNxsSyncGrpStatsItem *grs)
#endif
mDataStore->retrieveGxsMsgMetaData(reqIds, result);
const std::vector<RsGxsMsgMetaData*>& vec(result[grs->grpId]) ;
const std::vector<const RsGxsMsgMetaData*>& vec(result[grs->grpId]) ;
if(vec.empty()) // that means we don't have any, or there isn't any, but since the default is always 0, no need to send.
return ;
@ -970,12 +970,9 @@ void RsGxsNetService::handleRecvSyncGrpStatistics(RsNxsSyncGrpStatsItem *grs)
// be used to discard groups that are not used.
for(uint32_t i=0;i<vec.size();++i)
{
if(grs_resp->last_post_TS < vec[i]->mPublishTs)
grs_resp->last_post_TS = vec[i]->mPublishTs;
delete vec[i] ;
}
#ifdef NXS_NET_DEBUG_6
GXSNETDEBUG_PG(grs->PeerId(),grs->grpId) << " sending back statistics item with " << vec.size() << " elements." << std::endl;
#endif
@ -2953,21 +2950,19 @@ void RsGxsNetService::locked_genReqMsgTransaction(NxsTransaction* tr)
reqIds[grpId] = std::set<RsGxsMessageId>();
GxsMsgMetaResult result;
mDataStore->retrieveGxsMsgMetaData(reqIds, result);
std::vector<RsGxsMsgMetaData*> &msgMetaV = result[grpId];
std::vector<const RsGxsMsgMetaData*> &msgMetaV = result[grpId];
#ifdef NXS_NET_DEBUG_1
GXSNETDEBUG_PG(item->PeerId(),grpId) << " retrieving grp message list..." << std::endl;
GXSNETDEBUG_PG(item->PeerId(),grpId) << " grp locally contains " << msgMetaV.size() << " messsages." << std::endl;
#endif
std::vector<RsGxsMsgMetaData*>::const_iterator vit = msgMetaV.begin();
std::vector<const RsGxsMsgMetaData*>::const_iterator vit = msgMetaV.begin();
std::set<RsGxsMessageId> msgIdSet;
// put ids in set for each searching
for(; vit != msgMetaV.end(); ++vit)
{
msgIdSet.insert((*vit)->mMsgId);
delete(*vit);
}
msgMetaV.clear();
#ifdef NXS_NET_DEBUG_1
@ -4367,7 +4362,7 @@ void RsGxsNetService::handleRecvSyncMessage(RsNxsSyncMsgReqItem *item,bool item_
GxsMsgMetaResult metaResult;
mDataStore->retrieveGxsMsgMetaData(req, metaResult);
std::vector<RsGxsMsgMetaData*>& msgMetas = metaResult[item->grpId];
std::vector<const RsGxsMsgMetaData*>& msgMetas = metaResult[item->grpId];
#ifdef NXS_NET_DEBUG_0
GXSNETDEBUG_PG(item->PeerId(),item->grpId) << " retrieving message meta data." << std::endl;
@ -4395,9 +4390,9 @@ void RsGxsNetService::handleRecvSyncMessage(RsNxsSyncMsgReqItem *item,bool item_
if(canSendMsgIds(msgMetas, *grpMeta, peer, should_encrypt_to_this_circle_id))
{
for(std::vector<RsGxsMsgMetaData*>::iterator vit = msgMetas.begin();vit != msgMetas.end(); ++vit)
for(auto vit = msgMetas.begin();vit != msgMetas.end(); ++vit)
{
RsGxsMsgMetaData* m = *vit;
const RsGxsMsgMetaData* m = *vit;
// Check reputation
@ -4497,8 +4492,8 @@ void RsGxsNetService::handleRecvSyncMessage(RsNxsSyncMsgReqItem *item,bool item_
// release meta resource
for(std::vector<RsGxsMsgMetaData*>::iterator vit = msgMetas.begin(); vit != msgMetas.end(); ++vit)
delete *vit;
// for(std::vector<RsGxsMsgMetaData*>::iterator vit = msgMetas.begin(); vit != msgMetas.end(); ++vit)
// delete *vit;
}
void RsGxsNetService::locked_pushMsgRespFromList(std::list<RsNxsItem*>& itemL, const RsPeerId& sslId, const RsGxsGroupId& grp_id,const uint32_t& transN)
@ -4542,7 +4537,7 @@ void RsGxsNetService::locked_pushMsgRespFromList(std::list<RsNxsItem*>& itemL, c
}
}
bool RsGxsNetService::canSendMsgIds(std::vector<RsGxsMsgMetaData*>& msgMetas, const RsGxsGrpMetaData& grpMeta, const RsPeerId& sslId,RsGxsCircleId& should_encrypt_id)
bool RsGxsNetService::canSendMsgIds(std::vector<const RsGxsMsgMetaData*>& msgMetas, const RsGxsGrpMetaData& grpMeta, const RsPeerId& sslId,RsGxsCircleId& should_encrypt_id)
{
#ifdef NXS_NET_DEBUG_4
GXSNETDEBUG_PG(sslId,grpMeta.mGroupId) << "RsGxsNetService::canSendMsgIds() CIRCLE VETTING" << std::endl;
@ -4609,7 +4604,7 @@ bool RsGxsNetService::canSendMsgIds(std::vector<RsGxsMsgMetaData*>& msgMetas, co
GXSNETDEBUG_PG(sslId,grpMeta.mGroupId) << " deleting MsgMeta entry for msg ID " << msgMetas[i]->mMsgId << " signed by " << msgMetas[i]->mAuthorId << " who is not in group circle " << circleId << std::endl;
#endif
delete msgMetas[i] ;
//delete msgMetas[i] ;
msgMetas[i] = msgMetas[msgMetas.size()-1] ;
msgMetas.pop_back() ;
}

View File

@ -395,7 +395,7 @@ private:
* @return false, if you cannot send to this peer, true otherwise
*/
bool canSendGrpId(const RsPeerId& sslId, const RsGxsGrpMetaData& grpMeta, std::vector<GrpIdCircleVet>& toVet, bool &should_encrypt);
bool canSendMsgIds(std::vector<RsGxsMsgMetaData*>& msgMetas, const RsGxsGrpMetaData&, const RsPeerId& sslId, RsGxsCircleId &should_encrypt_id);
bool canSendMsgIds(std::vector<const RsGxsMsgMetaData*>& msgMetas, const RsGxsGrpMetaData&, const RsPeerId& sslId, RsGxsCircleId &should_encrypt_id);
/*!
* \brief checkPermissionsForFriendGroup

View File

@ -85,7 +85,7 @@ bool RsGxsMessageCleanUp::clean()
for(; mit != result.end(); ++mit)
{
std::vector<RsGxsMsgMetaData*>& metaV = mit->second;
std::vector<const RsGxsMsgMetaData*>& metaV = mit->second;
// First, make a map of which message have a child message. This allows to only delete messages that dont have child messages.
// A more accurate way to go would be to compute the time of the oldest message and possibly delete all the branch, but in the
@ -99,7 +99,7 @@ bool RsGxsMessageCleanUp::clean()
for( uint32_t i=0;i<metaV.size();++i)
{
RsGxsMsgMetaData* meta = metaV[i];
const RsGxsMsgMetaData* meta = metaV[i];
bool have_kids = (messages_with_kids.find(meta->mMsgId)!=messages_with_kids.end());
@ -132,7 +132,7 @@ bool RsGxsMessageCleanUp::clean()
std::cerr << std::endl;
#endif
delete meta;
//delete meta;
}
}

View File

@ -165,6 +165,7 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"),
RsThread::setStopTimeout(10);
#endif
#if !RS_VERSION_AT_LEAST(0,6,6)
registerHandler("/rsLoginHelper/createLocation",
[this](const std::shared_ptr<rb::Session> session)
{
@ -180,6 +181,7 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"),
std::string errorMessage;
bool makeHidden = false;
bool makeAutoTor = false;
std::string createToken;
// deserialize input parameters from JSON
{
@ -189,6 +191,7 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"),
RS_SERIAL_PROCESS(password);
RS_SERIAL_PROCESS(makeHidden);
RS_SERIAL_PROCESS(makeAutoTor);
RS_SERIAL_PROCESS(createToken);
}
// call retroshare C++ API
@ -196,8 +199,9 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"),
location, password, errorMessage, makeHidden,
makeAutoTor );
if(retval)
authorizeUser(location.mLocationId.toStdString(),password);
std::string tokenUser, tokenPw;
if(retval && parseToken(createToken, tokenUser, tokenPw))
authorizeUser(tokenUser,tokenPw);
// serialize out parameters and return value to JSON
{
@ -212,8 +216,9 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"),
DEFAULT_API_CALL_JSON_RETURN(rb::OK);
} );
}, false);
#endif // !RS_VERSION_AT_LEAST(0,6,6)
registerHandler("/rsLoginHelper/attemptLogin",
registerHandler("/rsLoginHelper/createLocationV2",
[this](const std::shared_ptr<rb::Session> session)
{
auto reqSize = session->get_request()->get_header("Content-Length", 0);
@ -223,28 +228,51 @@ JsonApiServer::JsonApiServer(): configMutex("JsonApiServer config"),
{
INITIALIZE_API_CALL_JSON_CONTEXT;
RsPeerId account;
RsPeerId locationId;
RsPgpId pgpId;
std::string locationName;
std::string pgpName;
std::string password;
// JSON API only
std::string apiUser;
std::string apiPass;
// deserialize input parameters from JSON
{
RsGenericSerializer::SerializeContext& ctx(cReq);
RsGenericSerializer::SerializeJob j(RsGenericSerializer::FROM_JSON);
RS_SERIAL_PROCESS(account);
RS_SERIAL_PROCESS(locationId);
RS_SERIAL_PROCESS(pgpId);
RS_SERIAL_PROCESS(locationName);
RS_SERIAL_PROCESS(pgpName);
RS_SERIAL_PROCESS(password);
// JSON API only
RS_SERIAL_PROCESS(apiUser);
RS_SERIAL_PROCESS(apiPass);
}
// call retroshare C++ API
RsInit::LoadCertificateStatus retval =
rsLoginHelper->attemptLogin(account, password);
std::error_condition retval;
if( retval == RsInit::OK )
authorizeUser(account.toStdString(), password);
if(apiUser.empty())
retval = RsJsonApiErrorNum::TOKEN_FORMAT_INVALID;
if(!retval)
retval = badApiCredientalsFormat(apiUser, apiPass);
if(!retval) // call retroshare C++ API
retval = rsLoginHelper->createLocationV2(
locationId, pgpId, locationName, pgpName, password );
if(!retval) retval = authorizeUser(apiUser, apiPass);
// serialize out parameters and return value to JSON
{
RsGenericSerializer::SerializeContext& ctx(cAns);
RsGenericSerializer::SerializeJob j(RsGenericSerializer::TO_JSON);
RS_SERIAL_PROCESS(locationId);
RS_SERIAL_PROCESS(pgpId);
RS_SERIAL_PROCESS(retval);
}
@ -467,18 +495,18 @@ void JsonApiServer::registerHandler(
const std::function<void (const std::shared_ptr<rb::Session>)>& callback )
{
/* Declare outside the lambda to avoid returning a dangling
* reference on Android */
* reference */
RsWarn tWarn;
const auto authFail =
[&](int status) -> RsWarn::stream_type&
[&](int status) -> std::ostream&
{
/* Capture session by reference as it is cheaper then copying
* shared_ptr by value which is not needed in this case */
session->close(status, corsOptionsHeaders);
return tWarn << "JsonApiServer authentication handler "
"blocked an attempt to call JSON API "
"authenticated method: " << path;
"blocked an attempt to call JSON API "
"authenticated method: " << path;
};
if(session->get_request()->get_method() == "OPTIONS")

View File

@ -154,6 +154,7 @@ rs_webui {
HEADERS += plugins/pluginmanager.h \
plugins/dlfcn_win32.h \
rsitems/rspluginitems.h \
util/i2pcommon.h \
util/rsinitedptr.h
HEADERS += $$PUBLIC_HEADERS
@ -327,6 +328,8 @@ INCLUDEPATH *= $${OPENPGPSDK_DIR}
PRE_TARGETDEPS *= $${OPENPGPSDK_DIR}/lib/libops.a
LIBS *= $${OPENPGPSDK_DIR}/lib/libops.a -lbz2
################################### HEADERS & SOURCES #############################
HEADERS += ft/ftchunkmap.h \
ft/ftcontroller.h \
ft/ftdata.h \
@ -468,7 +471,12 @@ HEADERS += turtle/p3turtle.h \
turtle/turtleclientservice.h
HEADERS += util/folderiterator.h \
util/rsdebug.h \
util/rsdebug.h \
util/rsdebuglevel0.h \
util/rsdebuglevel1.h \
util/rsdebuglevel2.h \
util/rsdebuglevel3.h \
util/rsdebuglevel4.h \
util/rskbdinput.h \
util/rsmemory.h \
util/smallobject.h \
@ -510,7 +518,8 @@ SOURCES += ft/ftchunkmap.cc \
ft/ftfilesearch.cc \
ft/ftserver.cc \
ft/fttransfermodule.cc \
ft/ftturtlefiletransferitem.cc
ft/ftturtlefiletransferitem.cc \
util/i2pcommon.cpp
SOURCES += crypto/chacha20.cpp \
crypto/hashstream.cc\

View File

@ -42,39 +42,19 @@ using std::dec;
#include <sys/timeb.h>
#endif
//#define PQI_HDL_DEBUG_UR 1
#ifdef PQI_HDL_DEBUG_UR
static double getCurrentTS()
{
#ifndef WINDOWS_SYS
struct timeval cts_tmp;
gettimeofday(&cts_tmp, NULL);
double cts = (cts_tmp.tv_sec) + ((double) cts_tmp.tv_usec) / 1000000.0;
#else
struct _timeb timebuf;
_ftime( &timebuf);
double cts = (timebuf.time) + ((double) timebuf.millitm) / 1000.0;
#endif
return cts;
}
#endif
struct RsLog::logInfo pqihandlerzoneInfo = {RsLog::Default, "pqihandler"};
#define pqihandlerzone &pqihandlerzoneInfo
//static const int PQI_HANDLER_NB_PRIORITY_LEVELS = 10 ;
//static const float PQI_HANDLER_NB_PRIORITY_RATIO = 2 ;
/****
#define DEBUG_TICK 1
#define RSITEM_DEBUG 1
****/
//#define UPDATE_RATES_DEBUG 1
// #define DEBUG_TICK 1
// #define RSITEM_DEBUG 1
pqihandler::pqihandler() : coreMtx("pqihandler")
{
RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/
RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/
// setup minimal total+individual rates.
rateIndiv_out = 0.01;
@ -97,7 +77,7 @@ int pqihandler::tick()
int moreToTick = 0;
{
RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/
RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/
// tick all interfaces...
std::map<RsPeerId, SearchModule *>::iterator it;
@ -127,9 +107,13 @@ int pqihandler::tick()
if(now > mLastRateCapUpdate + 5)
{
std::map<RsPeerId, RsConfigDataRates> rateMap;
std::map<RsPeerId, RsConfigDataRates>::iterator it;
// every 5 secs, update the max rates for all modules
RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/
RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/
for(std::map<RsPeerId, SearchModule *>::iterator it = mods.begin(); it != mods.end(); ++it)
{
// This is rather inelegant, but pqihandler has searchModules that are dynamically allocated, so the max rates
@ -149,7 +133,7 @@ int pqihandler::tick()
bool pqihandler::queueOutRsItem(RsItem *item)
{
RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/
RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/
uint32_t size ;
locked_HandleRsItem(item, size);
@ -166,7 +150,7 @@ bool pqihandler::queueOutRsItem(RsItem *item)
int pqihandler::status()
{
std::map<RsPeerId, SearchModule *>::iterator it;
RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/
RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/
{ // for output
std::string out = "pqihandler::status() Active Modules:\n";
@ -192,7 +176,7 @@ int pqihandler::status()
bool pqihandler::AddSearchModule(SearchModule *mod)
{
RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/
RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/
// if peerid used -> error.
//std::map<RsPeerId, SearchModule *>::iterator it;
if (mod->peerid != mod->pqi->PeerId())
@ -223,7 +207,7 @@ bool pqihandler::AddSearchModule(SearchModule *mod)
bool pqihandler::RemoveSearchModule(SearchModule *mod)
{
RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/
RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/
std::map<RsPeerId, SearchModule *>::iterator it;
for(it = mods.begin(); it != mods.end(); ++it)
{
@ -313,7 +297,7 @@ int pqihandler::ExtractRates(std::map<RsPeerId, RsBwRates> &ratemap, RsBwRat
total.mQueueOut = 0;
/* Lock once rates have been retrieved */
RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/
RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/
std::map<RsPeerId, SearchModule *>::iterator it;
for(it = mods.begin(); it != mods.end(); ++it)
@ -340,10 +324,6 @@ int pqihandler::ExtractRates(std::map<RsPeerId, RsBwRates> &ratemap, RsBwRat
// internal fn to send updates
int pqihandler::UpdateRates()
{
#ifdef PQI_HDL_DEBUG_UR
uint64_t t_now;
#endif
std::map<RsPeerId, SearchModule *>::iterator it;
float avail_in = getMaxRate(true);
@ -353,18 +333,15 @@ int pqihandler::UpdateRates()
float used_bw_out = 0;
/* Lock once rates have been retrieved */
RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/
RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/
int num_sm = mods.size();
float used_bw_in_table[num_sm]; /* table of in bandwidth currently used by each module */
float used_bw_out_table[num_sm]; /* table of out bandwidth currently used by each module */
int effectiveUploadsSm = 0;
int effectiveDownloadsSm = 0;
// loop through modules to get the used bandwith and the number of modules that are affectively transfering
#ifdef PQI_HDL_DEBUG_UR
std::cerr << "Looping through modules" << std::endl;
// loop through modules to get the used bandwidth
#ifdef UPDATE_RATES_DEBUG
RsDbg() << "UPDATE_RATES pqihandler::UpdateRates Looping through modules" << std::endl;
#endif
int index = 0;
@ -372,49 +349,33 @@ int pqihandler::UpdateRates()
for(it = mods.begin(); it != mods.end(); ++it)
{
SearchModule *mod = (it -> second);
float crate_in = mod -> pqi -> getRate(true);
traffInSum += mod -> pqi -> getTraffic(true);
traffOutSum += mod -> pqi -> getTraffic(false);
#ifdef PQI_HDL_DEBUG_UR
if(crate_in > 0.0)
std::cerr << " got in rate for peer " << it->first << " : " << crate_in << std::endl;
#endif
if ((crate_in > 0.01 * avail_in) || (crate_in > 0.1))
{
++effectiveDownloadsSm;
}
float crate_in = mod -> pqi -> getRate(true);
float crate_out = mod -> pqi -> getRate(false);
if ((crate_out > 0.01 * avail_out) || (crate_out > 0.1))
{
++effectiveUploadsSm;
}
used_bw_in += crate_in;
used_bw_out += crate_out;
/* fill the table of bandwidth */
/* fill the table of used bandwidths */
used_bw_in_table[index] = crate_in;
used_bw_out_table[index] = crate_out;
++index;
}
#ifdef PQI_HDL_DEBUG_UR
t_now = 1000 * getCurrentTS();
std::cerr << dec << t_now << " pqihandler::UpdateRates(): Sorting used_bw_out_table: " << num_sm << " entries" << std::endl;
#ifdef UPDATE_RATES_DEBUG
RsDbg() << "UPDATE_RATES pqihandler::UpdateRates Sorting used_bw_out_table: " << num_sm << " entries" << std::endl;
#endif
/* Sort the used bw in/out table in ascending order */
std::sort(used_bw_in_table, used_bw_in_table + num_sm);
std::sort(used_bw_out_table, used_bw_out_table + num_sm);
#ifdef PQI_HDL_DEBUG_UR
t_now = 1000 * getCurrentTS();
std::cerr << dec << t_now << " pqihandler::UpdateRates(): Done." << std::endl;
std::cerr << dec << t_now << " pqihandler::UpdateRates(): used_bw_out " << used_bw_out << std::endl;
#ifdef UPDATE_RATES_DEBUG
RsDbg() << "UPDATE_RATES pqihandler::UpdateRates used_bw_out " << used_bw_out << std::endl;
#endif
/* Calculate the optimal out_max value, taking into account avail_out and the out bw requested by modules */
@ -441,9 +402,8 @@ int pqihandler::UpdateRates()
}
}
#ifdef PQI_HDL_DEBUG_UR
t_now = 1000 * getCurrentTS();
std::cerr << dec << t_now << " pqihandler::UpdateRates(): mod_index " << mod_index << " out_max_bw " << out_max_bw << " remaining out bw " << out_remaining_bw << std::endl;
#ifdef UPDATE_RATES_DEBUG
RsDbg() << "UPDATE_RATES pqihandler::UpdateRates mod_index " << mod_index << " out_max_bw " << out_max_bw << " remaining out bw " << out_remaining_bw << std::endl;
#endif
/* Allocate only half the remaining out bw, if any, to make it smoother */
@ -473,67 +433,70 @@ int pqihandler::UpdateRates()
}
}
#ifdef PQI_HDL_DEBUG_UR
t_now = 1000 * getCurrentTS();
std::cerr << dec << t_now << " pqihandler::UpdateRates(): mod_index " << mod_index << " in_max_bw " << in_max_bw << " remaining in bw " << in_remaining_bw << std::endl;
#ifdef UPDATE_RATES_DEBUG
RsDbg() << "UPDATE_RATES pqihandler::UpdateRates mod_index " << mod_index << " in_max_bw " << in_max_bw << " remaining in bw " << in_remaining_bw << std::endl;
#endif
/* Allocate only half the remaining in bw, if any, to make it smoother */
in_max_bw = in_max_bw + in_remaining_bw / 2;
#ifdef DEBUG_QOS
// std::cerr << "Totals (In) Used B/W " << used_bw_in;
// std::cerr << " Available B/W " << avail_in;
// std::cerr << " Effective transfers " << effectiveDownloadsSm << std::endl;
// std::cerr << "Totals (Out) Used B/W " << used_bw_out;
// std::cerr << " Available B/W " << avail_out;
// std::cerr << " Effective transfers " << effectiveUploadsSm << std::endl;
#endif
// store current total in and ou used bw
locked_StoreCurrentRates(used_bw_in, used_bw_out);
//computing average rates for effective transfers
float max_in_effective = avail_in / num_sm;
if (effectiveDownloadsSm != 0) {
max_in_effective = avail_in / effectiveDownloadsSm;
}
float max_out_effective = avail_out / num_sm;
if (effectiveUploadsSm != 0) {
max_out_effective = avail_out / effectiveUploadsSm;
}
//modify the in and out limit
#ifdef PQI_HDL_DEBUG_UR
t_now = 1000 * getCurrentTS();
std::cerr << dec << t_now << " pqihandler::UpdateRates(): setting new out_max " << out_max_bw << " in_max " << in_max_bw << std::endl;
#ifdef UPDATE_RATES_DEBUG
RsDbg() << "UPDATE_RATES pqihandler::UpdateRates setting new out_max " << out_max_bw << " in_max " << in_max_bw << std::endl;
#endif
// retrieve down (from peer point of view) bandwidth limits set by peers in their own settings
std::map<RsPeerId, RsConfigDataRates> rateMap;
rsConfig->getAllBandwidthRates(rateMap);
std::map<RsPeerId, RsConfigDataRates>::iterator rateMap_it;
#ifdef UPDATE_RATES_DEBUG
// Dump RsConfigurationDataRates
RsDbg() << "UPDATE_RATES pqihandler::UpdateRates RsConfigDataRates dump" << std::endl;
for (rateMap_it = rateMap.begin(); rateMap_it != rateMap.end(); rateMap_it++)
RsDbg () << "UPDATE_RATES pqihandler::UpdateRates PeerId " << rateMap_it->first.toStdString() << " mAllowedOut " << rateMap_it->second.mAllowedOut << std::endl;
#endif
// update max rates taking into account the limits set by peers in their own settings
for(it = mods.begin(); it != mods.end(); ++it)
{
SearchModule *mod = (it -> second);
mod -> pqi -> setMaxRate(true, in_max_bw);
mod -> pqi -> setMaxRate(false, out_max_bw);
// for our down bandwidth we set the max to the calculated value without taking into account the max set by peers: they will control their up bw on their side
mod -> pqi -> setMaxRate(true, in_max_bw);
// for our up bandwidth we limit to the maximum down bw provided by peers via BwCtrl because we don't want to clog our outqueues, the SSL buffers, and our friends inbound queues
if ((rateMap_it = rateMap.find(mod->pqi->PeerId())) != rateMap.end())
{
if (rateMap_it->second.mAllowedOut > 0)
{
if (out_max_bw > rateMap_it->second.mAllowedOut)
mod -> pqi -> setMaxRate(false, rateMap_it->second.mAllowedOut);
else
mod -> pqi -> setMaxRate(false, out_max_bw);
}
else
mod -> pqi -> setMaxRate(false, out_max_bw);
}
}
//cap the rates
#ifdef UPDATE_RATES_DEBUG
// dump maxRates
for(it = mods.begin(); it != mods.end(); ++it)
{
SearchModule *mod = (it -> second);
if (mod -> pqi -> getMaxRate(false) < max_out_effective) mod -> pqi -> setMaxRate(false, max_out_effective);
if (mod -> pqi -> getMaxRate(false) > avail_out) mod -> pqi -> setMaxRate(false, avail_out);
if (mod -> pqi -> getMaxRate(true) < max_in_effective) mod -> pqi -> setMaxRate(true, max_in_effective);
if (mod -> pqi -> getMaxRate(true) > avail_in) mod -> pqi -> setMaxRate(true, avail_in);
RsDbg() << "UPDATE_RATES pqihandler::UpdateRates PeerID " << (mod ->pqi -> PeerId()).toStdString() << " new bandwidth limits up " << mod -> pqi -> getMaxRate(false) << " down " << mod -> pqi -> getMaxRate(true) << std::endl;
}
#endif
return 1;
}
void pqihandler::getCurrentRates(float &in, float &out)
{
RsStackMutex stack(coreMtx); /**************** LOCKED MUTEX ****************/
RS_STACK_MUTEX(coreMtx); /**************** LOCKED MUTEX ****************/
in = rateTotal_in;
out = rateTotal_out;

View File

@ -413,9 +413,10 @@ int unix_fcntl_nonblock(int fd)
{
int ret;
/******************* WINDOWS SPECIFIC PART ******************/
/******************* OS SPECIFIC PART ******************/
#ifndef WINDOWS_SYS // ie UNIX
ret = fcntl(fd, F_SETFL, O_NONBLOCK);
int flags = fcntl(fd, F_GETFL);
ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
#ifdef NET_DEBUG
std::cerr << "unix_fcntl_nonblock():" << ret << " errno:" << errno << std::endl;

View File

@ -1,5 +1,5 @@
/*******************************************************************************
* libretroshare/src/pqi: pqiservice.h *
* libretroshare/src/pqi: pqiservice.cc *
* *
* libretroshare: retroshare core library *
* *
@ -23,6 +23,22 @@
#include "util/rsdebug.h"
#include "util/rsstring.h"
#include <sstream>
#include <sys/time.h>
static double getCurrentTS()
{
#ifndef WINDOWS_SYS
struct timeval cts_tmp;
gettimeofday(&cts_tmp, NULL);
double cts = (cts_tmp.tv_sec) + ((double) cts_tmp.tv_usec) / 1000000.0;
#else
struct _timeb timebuf;
_ftime( &timebuf);
double cts = (timebuf.time) + ((double) timebuf.millitm) / 1000.0;
#endif
return cts;
}
#ifdef SERVICE_DEBUG
const int pqiservicezone = 60478;
#endif
@ -44,7 +60,7 @@ bool pqiService::send(RsRawItem *item)
p3ServiceServer::p3ServiceServer(pqiPublisher *pub, p3ServiceControl *ctrl) : mPublisher(pub), mServiceControl(ctrl), srvMtx("p3ServiceServer")
{
RsStackMutex stack(srvMtx); /********* LOCKED *********/
RS_STACK_MUTEX(srvMtx); /********* LOCKED *********/
#ifdef SERVICE_DEBUG
pqioutput(PQL_DEBUG_BASIC, pqiservicezone,
@ -56,7 +72,7 @@ p3ServiceServer::p3ServiceServer(pqiPublisher *pub, p3ServiceControl *ctrl) : mP
int p3ServiceServer::addService(pqiService *ts, bool defaultOn)
{
RsStackMutex stack(srvMtx); /********* LOCKED *********/
RS_STACK_MUTEX(srvMtx); /********* LOCKED *********/
#ifdef SERVICE_DEBUG
pqioutput(PQL_DEBUG_BASIC, pqiservicezone,
@ -84,7 +100,7 @@ int p3ServiceServer::addService(pqiService *ts, bool defaultOn)
bool p3ServiceServer::getServiceItemNames(uint32_t service_type,std::map<uint8_t,std::string>& names)
{
RsStackMutex stack(srvMtx); /********* LOCKED *********/
RS_STACK_MUTEX(srvMtx); /********* LOCKED *********/
std::map<uint32_t, pqiService *>::iterator it=services.find(service_type) ;
@ -99,7 +115,7 @@ bool p3ServiceServer::getServiceItemNames(uint32_t service_type,std::map<uint8_t
int p3ServiceServer::removeService(pqiService *ts)
{
RsStackMutex stack(srvMtx); /********* LOCKED *********/
RS_STACK_MUTEX(srvMtx); /********* LOCKED *********/
#ifdef SERVICE_DEBUG
pqioutput(PQL_DEBUG_BASIC, pqiservicezone, "p3ServiceServer::removeService()");
@ -124,60 +140,33 @@ int p3ServiceServer::removeService(pqiService *ts)
bool p3ServiceServer::recvItem(RsRawItem *item)
{
RsStackMutex stack(srvMtx); /********* LOCKED *********/
#ifdef SERVICE_DEBUG
std::cerr << "p3ServiceServer::incoming()";
std::cerr << std::endl;
{
std::string out;
rs_sprintf(out, "p3ServiceServer::incoming() PacketId: %x\nLooking for Service: %x\nItem:\n", item -> PacketId(), (item -> PacketId() & 0xffffff00));
item -> print_string(out);
std::cerr << out;
std::cerr << std::endl;
}
#endif
// Packet Filtering.
// This doesn't need to be in Mutex.
if (!mServiceControl->checkFilter(item->PacketId() & 0xffffff00, item->PeerId()))
{
#ifdef SERVICE_DEBUG
std::cerr << "p3ServiceServer::recvItem() Fails Filtering " << std::endl;
#endif
delete item;
return false;
}
pqiService *s = NULL;
std::map<uint32_t, pqiService *>::iterator it;
it = services.find(item -> PacketId() & 0xffffff00);
if (it == services.end())
// access the service map under mutex lock
{
#ifdef SERVICE_DEBUG
std::cerr << "p3ServiceServer::incoming() Service: No Service - deleting";
std::cerr << std::endl;
#endif
delete item;
return false;
RS_STACK_MUTEX(srvMtx);
auto it = services.find(item -> PacketId() & 0xffffff00);
if (it == services.end())
{
delete item;
return false;
}
s = it->second;
}
{
#ifdef SERVICE_DEBUG
std::cerr << "p3ServiceServer::incoming() Sending to : " << (void *) it -> second;
std::cerr << std::endl;
#endif
return (it->second) -> recv(item);
}
delete item;
return false;
// then call recv off mutex
bool result = s->recv(item);
return result;
}
bool p3ServiceServer::sendItem(RsRawItem *item)
{
#ifdef SERVICE_DEBUG
@ -204,40 +193,27 @@ bool p3ServiceServer::sendItem(RsRawItem *item)
}
mPublisher->sendItem(item);
return true;
}
int p3ServiceServer::tick()
{
mServiceControl->tick();
RsStackMutex stack(srvMtx); /********* LOCKED *********/
#ifdef SERVICE_DEBUG
pqioutput(PQL_DEBUG_ALL, pqiservicezone,
"p3ServiceServer::tick()");
#endif
std::map<uint32_t, pqiService *>::iterator it;
// from the beginning to where we started.
for(it = services.begin();it != services.end(); ++it)
{
#ifdef SERVICE_DEBUG
std::string out;
rs_sprintf(out, "p3ServiceServer::service id: %u -> Service: %p", it -> first, it -> second);
pqioutput(PQL_DEBUG_ALL, pqiservicezone, out);
#endif
// now we should actually tick the service.
(it -> second) -> tick();
// make a copy of the service map
std::map<uint32_t,pqiService *> local_map;
{
RS_STACK_MUTEX(srvMtx);
local_map=services;
}
// tick all services off mutex
for(auto it(local_map.begin());it!=local_map.end();++it)
{
(it->second)->tick();
}
return 1;
}

View File

@ -372,9 +372,11 @@ int pqissl::status()
// tick......
int pqissl::tick()
{
RsStackMutex stack(mSslMtx); /**** LOCKED MUTEX ****/
// there is no reason to lock pqissl mutex now
// we will lock the mutex later if we actually need to call to ConnectAttempt
// RsStackMutex stack(mSslMtx); /**** LOCKED MUTEX ****/
//pqistreamer::tick();
// pqistreamer::tick();
// continue existing connection attempt.
if (!active)
@ -385,7 +387,8 @@ int pqissl::tick()
#ifdef PQISSL_LOG_DEBUG
rslog(RSL_DEBUG_BASIC, pqisslzone, "pqissl::tick() Continuing Connection Attempt!");
#endif
// now lock pqissl mutex, that will take up to 10 ms
RsStackMutex stack(mSslMtx); /**** LOCKED MUTEX ****/
ConnectAttempt();
return 1;
}

View File

@ -1,5 +1,5 @@
/*******************************************************************************
* libretroshare/src/pqi: pqistreamer.h *
* libretroshare/src/pqi: pqistreamer.cc *
* *
* libretroshare: retroshare core library *
* *
@ -102,38 +102,39 @@ pqistreamer::pqistreamer(RsSerialiser *rss, const RsPeerId& id, BinInterface *bi
mAvgDtOut(0), mAvgDtIn(0)
{
// 100 B/s (minimal)
setMaxRate(true, 0.1);
setMaxRate(false, 0.1);
setRate(true, 0); // needs to be off-mutex
setRate(false, 0);
// 100 B/s (minimal)
setMaxRate(true, 0.1);
setMaxRate(false, 0.1);
setRate(true, 0); // needs to be off-mutex
setRate(false, 0);
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 ;
mAcceptsPacketSlicing = false ; // by default. Will be turned into true when everyone's ready.
mLastSentPacketSlicingProbe = 0 ;
mAvgLastUpdate = mCurrSentTS = mCurrReadTS = getCurrentTS();
mAvgLastUpdate = mCurrSentTS = mCurrReadTS = getCurrentTS();
mIncomingSize = 0 ;
mIncomingSize = 0 ;
mIncomingSize_bytes = 0;
mStatisticsTimeStamp = 0 ;
/* allocated once */
mPkt_rpend_size = 0;
mPkt_rpending = 0;
mReading_state = reading_state_initial ;
mStatisticsTimeStamp = 0 ;
/* allocated once */
mPkt_rpend_size = 0;
mPkt_rpending = 0;
mReading_state = reading_state_initial ;
pqioutput(PQL_DEBUG_ALL, pqistreamerzone, "pqistreamer::pqistreamer() Initialisation!");
pqioutput(PQL_DEBUG_ALL, pqistreamerzone, "pqistreamer::pqistreamer() Initialisation!");
if (!bio_in)
{
pqioutput(PQL_ALERT, pqistreamerzone, "pqistreamer::pqistreamer() NULL bio, FATAL ERROR!");
exit(1);
}
if (!bio_in)
{
pqioutput(PQL_ALERT, pqistreamerzone, "pqistreamer::pqistreamer() NULL bio, FATAL ERROR!");
exit(1);
}
mFailed_read_attempts = 0; // reset failed read, as no packet is still read.
mFailed_read_attempts = 0; // reset failed read, as no packet is still read.
return;
return;
}
pqistreamer::~pqistreamer()
@ -159,7 +160,7 @@ pqistreamer::~pqistreamer()
if (mRsSerialiser)
delete mRsSerialiser;
free_pend_locked() ;
free_pend() ;
// clean up incoming.
while (!mIncoming.empty())
@ -177,6 +178,7 @@ pqistreamer::~pqistreamer()
// Get/Send Items.
// This is the entry poing for methods willing to send items through our out queue
int pqistreamer::SendItem(RsItem *si,uint32_t& out_size)
{
#ifdef RSITEM_DEBUG
@ -199,18 +201,30 @@ RsItem *pqistreamer::GetItem()
pqioutput(PQL_DEBUG_ALL, pqistreamerzone, "pqistreamer::GetItem()");
#endif
RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/
if(mIncoming.empty())
return NULL;
RsItem *osr = mIncoming.front() ;
mIncoming.pop_front() ;
--mIncomingSize;
mIncoming.pop_front() ;
--mIncomingSize;
// for future use
// mIncomingSize_bytes -=
return osr;
}
float pqistreamer::getMaxRate(bool b)
{
RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/
return getMaxRate_locked(b);
}
float pqistreamer::getMaxRate_locked(bool b)
{
return RateInterface::getMaxRate(b) ;
}
float pqistreamer::getRate(bool b)
{
RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/
@ -219,26 +233,28 @@ float pqistreamer::getRate(bool b)
void pqistreamer::setMaxRate(bool b,float f)
{
RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/
RateInterface::setMaxRate(b,f) ;
RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/
setMaxRate_locked(b,f);
}
void pqistreamer::setMaxRate_locked(bool b,float f)
{
RateInterface::setMaxRate(b,f) ;
}
void pqistreamer::setRate(bool b,float f)
{
RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/
RateInterface::setRate(b,f) ;
}
void pqistreamer::updateRates()
{
// update rates both ways.
// update actual rates both ways.
double t = getCurrentTS(); // get current timestamp.
double diff ;
{
RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/
diff = t - mAvgLastUpdate ;
}
double diff = t - mAvgLastUpdate;
if (diff > PQISTREAM_AVG_PERIOD)
{
@ -263,10 +279,11 @@ void pqistreamer::updateRates()
setRate(false, 0);
}
mAvgLastUpdate = t;
mAvgReadCount = 0;
{
RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/
mAvgLastUpdate = t;
mAvgReadCount = 0;
mAvgSentCount = 0;
}
}
@ -277,7 +294,7 @@ int pqistreamer::tick_bio()
RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/
mBio->tick();
/* short circuit everything is bio isn't active */
/* short circuit everything if bio isn't active */
if (!(mBio->isactive()))
{
return 0;
@ -285,36 +302,36 @@ int pqistreamer::tick_bio()
return 1;
}
int pqistreamer::tick_recv(uint32_t timeout)
{
RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/
// Apart from a few exceptions that are atomic (mLastIncomingTs, mIncomingSize), only this pqi thread reads/writes mIncoming queue and related counters.
// The lock of pqistreamer mutex is thus not needed here.
// The mutex lock is still needed before calling locked_addTrafficClue because this method is also used by the thread pushing packets in mOutPkts.
// Locks around rates are provided internally.
if (mBio->moretoread(timeout))
{
handleincoming_locked();
handleincoming();
}
if(!(mBio->isactive()))
{
free_pend();
}
if(!(mBio->isactive()))
{
free_pend_locked();
}
return 1;
}
int pqistreamer::tick_send(uint32_t timeout)
{
RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/
/* short circuit everything is bio isn't active */
/* short circuit everything if bio isn't active */
if (!(mBio->isactive()))
{
free_pend_locked();
free_pend();
return 0;
}
if (mBio->cansend(timeout))
{
RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/
handleoutgoing_locked();
}
@ -340,12 +357,11 @@ int pqistreamer::status()
return 0;
}
// this method is overloaded by pqiqosstreamer
void pqistreamer::locked_storeInOutputQueue(void *ptr,int,int)
{
mOutPkts.push_back(ptr);
}
//
/**************** HANDLE OUTGOING TRANSLATION + TRANSMISSION ******/
int pqistreamer::queue_outpqi_locked(RsItem *pqi,uint32_t& pktsize)
{
@ -354,7 +370,6 @@ int pqistreamer::queue_outpqi_locked(RsItem *pqi,uint32_t& pktsize)
std::cerr << "pqistreamer::queue_outpqi() called." << std::endl;
#endif
/* decide which type of packet it is */
pktsize = mRsSerialiser->size(pqi);
@ -362,7 +377,6 @@ int pqistreamer::queue_outpqi_locked(RsItem *pqi,uint32_t& pktsize)
if(ptr == NULL)
return 0 ;
#ifdef DEBUG_PQISTREAMER
std::cerr << "pqistreamer::queue_outpqi() serializing packet with packet size : " << pktsize << std::endl;
@ -403,27 +417,31 @@ int pqistreamer::queue_outpqi_locked(RsItem *pqi,uint32_t& pktsize)
return 1; // keep error internal.
}
int pqistreamer::handleincomingitem_locked(RsItem *pqi,int len)
int pqistreamer::handleincomingitem(RsItem *pqi,int len)
{
#ifdef DEBUG_PQISTREAMER
pqioutput(PQL_DEBUG_ALL, pqistreamerzone, "pqistreamer::handleincomingitem_locked()");
pqioutput(PQL_DEBUG_ALL, pqistreamerzone, "pqistreamer::handleincomingitem()");
#endif
// timestamp last received packet.
mLastIncomingTs = time(NULL);
// Use overloaded Contact function
pqi -> PeerId(PeerId());
mIncoming.push_back(pqi);
++mIncomingSize ;
/*******************************************************************************************/
// keep info for stats for a while. Only keep the items for the last two seconds. sec n is ongoing and second n-1
// is a full statistics chunk that can be used in the GUI
mIncoming.push_back(pqi);
++mIncomingSize;
// for future use
// mIncomingSize_bytes += len;
locked_addTrafficClue(pqi,len,mCurrentStatsChunk_In) ;
/*******************************************************************************************/
/*******************************************************************************************/
// keep info for stats for a while. Only keep the items for the last two seconds. sec n is ongoing and second n-1
// is a full statistics chunk that can be used in the GUI
{
RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/
locked_addTrafficClue(pqi,len,mCurrentStatsChunk_In) ;
}
/*******************************************************************************************/
return 1;
}
@ -456,8 +474,8 @@ void pqistreamer::locked_addTrafficClue(const RsItem *pqi,uint32_t pktsize,std::
rstime_t pqistreamer::getLastIncomingTS()
{
RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/
// This is the only case where another thread (rs main for pqiperson) will access our data
// Still a mutex lock is not needed because the operation is atomic
return mLastIncomingTs;
}
@ -693,23 +711,23 @@ int pqistreamer::handleoutgoing_locked()
/* Handles reading from input stream.
*/
int pqistreamer::handleincoming_locked()
int pqistreamer::handleincoming()
{
int readbytes = 0;
static const int max_failed_read_attempts = 2000 ;
#ifdef DEBUG_PQISTREAMER
pqioutput(PQL_DEBUG_ALL, pqistreamerzone, "pqistreamer::handleincoming_locked()");
pqioutput(PQL_DEBUG_ALL, pqistreamerzone, "pqistreamer::handleincoming()");
#endif
if(!(mBio->isactive()))
{
mReading_state = reading_state_initial ;
free_pend_locked();
free_pend();
return 0;
}
else
allocate_rpend_locked();
allocate_rpend();
// enough space to read any packet.
uint32_t maxlen = mPkt_rpend_size;
@ -718,7 +736,7 @@ int pqistreamer::handleincoming_locked()
// initial read size: basic packet.
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();
#ifdef DEBUG_PQISTREAMER
std::cerr << "[" << (void*)pthread_self() << "] " << "reading state = " << mReading_state << std::endl ;
@ -967,19 +985,19 @@ continue_packet:
std::cerr << "Inputing partial packet " << RsUtil::BinToHex((char*)block,8) << std::endl;
#endif
uint32_t packet_length = 0 ;
pkt = addPartialPacket_locked(block,pktlen,slice_packet_id,is_packet_starting,is_packet_ending,packet_length) ;
pkt = addPartialPacket(block,pktlen,slice_packet_id,is_packet_starting,is_packet_ending,packet_length) ;
pktlen = packet_length ;
}
else
pkt = mRsSerialiser->deserialise(block, &pktlen);
if ((pkt != NULL) && (0 < handleincomingitem_locked(pkt,pktlen)))
if ((pkt != NULL) && (0 < handleincomingitem(pkt,pktlen)))
{
#ifdef DEBUG_PQISTREAMER
pqioutput(PQL_DEBUG_BASIC, pqistreamerzone, "Successfully Read a Packet!");
#endif
inReadBytes_locked(pktlen); // only count deserialised packets, because that's what is actually been transfered.
inReadBytes(pktlen); // only count deserialised packets, because that's what is actually been transfered.
}
else if (!is_partial_packet)
{
@ -1012,7 +1030,7 @@ continue_packet:
return 0;
}
RsItem *pqistreamer::addPartialPacket_locked(const void *block, uint32_t len, uint32_t slice_packet_id, bool is_packet_starting, bool is_packet_ending, uint32_t &total_len)
RsItem *pqistreamer::addPartialPacket(const void *block, uint32_t len, uint32_t slice_packet_id, bool is_packet_starting, bool is_packet_ending, uint32_t &total_len)
{
#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 ;
@ -1134,7 +1152,7 @@ int pqistreamer::outAllowedBytes_locked()
// low pass filter on mAvgDtOut
mAvgDtOut = PQISTREAM_AVG_DT_FRAC * mAvgDtOut + (1 - PQISTREAM_AVG_DT_FRAC) * dt;
double maxout = getMaxRate(false) * 1024.0;
double maxout = getMaxRate_locked(false) * 1024.0;
// this is used to take into account a possible excess of data sent during the previous round
mCurrSent -= int(dt * maxout);
@ -1156,7 +1174,7 @@ int pqistreamer::outAllowedBytes_locked()
return quota;
}
int pqistreamer::inAllowedBytes_locked()
int pqistreamer::inAllowedBytes()
{
double t = getCurrentTS(); // in sec, with high accuracy
@ -1194,7 +1212,7 @@ int pqistreamer::inAllowedBytes_locked()
#ifdef DEBUG_PQISTREAMER
uint64_t t_now = 1000 * getCurrentTS();
std::cerr << std::dec << t_now << " DEBUG_PQISTREAMER pqistreamer::inAllowedBytes_locked PeerId " << this->PeerId().toStdString() << " dt " << (int)(1000 * dt) << "ms, mAvgDtIn " << (int)(1000 * mAvgDtIn) << "ms, maxin " << (int)(maxin) << " bytes/s, mCurrRead " << mCurrRead << " bytes, quota " << (int)(quota) << " bytes" << std::endl;
std::cerr << std::dec << t_now << " DEBUG_PQISTREAMER pqistreamer::inAllowedBytes PeerId " << this->PeerId().toStdString() << " dt " << (int)(1000 * dt) << "ms, mAvgDtIn " << (int)(1000 * mAvgDtIn) << "ms, maxin " << (int)(maxin) << " bytes/s, mCurrRead " << mCurrRead << " bytes, quota " << (int)(quota) << " bytes" << std::endl;
#endif
return quota;
@ -1231,7 +1249,7 @@ void pqistreamer::outSentBytes_locked(uint32_t outb)
return;
}
void pqistreamer::inReadBytes_locked(uint32_t inb)
void pqistreamer::inReadBytes(uint32_t inb)
{
#ifdef DEBUG_PQISTREAMER
{
@ -1248,7 +1266,7 @@ void pqistreamer::inReadBytes_locked(uint32_t inb)
return;
}
void pqistreamer::allocate_rpend_locked()
void pqistreamer::allocate_rpend()
{
if(mPkt_rpending)
return;
@ -1271,17 +1289,17 @@ int pqistreamer::reset()
#ifdef DEBUG_PQISTREAMER
std::cerr << "pqistreamer::reset()" << std::endl;
#endif
free_pend_locked();
free_pend();
return 1 ;
}
void pqistreamer::free_pend_locked()
void pqistreamer::free_pend()
{
if(mPkt_rpending)
{
#ifdef DEBUG_PQISTREAMER
std::cerr << "pqistreamer::free_pend_locked(): pending input packet buffer" << std::endl;
std::cerr << "pqistreamer::free_pend(): pending input packet buffer" << std::endl;
#endif
free(mPkt_rpending);
mPkt_rpending = 0;
@ -1291,7 +1309,7 @@ void pqistreamer::free_pend_locked()
if (mPkt_wpending)
{
#ifdef DEBUG_PQISTREAMER
std::cerr << "pqistreamer::free_pend_locked(): pending output packet buffer" << std::endl;
std::cerr << "pqistreamer::free_pend(): pending output packet buffer" << std::endl;
#endif
free(mPkt_wpending);
mPkt_wpending = NULL;
@ -1300,7 +1318,7 @@ void pqistreamer::free_pend_locked()
#ifdef DEBUG_PQISTREAMER
if(!mPartialPackets.empty())
std::cerr << "pqistreamer::free_pend_locked(): " << mPartialPackets.size() << " pending input partial packets" << std::endl;
std::cerr << "pqistreamer::free_pend(): " << mPartialPackets.size() << " pending input partial packets" << std::endl;
#endif
// also delete any incoming partial packet
for(std::map<uint32_t,PartialPacketRecord>::iterator it(mPartialPackets.begin());it!=mPartialPackets.end();++it)
@ -1318,26 +1336,47 @@ int pqistreamer::gatherStatistics(std::list<RSTrafficClue>& outqueue_lst,std
return locked_gatherStatistics(outqueue_lst,inqueue_lst);
}
// this method is overloaded by pqiqosstreamer
int pqistreamer::getQueueSize(bool in)
{
RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/
if (in)
return mIncomingSize;
else
return locked_out_queue_size();
// no mutex is needed here because this is atomic
return mIncomingSize;
else
{
RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/
return locked_out_queue_size();
}
}
int pqistreamer::getQueueSize_bytes(bool in)
{
if (in)
// no mutex is needed here because this is atomic
// for future use, mIncomingSize_bytes is not updated yet
return mIncomingSize_bytes;
else
{
RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/
return locked_compute_out_pkt_size();
}
}
void pqistreamer::getRates(RsBwRates &rates)
{
RateInterface::getRates(rates);
RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/
// no mutex is needed here because this is atomic
rates.mQueueIn = mIncomingSize;
rates.mQueueIn = mIncomingSize;
rates.mQueueOut = locked_out_queue_size();
{
RsStackMutex stack(mStreamerMtx); /**** LOCKED MUTEX ****/
rates.mQueueOut = locked_out_queue_size();
}
}
// this method is overloaded by pqiqosstreamer
int pqistreamer::locked_out_queue_size() const
{
// Warning: because out_pkt is a list, calling size
@ -1347,6 +1386,7 @@ int pqistreamer::locked_out_queue_size() const
return mOutPkts.size() ;
}
// this method is overloaded by pqiqosstreamer
void pqistreamer::locked_clear_out_queue()
{
for(std::list<void*>::iterator it = mOutPkts.begin(); it != mOutPkts.end(); )
@ -1361,6 +1401,7 @@ void pqistreamer::locked_clear_out_queue()
}
}
// this method is overloaded by pqiqosstreamer
int pqistreamer::locked_compute_out_pkt_size() const
{
int total = 0 ;
@ -1379,6 +1420,7 @@ int pqistreamer::locked_gatherStatistics(std::list<RSTrafficClue>& out_lst,std::
return 1 ;
}
// this method is overloaded by pqiqosstreamer
void *pqistreamer::locked_pop_out_data(uint32_t /*max_slice_size*/, uint32_t &size, bool &starts, bool &ends, uint32_t &packet_id)
{
size = 0 ;
@ -1400,4 +1442,3 @@ void *pqistreamer::locked_pop_out_data(uint32_t /*max_slice_size*/, uint32_t &si
return res ;
}

View File

@ -38,8 +38,8 @@ class RsSerialiser;
struct PartialPacketRecord
{
void *mem ;
uint32_t size ;
void *mem ;
uint32_t size ;
};
/**
@ -65,18 +65,23 @@ class pqistreamer: public PQInterface
virtual RsItem *GetItem();
virtual int status();
rstime_t getLastIncomingTS(); // Time of last data packet, for checking a connection is alive.
rstime_t getLastIncomingTS(); // Time of last data packet, for checking a connection is alive.
virtual void getRates(RsBwRates &rates);
virtual int getQueueSize(bool in); // extracting data.
virtual int getQueueSize_bytes(bool in); // size of incoming queue in bytes
virtual int gatherStatistics(std::list<RSTrafficClue>& outqueue_stats,std::list<RSTrafficClue>& inqueue_stats); // extracting data.
// mutex protected versions of RateInterface calls.
virtual void setRate(bool b,float f) ;
virtual void setMaxRate(bool b,float f) ;
virtual float getRate(bool b) ;
virtual void setMaxRate_locked(bool b,float f) ;
protected:
virtual int reset() ;
virtual float getRate(bool b) ;
virtual float getMaxRate(bool b) ;
virtual float getMaxRate_locked(bool b);
protected:
virtual int reset() ;
int tick_bio();
int tick_send(uint32_t timeout);
@ -104,12 +109,12 @@ class pqistreamer: public PQInterface
private:
int queue_outpqi_locked(RsItem *i,uint32_t& serialized_size);
int handleincomingitem_locked(RsItem *i, int len);
int handleincomingitem(RsItem *i, int len);
// ticked regularly (manages out queues and sending
// via above interfaces.
virtual int handleoutgoing_locked();
virtual int handleincoming_locked();
virtual int handleincoming();
// Bandwidth/Streaming Management.
float outTimeSlice_locked();
@ -117,11 +122,11 @@ class pqistreamer: public PQInterface
int outAllowedBytes_locked();
void outSentBytes_locked(uint32_t );
int inAllowedBytes_locked();
void inReadBytes_locked(uint32_t );
int inAllowedBytes();
void inReadBytes(uint32_t );
// cleans up everything that's pending / half finished.
void free_pend_locked();
void free_pend();
// RsSerialiser - determines which packets can be serialised.
RsSerialiser *mRsSerialiser;
@ -129,13 +134,12 @@ class pqistreamer: public PQInterface
void *mPkt_wpending; // storage for pending packet to write.
uint32_t mPkt_wpending_size; // ... and its size.
void allocate_rpend_locked(); // use these two functions to allocate/free the buffer below
void allocate_rpend(); // use these two functions to allocate/free the buffer below
int mPkt_rpend_size; // size of pkt_rpending.
void *mPkt_rpending; // storage for read in pending packets.
enum {reading_state_packet_started=1,
reading_state_initial=0 } ;
enum {reading_state_packet_started=1, reading_state_initial=0 } ;
int mReading_state ;
int mFailed_read_attempts ;
@ -144,7 +148,8 @@ class pqistreamer: public PQInterface
std::list<void *> mOutPkts; // Cntrl / Search / Results queue
std::list<RsItem *> mIncoming;
uint32_t mIncomingSize; // size of mIncoming. To avoid calling linear cost std::list::size()
uint32_t mIncomingSize; // size of mIncoming. To avoid calling linear cost std::list::size()
uint32_t mIncomingSize_bytes; // size of Incoming in btyes
// data for network stats.
int mTotalRead;
@ -154,8 +159,8 @@ class pqistreamer: public PQInterface
int mCurrRead;
int mCurrSent;
double mCurrReadTS; // TS from which these are measured.
double mCurrSentTS;
double mCurrReadTS; // TS from which these are measured.
double mCurrSentTS;
double mAvgLastUpdate; // TS from which these are measured.
uint32_t mAvgReadCount;
@ -174,12 +179,12 @@ class pqistreamer: public PQInterface
std::list<RSTrafficClue> mCurrentStatsChunk_Out ;
rstime_t mStatisticsTimeStamp ;
bool mAcceptsPacketSlicing ;
rstime_t mLastSentPacketSlicingProbe ;
void locked_addTrafficClue(const RsItem *pqi, uint32_t pktsize, std::list<RSTrafficClue> &lst);
RsItem *addPartialPacket_locked(const void *block, uint32_t len, uint32_t slice_packet_id,bool packet_starting,bool packet_ending,uint32_t& total_len);
bool mAcceptsPacketSlicing ;
rstime_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,uint32_t& total_len);
std::map<uint32_t,PartialPacketRecord> mPartialPackets ;
std::map<uint32_t,PartialPacketRecord> mPartialPackets ;
};
#endif //MRK_PQI_STREAMER_HEADER

View File

@ -23,17 +23,17 @@
#include "pqi/pqithreadstreamer.h"
#include <unistd.h>
#define DEFAULT_STREAMER_TIMEOUT 10000 // 10 ms.
#define DEFAULT_STREAMER_SLEEP 1000 // 1 ms.
#define DEFAULT_STREAMER_TIMEOUT 10000 // 10 ms
#define DEFAULT_STREAMER_SLEEP 30000 // 30 ms
#define DEFAULT_STREAMER_IDLE_SLEEP 1000000 // 1 sec
//#define PQISTREAMER_DEBUG
// #define PQISTREAMER_DEBUG
pqithreadstreamer::pqithreadstreamer(PQInterface *parent, RsSerialiser *rss, const RsPeerId& id, BinInterface *bio_in, int bio_flags_in)
:pqistreamer(rss, id, bio_in, bio_flags_in), mParent(parent), mTimeout(0), mThreadMutex("pqithreadstreamer")
{
mTimeout = DEFAULT_STREAMER_TIMEOUT;
mSleepPeriod = DEFAULT_STREAMER_SLEEP;
mTimeout = DEFAULT_STREAMER_TIMEOUT;
mSleepPeriod = DEFAULT_STREAMER_SLEEP;
}
bool pqithreadstreamer::RecvItem(RsItem *item)
@ -43,55 +43,59 @@ bool pqithreadstreamer::RecvItem(RsItem *item)
int pqithreadstreamer::tick()
{
RsStackMutex stack(mThreadMutex);
tick_bio();
// pqithreadstreamer mutex lock is not needed here
// we will only check if the connection is active, and if not we will try to establish it
tick_bio();
return 0;
}
void pqithreadstreamer::threadTick()
{
uint32_t recv_timeout = 0;
uint32_t sleep_period = 0;
bool isactive = false;
{
RsStackMutex stack(mStreamerMtx);
recv_timeout = mTimeout;
sleep_period = mSleepPeriod;
isactive = mBio->isactive();
}
uint32_t recv_timeout = 0;
uint32_t sleep_period = 0;
bool isactive = false;
{
RsStackMutex stack(mStreamerMtx);
recv_timeout = mTimeout;
sleep_period = mSleepPeriod;
isactive = mBio->isactive();
}
updateRates() ;
// update the connection rates
updateRates() ;
if (!isactive)
{
rstime::rs_usleep(DEFAULT_STREAMER_IDLE_SLEEP);
return ;
}
// if the connection est not active, long sleep then return
if (!isactive)
{
rstime::rs_usleep(DEFAULT_STREAMER_IDLE_SLEEP);
return ;
}
{
RsStackMutex stack(mThreadMutex);
tick_recv(recv_timeout);
}
// fill incoming queue with items from SSL
{
RsStackMutex stack(mThreadMutex);
tick_recv(recv_timeout);
}
// Push Items, Outside of Mutex.
RsItem *incoming = NULL;
while((incoming = GetItem()))
{
RecvItem(incoming);
}
// move items to appropriate service queue or shortcut to fast service
RsItem *incoming = NULL;
while((incoming = GetItem()))
{
RecvItem(incoming);
}
{
RsStackMutex stack(mThreadMutex);
tick_send(0);
}
// parse the outgoing queue and send items to SSL
{
RsStackMutex stack(mThreadMutex);
tick_send(0);
}
if (sleep_period)
{
rstime::rs_usleep(sleep_period);
}
// sleep
if (sleep_period)
{
rstime::rs_usleep(sleep_period);
}
}

View File

@ -33,6 +33,7 @@
#include "serialiser/rsserializable.h"
#include "serialiser/rstypeserializer.h"
#include "util/rstime.h"
#include "util/rsdebug.h"
class RsEvents;
@ -126,8 +127,7 @@ struct RsEventsErrorCategory: std::error_category
case RsEventsErrorNum::INVALID_HANDLER_ID:
return "Invalid handler id";
default:
return "Error message for error: " + std::to_string(ev) +
" not available in category: " + name();
return rsErrorNotInCategory(ev, name());
}
}

View File

@ -37,6 +37,7 @@
#include "util/rstime.h"
#include "retroshare/rsevents.h"
#include "util/rsmemory.h"
#include "util/rsdebug.h"
class RsFiles;
@ -63,8 +64,7 @@ struct RsFilesErrorCategory: std::error_category
case RsFilesErrorNum::FILES_HANDLE_NOT_FOUND:
return "Files handle not found";
default:
return "Error message for error: " + std::to_string(ev) +
" not available in category: " + name();
return rsErrorNotInCategory(ev, name());
}
}
@ -658,7 +658,8 @@ public:
* @brief Get file details
* @jsonapi{development}
* @param[in] hash file identifier
* @param[in] hintflags filtering hint (RS_FILE_HINTS_EXTRA|...|RS_FILE_HINTS_LOCAL)
* @param[in] hintflags filtering hint ( RS_FILE_HINTS_UPLOAD|...|
* RS_FILE_HINTS_EXTRA|RS_FILE_HINTS_LOCAL )
* @param[out] info storage for file information
* @return true if file found, false otherwise
*/

View File

@ -507,25 +507,27 @@ private:
std::map<uint32_t,TokenRequestType> mActiveTokens;
#ifdef DEBUG_GXSIFACEHELPER
void locked_dumpTokens()
{
const uint16_t service_id = mGxs.serviceType();
const auto countSize = static_cast<size_t>(TokenRequestType::__MAX);
uint32_t count[countSize] = {0};
RsDbg() << __PRETTY_FUNCTION__ << "Service 0x" << std::hex << service_id
<< " (" << rsServiceControl->getServiceName(
RsServiceInfo::RsServiceInfoUIn16ToFullServiceId(service_id) )
<< ") this=0x" << static_cast<void*>(this)
<< ") Active tokens (per type): ";
RsDbg rsdbg;
rsdbg << __PRETTY_FUNCTION__ << " Service 0x" << std::hex << service_id
<< " (" << rsServiceControl->getServiceName(
RsServiceInfo::RsServiceInfoUIn16ToFullServiceId(service_id) )
<< ") this=0x" << static_cast<void*>(this)
<< ") Active tokens (per type): ";
// let's count how many token of each type we've got.
for(auto& it: mActiveTokens) ++count[static_cast<size_t>(it.second)];
for(uint32_t i=0; i < countSize; ++i)
RsDbg().uStream() /* << i << ":" */ << count[i] << " ";
RsDbg().uStream() << std::endl;
rsdbg /* << i << ":" */ << count[i] << " ";
}
#endif // def DEBUG_GXSIFACEHELPER
RS_SET_CONTEXT_DEBUG_LEVEL(1)
};

View File

@ -20,8 +20,7 @@
*******************************************************************************/
#pragma once
/// RetroShare initialization and login API
/// @file RetroShare initialization and login API
// Initialize ok, result >= 0
#define RS_INIT_OK 0 // Initialize ok
@ -32,11 +31,15 @@
#define RS_INIT_NO_KEYRING -3 // Keyring is empty. Need to import it.
#define RS_INIT_NO_EXECUTABLE -4 // executable path hasn't been set in config options
#include <stdint.h>
#include <list>
#include <map>
#include <vector>
#include <retroshare/rstypes.h>
#include <cstdint>
#include <system_error>
#include "retroshare/rstypes.h"
#include "retroshare/rsversion.h"
class RsLoginHelper;
@ -46,6 +49,71 @@ class RsLoginHelper;
*/
extern RsLoginHelper* rsLoginHelper;
enum class RsInitErrorNum : int32_t
{
ALREADY_LOGGED_IN = 6000,
CANT_ACQUIRE_LOCK = 6001,
INVALID_LOCATION_NAME = 6002,
PGP_NAME_OR_ID_NEEDED = 6003,
PGP_KEY_CREATION_FAILED = 6004,
SSL_KEY_CREATION_FAILED = 6005,
INVALID_SSL_ID = 6006,
LOGIN_FAILED = 6007
};
struct RsInitErrorCategory: std::error_category
{
const char* name() const noexcept override
{ return "RetroShare init"; }
std::string message(int ev) const override
{
switch (static_cast<RsInitErrorNum>(ev))
{
case RsInitErrorNum::ALREADY_LOGGED_IN:
return "Already logged in";
case RsInitErrorNum::CANT_ACQUIRE_LOCK:
return "Cannot aquire lock on location data. Another instance is "
"already running with this profile?";
case RsInitErrorNum::INVALID_LOCATION_NAME:
return "Invalid location name";
case RsInitErrorNum::PGP_NAME_OR_ID_NEEDED:
return "Either PGP name or PGP id is needed";
case RsInitErrorNum::PGP_KEY_CREATION_FAILED:
return "Failure creating PGP key";
case RsInitErrorNum::SSL_KEY_CREATION_FAILED:
return "Failure creating SSL key";
case RsInitErrorNum::INVALID_SSL_ID:
return "Invalid SSL id";
case RsInitErrorNum::LOGIN_FAILED:
return "Generic login failure";
default:
return rsErrorNotInCategory(ev, name());
}
}
const static RsInitErrorCategory instance;
};
namespace std
{
/** Register RsJsonApiErrorNum as an error condition enum, must be in std
* namespace */
template<> struct is_error_condition_enum<RsInitErrorNum> : true_type {};
}
/** Provide RsInitErrorNum conversion to std::error_condition, must be in
* same namespace of RsInitErrorNum */
inline std::error_condition make_error_condition(RsInitErrorNum e) noexcept
{
return std::error_condition(
static_cast<int>(e), RsInitErrorCategory::instance );
};
/**
* @brief The RsInitConfig struct
* This class contains common configuration options, that executables using libretroshare may want to
@ -85,7 +153,7 @@ struct RsConfigOptions
class RsInit
{
public:
enum LoadCertificateStatus : uint8_t
enum RS_DEPRECATED_FOR(RsInitErrorNum) LoadCertificateStatus : uint8_t
{
OK, /// Everything go as expected, no error occurred
ERR_ALREADY_RUNNING, /// Another istance is running already
@ -317,7 +385,7 @@ public:
/**
* @brief Normal way to attempt login
* @jsonapi{development,manualwrapper}
* @jsonapi{development,unauthenticated}
* @param[in] account Id of the account to which attempt login
* @param[in] password Password for the given account
* @return RsInit::OK if login attempt success, error code otherwhise
@ -353,6 +421,44 @@ public:
void getLocations(std::vector<RsLoginHelper::Location>& locations);
/**
* @brief Creates a new RetroShare location, and log in once is created
* @jsonapi{development,manualwrapper}
* @param[out] locationId storage for generated location SSL id
* @param[inout] pgpId specify PGP id to use to sign the location, if a null
* id is passed the PGP key is created too and this param is used as
* storage for its id.
* @param[in] password to protect and unlock the associated PGP key
* param[in] apiUser (JSON API only) string containing username for JSON API
* so it can be later used to authenticate JSON API calls. It is passed
* down to @see RsJsonApi::authorizeUser under the hood.
* param[in] apiPass (JSON API only) string containing password for JSON API
* so it can be later used to authenticate JSON API calls. It is passed
* down to @see RsJsonApi::authorizeUser under the hood.
* To improve security we strongly advise to not use the same as the
* password used for the PGP key.
* @return Success or error information
*/
std::error_condition createLocationV2(
RsPeerId& locationId,
RsPgpId& pgpId,
const std::string& locationName,
const std::string& pgpName,
const std::string& password
/* JSON API only
* const std::string& apiUser
* const std::string& apiPass */ );
/**
* @brief Check if RetroShare is already logged in, this usually return true
* after a successfull attemptLogin() and before closeSession()
* @jsonapi{development,unauthenticated}
* @return true if already logged in, false otherwise
*/
bool isLoggedIn();
#if !RS_VERSION_AT_LEAST(0,6,6)
/**
* @deprecated Use @see createLocationV2 instead
* @brief Creates a new RetroShare location, and log in once is created
* @jsonapi{development,manualwrapper}
* @param[inout] location provide input information to generate the location
@ -365,15 +471,9 @@ public:
* Tor hidden location. UNTESTED!
* @return true if success, false otherwise
*/
RS_DEPRECATED_FOR(createLocationV2)
bool createLocation( RsLoginHelper::Location& location,
const std::string& password, std::string& errorMessage,
bool makeHidden = false, bool makeAutoTor = false );
/**
* @brief Check if RetroShare is already logged in, this usually return true
* after a successfull attemptLogin() and before closeSession()
* @jsonapi{development,unauthenticated}
* @return true if already logged in, false otherwise
*/
bool isLoggedIn();
#endif // !RS_VERSION_AT_LEAST(0,6,6)
};

View File

@ -29,6 +29,7 @@
#include <cstdint>
#include <system_error>
#include "util/rsdebug.h"
#include "util/rsmemory.h"
class RsJsonApi;
@ -74,8 +75,7 @@ struct RsJsonApiErrorCategory: std::error_category
case RsJsonApiErrorNum::NOT_A_MACHINE_GUN:
return "Method must not be called in burst";
default:
return "Error message for error: " + std::to_string(ev) +
" not available in category: " + name();
return rsErrorNotInCategory(ev, name());
}
}

View File

@ -143,13 +143,14 @@ void RsServer::threadTick()
// if there is time left, we sleep
double timeToSleep = mTickInterval - mAvgRunDuration;
if (timeToSleep > 0)
{
// never sleep less than 50 ms
if (timeToSleep < 0.050)
timeToSleep = 0.050;
#ifdef TICK_DEBUG
RsDbg() << "TICK_DEBUG will sleep " << timeToSleep << " ms" << std::endl;
RsDbg() << "TICK_DEBUG will sleep " << (int) (1000 * timeToSleep) << " ms" << std::endl;
#endif
rstime::rs_usleep(timeToSleep * 1000000);
}
rstime::rs_usleep(timeToSleep * 1000000);
double ts = getCurrentTS();
mLastts = ts;
@ -229,12 +230,16 @@ void RsServer::threadTick()
// ticking is done, now compute new values of mLastRunDuration, mAvgRunDuration and mTickInterval
ts = getCurrentTS();
mLastRunDuration = ts - mLastts;
// low-pass filter and don't let mAvgRunDuration exceeds maxTickInterval
mAvgRunDuration = 0.1 * mLastRunDuration + 0.9 * mAvgRunDuration;
if (mAvgRunDuration > maxTickInterval)
mAvgRunDuration = maxTickInterval;
#ifdef TICK_DEBUG
RsDbg() << "TICK_DEBUG new mLastRunDuration " << mLastRunDuration << " mAvgRunDuration " << mAvgRunDuration << std::endl;
if (mLastRunDuration > WARN_BIG_CYCLE_TIME)
RsDbg() << "TICK_DEBUG excessively long lycle time " << mLastRunDuration << std::endl;
RsDbg() << "TICK_DEBUG excessively long cycle time " << mLastRunDuration << std::endl;
#endif
// if the core has returned that there is more to tick we decrease the ticking interval, else we increse it
@ -250,7 +255,7 @@ void RsServer::threadTick()
RsDbg() << "TICK_DEBUG new tick interval " << mTickInterval << std::endl;
#endif
// keep the tick interval within allowed limits
// keep the tick interval target within allowed limits
if (mTickInterval < minTickInterval)
mTickInterval = minTickInterval;
else if (mTickInterval > maxTickInterval)

View File

@ -161,7 +161,9 @@ public:
p3ChatService *chatSrv;
p3StatusService *mStatusSrv;
p3GxsTunnelService *mGxsTunnels;
#ifdef RS_USE_I2P_BOB
p3I2pBob *mI2pBob;
#endif
// This list contains all threaded services. It will be used to shut them down properly.

View File

@ -114,6 +114,8 @@ RsLoginHelper* rsLoginHelper = nullptr;
RsAccounts* rsAccounts = nullptr;
const RsInitErrorCategory RsInitErrorCategory::instance;
RsConfigOptions::RsConfigOptions()
:
autoLogin(false),
@ -921,8 +923,10 @@ int RsServer::StartupRetroShare()
mNetMgr->setManagers(mPeerMgr, mLinkMgr);
rsAutoProxyMonitor *autoProxy = rsAutoProxyMonitor::instance();
#ifdef RS_USE_I2P_BOB
mI2pBob = new p3I2pBob(mPeerMgr);
autoProxy->addProxy(autoProxyType::I2PBOB, mI2pBob);
#endif
//load all the SSL certs as friends
// std::list<std::string> sslIds;
@ -1647,7 +1651,9 @@ int RsServer::StartupRetroShare()
mConfigMgr->addConfiguration("wire.cfg", wire_ns);
#endif
#endif //RS_ENABLE_GXS
#ifdef RS_USE_I2P_BOB
mConfigMgr->addConfiguration("I2PBOB.cfg", mI2pBob);
#endif
mPluginsManager->addConfigurations(mConfigMgr) ;
@ -1722,7 +1728,7 @@ int RsServer::StartupRetroShare()
// now enable bob
bobSettings bs;
autoProxy->taskSync(autoProxyType::I2PBOB, autoProxyTask::getSettings, &bs);
bs.enableBob = true;
bs.enable = true;
autoProxy->taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &bs);
} else {
std::cerr << "RsServer::StartupRetroShare failed to receive keys" << std::endl;
@ -1793,7 +1799,9 @@ int RsServer::StartupRetroShare()
/**************************************************************************/
// auto proxy threads
#ifdef RS_USE_I2P_BOB
startServiceThread(mI2pBob, "I2P-BOB");
#endif
#ifdef RS_ENABLE_GXS
// Must Set the GXS pointers before starting threads.
@ -1950,6 +1958,47 @@ void RsLoginHelper::getLocations(std::vector<RsLoginHelper::Location>& store)
}
}
std::error_condition RsLoginHelper::createLocationV2(
RsPeerId& locationId, RsPgpId& pgpId,
const std::string& locationName, const std::string& pgpName,
const std::string& password )
{
if(isLoggedIn()) return RsInitErrorNum::ALREADY_LOGGED_IN;
if(locationName.empty()) return RsInitErrorNum::INVALID_LOCATION_NAME;
if(pgpId.isNull() && pgpName.empty())
return RsInitErrorNum::PGP_NAME_OR_ID_NEEDED;
std::string errorMessage;
if(pgpId.isNull() && !RsAccounts::GeneratePGPCertificate(
pgpName, "", password, pgpId, 4096, errorMessage ) )
{
RS_ERR("Failure creating PGP key: ", errorMessage);
return RsInitErrorNum::PGP_KEY_CREATION_FAILED;
}
std::string sslPassword =
RsRandom::random_alphaNumericString(RsInit::getSslPwdLen());
rsNotify->cachePgpPassphrase(password);
rsNotify->setDisableAskPassword(true);
bool ret = RsAccounts::createNewAccount(
pgpId, "", locationName, "", false, false, sslPassword,
locationId, errorMessage );
if(!ret)
{
RS_ERR("Failure creating SSL key: ", errorMessage);
return RsInitErrorNum::SSL_KEY_CREATION_FAILED;
}
RsInit::LoadPassword(sslPassword);
ret = (RsInit::OK == attemptLogin(locationId, password));
rsNotify->setDisableAskPassword(false);
return (ret ? std::error_condition() : RsInitErrorNum::LOGIN_FAILED);
}
#if !RS_VERSION_AT_LEAST(0,6,6)
bool RsLoginHelper::createLocation(
RsLoginHelper::Location& l, const std::string& password,
std::string& errorMessage, bool makeHidden, bool makeAutoTor )
@ -1991,6 +2040,7 @@ bool RsLoginHelper::createLocation(
rsNotify->setDisableAskPassword(false);
return ret;
}
#endif // !RS_VERSION_AT_LEAST(0,6,6)
bool RsLoginHelper::isLoggedIn()
{

View File

@ -26,6 +26,7 @@
#include "rsloginhandler.h"
#include "util/rsdir.h"
#include "retroshare/rsinit.h"
#include "util/rsdebug.h"
//#define DEBUG_RSLOGINHANDLER 1
@ -497,8 +498,15 @@ bool RsLoginHandler::enableAutoLogin(const RsPeerId& ssl_id,const std::string& s
NULL);
if (error) {
RsErr() << __PRETTY_FUNCTION__
<< " Could not store passwd using libsecret with"
<< " error.code=" << error->code
<< " error.domain=" << error->domain
<< " error.message=\"" << error->message << "\"" << std::endl;
if (error->code == 2)
RsErr() << "Do have a key wallet installed?" << std::endl
<< "Like gnome-keyring or other using \"Secret Service\" by DBus." << std::endl;
g_error_free (error);
std::cerr << "Could not store passwd using libsecret" << std::endl;
return false;
}
std::cout << "Stored passwd " << "************************" << " using libsecret" << std::endl;

View File

@ -235,8 +235,7 @@ template<> bool RsTypeSerializer::from_JSON( \
\
if(!ret) \
{ \
Dbg3() << __PRETTY_FUNCTION__ << " " << memberName << " not found" \
<< std::endl; \
RS_DBG3(memberName, " not found"); \
return false; \
} \
\
@ -503,8 +502,16 @@ bool RsTypeSerializer::from_JSON( const std::string& /*memberName*/,
// Binary blocks //
//============================================================================//
#if __cplusplus < 201703L
/* Solve weird undefined reference error with C++ < 17 see:
* https://stackoverflow.com/questions/8016780/undefined-reference-to-static-constexpr-char
*/
/*static*/ decltype(RsTypeSerializer::RawMemoryWrapper::base64_key) constexpr
RsTypeSerializer::RawMemoryWrapper::base64_key;
/*static*/ /* without this Android compilation breaks */
constexpr uint32_t RsTypeSerializer::RawMemoryWrapper::MAX_SERIALIZED_CHUNK_SIZE;
#endif
/*static*/
void RsTypeSerializer::RawMemoryWrapper::serial_process(
@ -542,18 +549,7 @@ void RsTypeSerializer::RawMemoryWrapper::serial_process(
ctx.mOffset += second;
break;
case RsGenericSerializer::DESERIALIZE:
if(first || second)
{
/* Items are created anew before deserialization so buffer pointer
* must be null and size 0 at this point */
RsWarn() << __PRETTY_FUNCTION__ << " DESERIALIZE got uninitialized "
<< " or pre-allocated buffer! Buffer pointer: " << first
<< " must be null and size: " << second << " must be 0 at "
<< "this point. Does your item costructor initialize them "
<< "properly?" << std::endl;
print_stacktrace();
}
freshMemCheck();
RS_SERIAL_PROCESS(second);
if(!ctx.mOk) break;
@ -597,44 +593,33 @@ void RsTypeSerializer::RawMemoryWrapper::serial_process(
if(!ctx.mOk) break;
std::string encodedValue;
RsBase64::encode(first, second, encodedValue, true, false);
ctx.mJson.SetString(
encodedValue.data(),
static_cast<rapidjson::SizeType>(encodedValue.length()),
ctx.mJson.GetAllocator());
ctx.mOk = ctx.mOk &&
RsTypeSerializer::to_JSON(base64_key, encodedValue, ctx.mJson);
break;
}
case RsGenericSerializer::FROM_JSON:
{
const bool yelding = !!(
RsSerializationFlags::YIELDING & ctx.mFlags );
if(!(ctx.mOk || yelding))
{
clear();
break;
}
if(!ctx.mJson.IsString())
{
RsErr() << __PRETTY_FUNCTION__ << " "
<< std::errc::invalid_argument << std::endl;
print_stacktrace();
freshMemCheck();
ctx.mOk = false;
clear();
break;
}
if( ctx.mJson.GetStringLength() >
const auto failure = [&]() -> void { ctx.mOk = false; clear(); };
const bool yielding = !!(
RsSerializationFlags::YIELDING & ctx.mFlags );
if(!(ctx.mOk || yielding)) return failure();
std::string encodedValue;
if(!RsTypeSerializer::from_JSON(
base64_key, encodedValue, ctx.mJson )) return failure();
if( encodedValue.length() >
RsBase64::encodedSize(MAX_SERIALIZED_CHUNK_SIZE, true) )
{
RsErr() << __PRETTY_FUNCTION__ << " "
<< std::errc::message_size << std::endl;
print_stacktrace();
ctx.mOk = false;
clear();
break;
return failure();
}
std::string encodedValue = ctx.mJson.GetString();
std::vector<uint8_t> decoded;
auto ec = RsBase64::decode(encodedValue, decoded);
if(ec)
@ -642,9 +627,7 @@ void RsTypeSerializer::RawMemoryWrapper::serial_process(
RsErr() << __PRETTY_FUNCTION__ << " " << ec << std::endl;
print_stacktrace();
ctx.mOk = false;
clear();
break;
return failure();
}
const auto decodedSize = decoded.size();
@ -655,11 +638,8 @@ void RsTypeSerializer::RawMemoryWrapper::serial_process(
break;
}
if(decodedSize != second)
{
first = reinterpret_cast<uint8_t*>(realloc(first, decodedSize));
second = static_cast<uint32_t>(decodedSize);
}
first = reinterpret_cast<uint8_t*>(malloc(decodedSize));
second = static_cast<uint32_t>(decodedSize);
memcpy(first, decoded.data(), second);
break;
@ -675,6 +655,24 @@ void RsTypeSerializer::RawMemoryWrapper::clear()
second = 0;
}
bool RsTypeSerializer::RawMemoryWrapper::freshMemCheck()
{
if(first || second)
{
/* Items are created anew before deserialization so buffer pointer
* must be null and size 0 at this point */
RsWarn() << __PRETTY_FUNCTION__ << " got uninitialized "
<< " or pre-allocated buffer! Buffer pointer: " << first
<< " must be null and size: " << second << " must be 0 at "
<< "this point. Does your item costructor initialize them "
<< "properly?" << std::endl;
print_stacktrace();
return false;
}
return true;
}
//============================================================================//
// std::error_condition //
//============================================================================//

View File

@ -39,7 +39,7 @@
#include "serialiser/rsserializer.h"
#include "serialiser/rsserializable.h"
#include "util/rsjson.h"
#include "util/rsdebug.h"
#include "util/rsdebuglevel1.h"
#include "util/cxx14retrocompat.h"
@ -59,12 +59,17 @@ struct RsTypeSerializer
/// Maximum supported size 10MB
static constexpr uint32_t MAX_SERIALIZED_CHUNK_SIZE = 10*1024*1024;
/** Key used for JSON serialization.
* @note Changing this value breaks JSON API retro-compatibility */
static constexpr char base64_key[] = "base64";
/// @see RsSerializable
void serial_process(
RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx ) override;
private:
void clear();
bool freshMemCheck();
};
/// Most types are not valid sequence containers
@ -710,12 +715,9 @@ struct RsTypeSerializer
E& member,
const std::string& memberName )
{
#ifdef RSSERIAL_DEBUG
std::cerr << __PRETTY_FUNCTION__ << " processing enum: "
<< typeid(E).name() << " as "
<< typeid(typename std::underlying_type<E>::type).name()
<< std::endl;
#endif
RS_DBG4( "processing enum: ", typeid(E).name(), " as ",
typeid(typename std::underlying_type<E>::type).name() );
serial_process(
j, ctx,
reinterpret_cast<typename std::underlying_type<E>::type&>(member),
@ -777,9 +779,9 @@ struct RsTypeSerializer
{
if(!yielding)
{
std::cerr << __PRETTY_FUNCTION__ << " \"" << memberName
<< "\" not found in JSON:" << std::endl
<< jDoc << std::endl << std::endl;
RsErr() << __PRETTY_FUNCTION__ << " \"" << memberName
<< "\" not found in JSON:" << std::endl
<< jDoc << std::endl << std::endl;
print_stacktrace();
}
ctx.mOk = false;
@ -790,9 +792,9 @@ struct RsTypeSerializer
if(!v.IsObject())
{
std::cerr << __PRETTY_FUNCTION__ << " \"" << memberName
<< "\" has wrong type in JSON, object expected, got:"
<< std::endl << jDoc << std::endl << std::endl;
RsErr() << __PRETTY_FUNCTION__ << " \"" << memberName
<< "\" has wrong type in JSON, object expected, got:"
<< std::endl << jDoc << std::endl << std::endl;
print_stacktrace();
ctx.mOk = false;
break;
@ -999,14 +1001,16 @@ protected:
uint8_t data[], uint32_t size, uint32_t &offset, T member )
{
std::decay_t<T> backupMember = member;
#if RS_DEBUG_LEVEL >= 3
uint32_t offsetBackup = offset;
#endif
bool ok = true;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wbool-compare"
/* Check with < and not with <= here as we write last byte after
* the loop. Order of && operands very important here! */
while(member > 127 && (ok = offset < size))
while(member > 127 && (ok = (offset < size)))
{
// | 128: Set the next byte flag
data[offset++] = (static_cast<uint8_t>(member & 127)) | 128;
@ -1031,13 +1035,13 @@ protected:
data[offset++] = static_cast<uint8_t>(member & 127);
Dbg3() << __PRETTY_FUNCTION__ << " backupMember: " << backupMember
<< " offsetBackup: " << offsetBackup << " offeset: " << offset
<< " serialized as: ";
#if RS_DEBUG_LEVEL >= 3
RsDbg tdbg( __PRETTY_FUNCTION__, " backupMember: ", backupMember,
" offsetBackup: ", offsetBackup, " offeset: ", offset,
" serialized as: " );
for(; offsetBackup < offset; ++offsetBackup)
Dbg3().uStream() << " " << std::bitset<8>(data[offsetBackup]);
Dbg3().uStream() << std::endl;
tdbg << " " << std::bitset<8>(data[offsetBackup]);
#endif
return ok;
}
@ -1077,13 +1081,13 @@ protected:
/* If return is not triggered inside the for loop, either the buffer
* ended before we encountered the end of the number, or the number
* is VLQ encoded improperly */
RsErr() << __PRETTY_FUNCTION__ << std::errc::illegal_byte_sequence
<< " size: " << size
<< " offsetBackup: " << offsetBackup
<< " offset: " << offset << " bytes: ";
RsErr rserr;
rserr << __PRETTY_FUNCTION__ << std::errc::illegal_byte_sequence
<< " size: " << size
<< " offsetBackup: " << offsetBackup
<< " offset: " << offset << " bytes: ";
for(; offsetBackup < offset; ++offsetBackup)
RsErr().uStream() << " " << std::bitset<8>(data[offsetBackup]);
RsErr().uStream() << std::endl;
rserr << " " << std::bitset<8>(data[offsetBackup]);
print_stacktrace();
return false;
@ -1146,7 +1150,7 @@ protected:
struct ErrConditionWrapper : RsSerializable
{
ErrConditionWrapper(const std::error_condition& ec): mec(ec) {}
explicit ErrConditionWrapper(const std::error_condition& ec): mec(ec) {}
/** supports only TO_JSON if a different SerializeJob is passed it will
* explode at runtime */

View File

@ -43,21 +43,14 @@ static const std::string kConfigKeyOutLength = "OUT_LENGTH";
static const std::string kConfigKeyOutQuantity = "OUT_QUANTITY";
static const std::string kConfigKeyOutVariance = "OUT_VARIANCE";
static const bool kDefaultBOBEnable = false;
static const int8_t kDefaultLength = 3;
static const int8_t kDefaultQuantity = 4;
static const int8_t kDefaultVariance = 0;
/// Sleep duration for receiving loop
static const useconds_t sleepTimeRecv = 10; // times 1000 = 10ms
/// Sleep duration for receiving loop in error/no-data case
static const useconds_t sleepTimeRecv = 250; // times 1000 = 250ms
/// Sleep duration for everything else
static const useconds_t sleepTimeWait = 50; // times 1000 = 50ms or 0.05s
static const int sleepFactorDefault = 10; // 0.5s
static const int sleepFactorFast = 1; // 0.05s
static const int sleepFactorSlow = 20; // 1s
static struct RsLog::logInfo i2pBobLogInfo = {RsLog::Default, "p3I2pBob"};
static const rstime_t selfCheckPeroid = 30;
void doSleep(useconds_t timeToSleepMS) {
@ -74,15 +67,7 @@ p3I2pBob::p3I2pBob(p3PeerMgr *peerMgr)
mProcessing(NULL), mLock("I2P-BOB")
{
// set defaults
mSetting.enableBob = kDefaultBOBEnable;
mSetting.keys = "";
mSetting.addr = "";
mSetting.inLength = kDefaultLength;
mSetting.inQuantity = kDefaultQuantity;
mSetting.inVariance = kDefaultVariance;
mSetting.outLength = kDefaultLength;
mSetting.outQuantity = kDefaultQuantity;
mSetting.outVariance = kDefaultVariance;
mSetting.initDefault();
mCommands.clear();
}
@ -90,12 +75,12 @@ p3I2pBob::p3I2pBob(p3PeerMgr *peerMgr)
bool p3I2pBob::isEnabled()
{
RS_STACK_MUTEX(mLock);
return mSetting.enableBob;
return mSetting.enable;
}
bool p3I2pBob::initialSetup(std::string &addr, uint16_t &/*port*/)
{
std::cout << "p3I2pBob::initialSetup" << std::endl;
RS_DBG("");
// update config
{
@ -108,7 +93,7 @@ bool p3I2pBob::initialSetup(std::string &addr, uint16_t &/*port*/)
}
}
std::cout << "p3I2pBob::initialSetup config updated" << std::endl;
RS_DBG("config updated");
// request keys
// p3I2pBob::stateMachineBOB expects mProcessing to be set therefore
@ -118,12 +103,12 @@ bool p3I2pBob::initialSetup(std::string &addr, uint16_t &/*port*/)
fakeTicket->task = autoProxyTask::receiveKey;
processTaskAsync(fakeTicket);
std::cout << "p3I2pBob::initialSetup fakeTicket requested" << std::endl;
RS_DBG("fakeTicket requested");
// now start thread
start("I2P-BOB gen key");
std::cout << "p3I2pBob::initialSetup thread started" << std::endl;
RS_DBG("thread started");
int counter = 0;
// wait for keys
@ -137,24 +122,24 @@ bool p3I2pBob::initialSetup(std::string &addr, uint16_t &/*port*/)
break;
if (++counter > 30) {
std::cout << "p3I2pBob::initialSetup timeout!" << std::endl;
RS_DBG4("timeout!");
return false;
}
}
std::cout << "p3I2pBob::initialSetup got keys" << std::endl;
RS_DBG("got keys");
// stop thread
fullstop();
std::cout << "p3I2pBob::initialSetup thread stopped" << std::endl;
RS_DBG("thread stopped");
{
RS_STACK_MUTEX(mLock);
addr = mSetting.addr;
addr = mSetting.address.base32;
}
std::cout << "p3I2pBob::initialSetup addr '" << addr << "'" << std::endl;
RS_DBG4("addr ", addr);
return true;
}
@ -172,7 +157,7 @@ void p3I2pBob::processTaskAsync(taskTicket *ticket)
}
break;
default:
rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::processTaskAsync unknown task");
RS_DBG("unknown task");
rsAutoProxyMonitor::taskError(ticket);
break;
}
@ -187,7 +172,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket)
case autoProxyTask::status:
// check if everything needed is set
if (!data) {
rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::status autoProxyTask::status data is missing");
RS_DBG("autoProxyTask::status data is missing");
rsAutoProxyMonitor::taskError(ticket);
break;
}
@ -201,7 +186,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket)
case autoProxyTask::getSettings:
// check if everything needed is set
if (!data) {
rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::data_tick autoProxyTask::getSettings data is missing");
RS_DBG("autoProxyTask::getSettings data is missing");
rsAutoProxyMonitor::taskError(ticket);
break;
}
@ -215,7 +200,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket)
case autoProxyTask::setSettings:
// check if everything needed is set
if (!data) {
rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::data_tick autoProxyTask::setSettings data is missing");
RS_DBG("autoProxyTask::setSettings data is missing");
rsAutoProxyMonitor::taskError(ticket);
break;
}
@ -235,7 +220,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket)
break;
case autoProxyTask::getErrorInfo:
if (!data) {
rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::data_tick autoProxyTask::getErrorInfo data is missing");
RS_DBG("autoProxyTask::getErrorInfo data is missing");
rsAutoProxyMonitor::taskError(ticket);
} else {
RS_STACK_MUTEX(mLock);
@ -244,34 +229,12 @@ void p3I2pBob::processTaskSync(taskTicket *ticket)
}
break;
default:
rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::processTaskSync unknown task");
RS_DBG("unknown task");
rsAutoProxyMonitor::taskError(ticket);
break;
}
}
std::string p3I2pBob::keyToBase32Addr(const std::string &key)
{
std::string copy(key);
// replace I2P specific chars
std::replace(copy.begin(), copy.end(), '~', '/');
std::replace(copy.begin(), copy.end(), '-', '+');
// decode
std::vector<uint8_t> bin = Radix64::decode(copy);
// hash
std::vector<uint8_t> sha256 = RsUtil::BinToSha256(bin);
// encode
std::string out = Radix32::encode(sha256);
// i2p uses lowercase
std::transform(out.begin(), out.end(), out.begin(), ::tolower);
out.append(".b32.i2p");
return out;
}
bool inline isAnswerOk(const std::string &answer) {
return (answer.compare(0, 2, "OK") == 0);
}
@ -284,10 +247,8 @@ void p3I2pBob::threadTick()
{
int sleepTime = 0;
{
RS_STACK_MUTEX(mLock);
std::stringstream ss;
ss << "data_tick mState: " << mState << " mTask: " << mTask << " mBOBState: " << mBOBState << " mPending: " << mPending.size();
rslog(RsLog::Debug_All, &i2pBobLogInfo, ss.str());
RS_STACK_MUTEX(mLock);
RS_DBG4("data_tick mState: ", mState, " mTask: ", mTask, " mBOBState: ", mBOBState, " mPending: ", mPending.size());
}
sleepTime += stateMachineController();
@ -326,15 +287,13 @@ int p3I2pBob::stateMachineBOB()
if (mBOBState == bsList) {
int counter = 0;
while (answer.find("OK Listing done") == std::string::npos) {
std::stringstream ss;
ss << "stateMachineBOB status check: read loop, counter: " << counter;
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, ss.str());
RS_DBG3("stateMachineBOB status check: read loop, counter: ", counter);
answer += recv();
counter++;
}
if (answer.find(mTunnelName) == std::string::npos) {
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineBOB status check: tunnel down!");
RS_DBG("status check: tunnel down!");
// signal error
*((bool *)mProcessing->data) = true;
}
@ -346,12 +305,12 @@ int p3I2pBob::stateMachineBOB()
switch (mBOBState) {
case bsNewkeysN:
key = answer.substr(3, answer.length()-3);
mSetting.addr = keyToBase32Addr(key);
mSetting.address.base32 = i2p::keyToBase32Addr(key);
IndicateConfigChanged();
break;
case bsGetkeys:
key = answer.substr(3, answer.length()-3);
mSetting.keys = key;
mSetting.address.privateKey = key;
IndicateConfigChanged();
break;
default:
@ -374,8 +333,8 @@ int p3I2pBob::stateMachineBOB_locked_failure(const std::string &answer, const bo
return sleepFactorDefault;
}
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineBOB FAILED to run command '" + currentState.command + "'");
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineBOB '" + answer + "'");
RS_DBG("FAILED to run command: ", currentState.command);
RS_DBG("answer: ", answer);
mErrorMsg.append("FAILED to run command '" + currentState.command + "'" + '\n');
mErrorMsg.append("reason '" + answer + "'" + '\n');
@ -422,14 +381,14 @@ int p3I2pBob::stateMachineController()
return stateMachineController_locked_idle();
case csDoConnect:
if (!connectI2P()) {
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController doConnect: unable to connect");
RS_DBG("doConnect: unable to connect");
mStateOld = mState;
mState = csError;
mErrorMsg = "unable to connect to BOB port";
return sleepFactorSlow;
}
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController doConnect: connected");
RS_DBG4("doConnect: connected");
mState = csConnected;
break;
case csConnected:
@ -437,7 +396,7 @@ int p3I2pBob::stateMachineController()
case csWaitForBob:
// check connection problems
if (mSocket == 0) {
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController waitForBob: conection lost");
RS_DBG("waitForBob: conection lost");
mStateOld = mState;
mState = csError;
mErrorMsg = "connection lost to BOB";
@ -447,21 +406,21 @@ int p3I2pBob::stateMachineController()
// check for finished BOB protocol
if (mBOBState == bsCleared) {
// done
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController waitForBob: mBOBState == bsCleared");
RS_DBG4("waitForBob: mBOBState == bsCleared");
mState = csDoDisconnect;
}
break;
case csDoDisconnect:
if (!disconnectI2P() || mSocket != 0) {
// just in case
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController doDisconnect: can't disconnect");
RS_DBG("doDisconnect: can't disconnect");
mStateOld = mState;
mState = csError;
mErrorMsg = "unable to disconnect from BOB";
return sleepFactorDefault;
}
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController doDisconnect: disconnected");
RS_DBG4("doDisconnect: disconnected");
mState = csDisconnected;
break;
case csDisconnected:
@ -487,12 +446,12 @@ int p3I2pBob::stateMachineController_locked_idle()
mProcessing = mPending.front();
mPending.pop();
if (!mSetting.enableBob && (
if (!mSetting.enable && (
mProcessing->task == autoProxyTask::start ||
mProcessing->task == autoProxyTask::stop ||
mProcessing->task == autoProxyTask::proxyStatusCheck)) {
// skip since we are not enabled
rslog(RsLog::Debug_Alert, &i2pBobLogInfo, "stateMachineController_locked_idle: disabled -> skipping ticket");
RS_DBG1("disabled -> skipping ticket");
rsAutoProxyMonitor::taskDone(mProcessing, autoProxyStatus::disabled);
mProcessing = NULL;
} else {
@ -514,7 +473,7 @@ int p3I2pBob::stateMachineController_locked_idle()
mTask = ctRunCheck;
break;
default:
rslog(RsLog::Debug_Alert, &i2pBobLogInfo, "stateMachineController_locked_idle unknown async task");
RS_DBG1("unknown async task");
rsAutoProxyMonitor::taskError(mProcessing);
mProcessing = NULL;
break;
@ -561,29 +520,29 @@ int p3I2pBob::stateMachineController_locked_connected()
switch (mTask) {
case ctRunSetUp:
// when we have a key use it for server tunnel!
if(mSetting.keys.empty()) {
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = setnickC");
if(mSetting.address.privateKey.empty()) {
RS_DBG4("setting mBOBState = setnickC");
mBOBState = bsSetnickC;
} else {
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = setnickS");
RS_DBG4("setting mBOBState = setnickS");
mBOBState = bsSetnickS;
}
break;
case ctRunShutDown:
// shut down existing tunnel
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = getnick");
RS_DBG4("setting mBOBState = getnick");
mBOBState = bsGetnick;
break;
case ctRunCheck:
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = list");
RS_DBG4("setting mBOBState = list");
mBOBState = bsList;
break;
case ctRunGetKeys:
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = setnickN");
RS_DBG4("setting mBOBState = setnickN");
mBOBState = bsSetnickN;
break;
case ctIdle:
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_connected: task is idle. This should not happen!");
RS_DBG("task is idle. This should not happen!");
break;
}
@ -599,7 +558,7 @@ int p3I2pBob::stateMachineController_locked_disconnected()
if(errorHappened) {
// reset old state
mStateOld = csIdel;
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_disconnected: error during process!");
RS_DBG("error during process!");
}
// answer ticket
@ -628,12 +587,12 @@ int p3I2pBob::stateMachineController_locked_disconnected()
mTask = mTaskOld;
if (!errorHappened) {
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_disconnected: run check result: ok");
RS_DBG4("run check result: ok");
break;
}
// switch to error
newState = csError;
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_disconnected: run check result: error");
RS_DBG("run check result: error");
mErrorMsg = "Connection check failed. Will try to restart tunnel.";
break;
@ -656,7 +615,7 @@ int p3I2pBob::stateMachineController_locked_disconnected()
mTask = mTaskOld;
break;
case ctIdle:
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_disconnected: task is idle. This should not happen!");
RS_DBG("task is idle. This should not happen!");
rsAutoProxyMonitor::taskError(mProcessing);
}
mProcessing = NULL;
@ -672,14 +631,12 @@ int p3I2pBob::stateMachineController_locked_error()
{
// wait for bob protocoll
if (mBOBState != bsCleared) {
rslog(RsLog::Debug_All, &i2pBobLogInfo, "stateMachineController_locked_error: waiting for BOB");
RS_DBG4("waiting for BOB");
return sleepFactorFast;
}
#if 0
std::stringstream ss;
ss << "stateMachineController_locked_error: mProcessing: " << (mProcessing ? "not null" : "null");
rslog(RsLog::Debug_All, &i2pBobLogInfo, ss.str());
RS_DBG4("stateMachineController_locked_error: mProcessing: ", (mProcessing ? "not null" : "null"));
#endif
// try to finish ticket
@ -687,7 +644,7 @@ int p3I2pBob::stateMachineController_locked_error()
switch (mTask) {
case ctRunCheck:
// connection check failed at some point
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_error: failed to check proxy status (it's likely dead)!");
RS_DBG("failed to check proxy status (it's likely dead)!");
*((bool *)mProcessing->data) = true;
mState = csDoDisconnect;
mStateOld = csIdel;
@ -695,7 +652,7 @@ int p3I2pBob::stateMachineController_locked_error()
break;
case ctRunShutDown:
// not a big deal though
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_error: failed to shut down tunnel (it's likely dead though)!");
RS_DBG("failed to shut down tunnel (it's likely dead though)!");
mState = csDoDisconnect;
mStateOld = csIdel;
mErrorMsg.clear();
@ -703,14 +660,14 @@ int p3I2pBob::stateMachineController_locked_error()
case ctIdle:
// should not happen but we need to deal with it
// this will produce some error messages in the log and finish the task (marked as failed)
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_error: task is idle. This should not happen!");
RS_DBG("task is idle. This should not happen!");
mState = csDoDisconnect;
mStateOld = csIdel;
mErrorMsg.clear();
break;
case ctRunGetKeys:
case ctRunSetUp:
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_error: failed to receive key / start up");
RS_DBG("failed to receive key / start up");
mStateOld = csError;
mState = csDoDisconnect;
// keep the error message
@ -721,7 +678,7 @@ int p3I2pBob::stateMachineController_locked_error()
// periodically retry
if (mLastProxyCheck < time(NULL) - (selfCheckPeroid >> 1) && mTask == ctRunSetUp) {
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_error: retrying");
RS_DBG("retrying");
mLastProxyCheck = time(NULL);
mErrorMsg.clear();
@ -734,7 +691,7 @@ int p3I2pBob::stateMachineController_locked_error()
// check for new tickets
if (!mPending.empty()) {
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_error: processing new ticket");
RS_DBG4("processing new ticket");
// reset and try new task
mTask = ctIdle;
@ -765,16 +722,16 @@ RsSerialiser *p3I2pBob::setupSerialiser()
bool p3I2pBob::saveList(bool &cleanup, std::list<RsItem *> &lst)
{
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "saveList");
RS_DBG4("");
cleanup = true;
RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet;
RsTlvKeyValue kv;
RS_STACK_MUTEX(mLock);
addKVS(vitem, kv, kConfigKeyBOBEnable, mSetting.enableBob ? "TRUE" : "FALSE")
addKVS(vitem, kv, kConfigKeyBOBKey, mSetting.keys)
addKVS(vitem, kv, kConfigKeyBOBAddr, mSetting.addr)
addKVS(vitem, kv, kConfigKeyBOBEnable, mSetting.enable ? "TRUE" : "FALSE")
addKVS(vitem, kv, kConfigKeyBOBKey, mSetting.address.privateKey)
addKVS(vitem, kv, kConfigKeyBOBAddr, mSetting.address.base32)
addKVSInt(vitem, kv, kConfigKeyInLength, mSetting.inLength)
addKVSInt(vitem, kv, kConfigKeyInQuantity, mSetting.inQuantity)
addKVSInt(vitem, kv, kConfigKeyInVariance, mSetting.inVariance)
@ -800,7 +757,7 @@ bool p3I2pBob::saveList(bool &cleanup, std::list<RsItem *> &lst)
bool p3I2pBob::loadList(std::list<RsItem *> &load)
{
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "loadList");
RS_DBG4("");
for(std::list<RsItem*>::const_iterator it = load.begin(); it!=load.end(); ++it) {
RsConfigKeyValueSet *vitem = dynamic_cast<RsConfigKeyValueSet*>(*it);
@ -808,11 +765,11 @@ bool p3I2pBob::loadList(std::list<RsItem *> &load)
RS_STACK_MUTEX(mLock);
for(std::list<RsTlvKeyValue>::const_iterator kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); ++kit) {
if (kit->key == kConfigKeyBOBEnable)
mSetting.enableBob = kit->value == "TRUE";
mSetting.enable = kit->value == "TRUE";
else if (kit->key == kConfigKeyBOBKey)
mSetting.keys = kit->value;
mSetting.address.privateKey = kit->value;
else if (kit->key == kConfigKeyBOBAddr)
mSetting.addr = kit->value;
mSetting.address.base32 = kit->value;
getKVSUInt(kit, kConfigKeyInLength, mSetting.inLength)
getKVSUInt(kit, kConfigKeyInQuantity, mSetting.inQuantity)
getKVSUInt(kit, kConfigKeyInVariance, mSetting.inVariance)
@ -820,7 +777,7 @@ bool p3I2pBob::loadList(std::list<RsItem *> &load)
getKVSUInt(kit, kConfigKeyOutQuantity, mSetting.outQuantity)
getKVSUInt(kit, kConfigKeyOutVariance, mSetting.outVariance)
else
rslog(RsLog::Warning, &i2pBobLogInfo, "loadList unknown key: " + kit->key);
RS_DBG("unknown key: ", kit->key);
}
}
delete vitem;
@ -884,7 +841,7 @@ void p3I2pBob::getStates(bobStates *bs)
std::string p3I2pBob::executeCommand(const std::string &command)
{
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "executeCommand_locked running '" + command + "'");
RS_DBG4("running: ", command);
std::string copy = command;
copy.push_back('\n');
@ -896,7 +853,7 @@ std::string p3I2pBob::executeCommand(const std::string &command)
// receive answer (trailing new line is already removed!)
std::string ans = recv();
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "executeCommand_locked answer '" + ans + "'");
RS_DBG4("answer: ", ans);
return ans;
}
@ -906,7 +863,7 @@ bool p3I2pBob::connectI2P()
// there is only one thread that touches mSocket - no need for a lock
if (mSocket != 0) {
rslog(RsLog::Warning, &i2pBobLogInfo, "connectI2P_locked mSocket != 0");
RS_DBG("mSocket != 0");
return false;
}
@ -914,21 +871,21 @@ bool p3I2pBob::connectI2P()
mSocket = unix_socket(PF_INET, SOCK_STREAM, 0);
if (mSocket < 0)
{
rslog(RsLog::Warning, &i2pBobLogInfo, "connectI2P_locked Failed to open socket! Socket Error: " + socket_errorType(errno));
RS_DBG("Failed to open socket! Socket Error: ", socket_errorType(errno));
return false;
}
// connect
int err = unix_connect(mSocket, mI2PProxyAddr);
if (err != 0) {
rslog(RsLog::Warning, &i2pBobLogInfo, "connectI2P_locked Failed to connect to BOB! Socket Error: " + socket_errorType(errno));
RS_DBG("Failed to connect to BOB! Socket Error: ", socket_errorType(errno));
return false;
}
// receive hello msg
recv();
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "connectI2P_locked done");
RS_DBG4("done");
return true;
}
@ -937,17 +894,17 @@ bool p3I2pBob::disconnectI2P()
// there is only one thread that touches mSocket - no need for a lock
if (mSocket == 0) {
rslog(RsLog::Warning, &i2pBobLogInfo, "disconnectI2P_locked mSocket == 0");
RS_DBG("mSocket == 0");
return true;
}
int err = unix_close(mSocket);
if (err != 0) {
rslog(RsLog::Warning, &i2pBobLogInfo, "disconnectI2P_locked Failed to close socket! Socket Error: " + socket_errorType(errno));
RS_DBG("Failed to close socket! Socket Error: ", socket_errorType(errno));
return false;
}
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "disconnectI2P_locked done");
RS_DBG4("done");
mSocket = 0;
return true;
}
@ -968,7 +925,7 @@ std::string toString(const std::string &a, const int8_t b) {
void p3I2pBob::finalizeSettings_locked()
{
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "finalizeSettings_locked");
RS_DBG4("");
sockaddr_storage_clear(mI2PProxyAddr);
// get i2p proxy addr
@ -979,8 +936,8 @@ void p3I2pBob::finalizeSettings_locked()
sockaddr_storage_setipv4(mI2PProxyAddr, (sockaddr_in*)&proxy);
sockaddr_storage_setport(mI2PProxyAddr, 2827);
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "finalizeSettings_locked using " + sockaddr_storage_tostring(mI2PProxyAddr));
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "finalizeSettings_locked using " + mSetting.addr);
RS_DBG4("using ", mI2PProxyAddr);
RS_DBG4("using ", mSetting.address.base32);
peerState ps;
mPeerMgr->getOwnNetStatus(ps);
@ -988,21 +945,17 @@ void p3I2pBob::finalizeSettings_locked()
// setup commands
// new lines are appended later!
// generate random suffix for name
// RSRandom::random_alphaNumericString can return very weird looking strings like: ,,@z+M
// use base32 instead
size_t len = 5; // 5 characters = 8 base32 symbols
std::vector<uint8_t> tmp(len);
RSRandom::random_bytes(tmp.data(), len);
const std::string location = Radix32::encode(tmp.data(), len);
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "finalizeSettings_locked using suffix " + location);
// generate 8 characater long random suffix for name
constexpr size_t len = 8;
const std::string location = RsRandom::alphaNumeric(len);
RS_DBG4("using suffix ", location);
mTunnelName = "RetroShare-" + location;
const std::string setnick = "setnick RetroShare-" + location;
const std::string getnick = "getnick RetroShare-" + location;
const std::string newkeys = "newkeys";
const std::string getkeys = "getkeys";
const std::string setkeys = "setkeys " + mSetting.keys;
const std::string setkeys = "setkeys " + mSetting.address.privateKey;
const std::string inhost = "inhost " + sockaddr_storage_iptostring(proxy);
const std::string inport = toString("inport ", sockaddr_storage_port(proxy));
const std::string outhost = "outhost " + sockaddr_storage_iptostring(ps.localaddr);
@ -1063,7 +1016,7 @@ void p3I2pBob::finalizeSettings_locked()
void p3I2pBob::updateSettings_locked()
{
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "updateSettings_locked");
RS_DBG4("");
sockaddr_storage proxy;
mPeerMgr->getProxyServerAddress(RS_HIDDEN_TYPE_I2P, proxy);
@ -1071,7 +1024,7 @@ void p3I2pBob::updateSettings_locked()
peerState ps;
mPeerMgr->getOwnNetStatus(ps);
const std::string setkeys = "setkeys " + mSetting.keys;
const std::string setkeys = "setkeys " + mSetting.address.privateKey;
const std::string inhost = "inhost " + sockaddr_storage_iptostring(proxy);
const std::string inport = toString("inport ", sockaddr_storage_port(proxy));
const std::string outhost = "outhost " + sockaddr_storage_iptostring(ps.localaddr);
@ -1103,38 +1056,62 @@ void p3I2pBob::updateSettings_locked()
std::string p3I2pBob::recv()
{
// BOB works line based
// -> \n indicates and of the line
constexpr uint16_t bufferSize = 128;
char buffer[bufferSize];
std::string ans;
ssize_t length;
const uint16_t bufferSize = 128;
std::vector<char> buffer(bufferSize);
uint16_t retry = 10;
do {
doSleep(sleepTimeRecv);
memset(buffer, 0, bufferSize);
// there is only one thread that touches mSocket - no need for a lock
length = ::recv(mSocket, buffer.data(), buffer.size(), 0);
if (length < 0)
// peek at data
auto length = ::recv(mSocket, buffer, bufferSize, MSG_PEEK);
if (length <= 0) {
if (length < 0) {
// error
perror(__PRETTY_FUNCTION__);
}
retry--;
doSleep(sleepTimeRecv);
continue;
}
ans.append(buffer.begin(), buffer.end());
// at least one byte was read
// clean received string
ans.erase(std::remove(ans.begin(), ans.end(), '\0'), ans.end());
ans.erase(std::remove(ans.begin(), ans.end(), '\n'), ans.end());
// search for new line
auto bufferStr = std::string(buffer);
size_t pos = bufferStr.find('\n');
#if 0
std::stringstream ss;
ss << "recv length: " << length << " (bufferSize: " << bufferSize << ") ans: " << ans.length();
rslog(RsLog::Debug_All, &i2pBobLogInfo, ss.str());
#endif
if (pos == std::string::npos) {
// no new line found -> more to read
// clear and resize buffer again
buffer.clear();
buffer.resize(bufferSize);
// sanity check
if (length != bufferSize) {
// expectation: a full buffer was peeked)
RS_DBG1("peeked less than bufferSize but also didn't found a new line character");
}
// this should never happen
assert(length <= bufferSize);
} else {
// new line found -> end of message
if (this->shouldStop())
break;
} while(length == bufferSize || ans.size() < 4);
// calculate how much there is to read, read the \n, too!
length = pos + 1;
// end loop
retry = 0;
}
// now read for real
memset(buffer, 0, bufferSize);
length = ::recv(mSocket, buffer, length, 0);
bufferStr = std::string(buffer);
ans.append(bufferStr);
} while(retry > 0);
return ans;
}

View File

@ -30,9 +30,10 @@
#include <sys/socket.h>
#endif
#include "pqi/p3cfgmgr.h"
#include "services/autoproxy/rsautoproxymonitor.h"
#include "util/rsthreads.h"
#include "pqi/p3cfgmgr.h"
#include "util/i2pcommon.h"
/*
* This class implements I2P BOB (BASIC OPEN BRIDGE) communication to allow RS
@ -49,7 +50,7 @@
*
* Note 3:
* BOB needs a unique name as an ID for each tunnel.
* We use 'RetroShare-' + 8 base32 characters.
* We use 'RetroShare-' + 8 random base32 characters.
*
* Design:
* The service uses three state machines to manage its task:
@ -72,7 +73,7 @@
* mCommands[bobState::quit] = {quit, bobState::cleared};
*
* stateMachineController:
* This state machone manages the high level tasks.
* This state machine manages the high level tasks.
* It is controlled by mState and mTask.
*
* mTast:
@ -162,19 +163,7 @@ struct bobStateInfo {
bobState nextState;
};
struct bobSettings {
bool enableBob; ///< This field is used by the pqi subsystem to determinine whether SOCKS proxy or BOB is used for I2P connections
std::string keys; ///< (optional) server keys
std::string addr; ///< (optional) hidden service addr. in base32 form
int8_t inLength;
int8_t inQuantity;
int8_t inVariance;
int8_t outLength;
int8_t outQuantity;
int8_t outVariance;
};
struct bobSettings : i2p::settings {};
///
/// \brief The bobStates struct
@ -203,8 +192,6 @@ public:
void processTaskAsync(taskTicket *ticket);
void processTaskSync(taskTicket *ticket);
static std::string keyToBase32Addr(const std::string &key);
void threadTick() override; /// @see RsTickingThread
private:

View File

@ -22,6 +22,7 @@
#include "rsautoproxymonitor.h"
#include <unistd.h> /* for usleep() */
#include "util/rsdebug.h"
#include "util/rstime.h"
rsAutoProxyMonitor *rsAutoProxyMonitor::mInstance = NULL;
@ -42,8 +43,10 @@ rsAutoProxyMonitor *rsAutoProxyMonitor::instance()
void rsAutoProxyMonitor::addProxy(autoProxyType::autoProxyType_enum type, autoProxyService *service)
{
RS_STACK_MUTEX(mLock);
if (mProxies.find(type) != mProxies.end())
std::cerr << "sAutoProxyMonitor::addProxy type " << type << " already added - OVERWRITING" << std::endl;
if (mProxies.find(type) != mProxies.end()) {
RS_ERR("type ", type, " already added - OVERWRITING");
print_stacktrace();
}
mProxies[type] = service;
}
@ -117,7 +120,7 @@ void rsAutoProxyMonitor::stopAllRSShutdown()
do {
rstime::rs_usleep(1000 * 1000);
RS_STACK_MUTEX(mLock);
std::cout << "(II) waiting for auto proxy service(s) to shut down " << t << "/" << timeout << " (remaining: " << mProxies.size() << ")" << std::endl;
RS_DBG("waiting for auto proxy service(s) to shut down ", t, "/", timeout, " (remaining: ", mProxies.size(), ")");
if (mProxies.empty())
break;
t++;
@ -146,13 +149,16 @@ void rsAutoProxyMonitor::task(taskTicket *ticket)
{
// sanity checks
if (!ticket->async && ticket->types.size() > 1) {
std::cerr << "(WW) rsAutoProxyMonitor::task synchronous call to multiple services. This can cause problems!" << std::endl;
RS_ERR("synchronous call to multiple services. This can cause problems!");
print_stacktrace();
}
if (ticket->async && !ticket->cb && ticket->data) {
std::cerr << "(WW) rsAutoProxyMonitor::task asynchronous call with data but no callback. This will likely causes memory leak!" << std::endl;
RS_ERR("asynchronous call with data but no callback. This will likely causes memory leak!");
print_stacktrace();
}
if (ticket->types.size() > 1 && ticket->data) {
std::cerr << "(WW) rsAutoProxyMonitor::task call with data to multiple services. This will likely causes memory leak!" << std::endl;
RS_ERR("call with data to multiple services. This will likely causes memory leak!");
print_stacktrace();
}
std::vector<autoProxyType::autoProxyType_enum>::const_iterator it;
@ -168,7 +174,11 @@ void rsAutoProxyMonitor::task(taskTicket *ticket)
*tt = *ticket;
tt->types.clear();
tt->types.push_back(*it);
s->processTaskAsync(tt);
// it's async!
RsThread::async([s, tt] {
s->processTaskAsync(tt);
});
} else {
s->processTaskSync(ticket);
}
@ -187,7 +197,8 @@ void rsAutoProxyMonitor::taskAsync(std::vector<autoProxyType::autoProxyType_enum
if (!isAsyncTask(task)) {
// Usually the services will reject this ticket.
// Just print a warning - maybe there is some special case where this is a good idea.
std::cerr << "(WW) rsAutoProxyMonitor::taskAsync called with a synchronous task!" << std::endl;
RS_ERR("called with a synchronous task!");
print_stacktrace();
}
taskTicket *tt = getTicket();
@ -215,7 +226,8 @@ void rsAutoProxyMonitor::taskSync(std::vector<autoProxyType::autoProxyType_enum>
if (isAsyncTask(task)) {
// Usually the services will reject this ticket.
// Just print a warning - maybe there is some special case where this is a good idea.
std::cerr << "(WW) rsAutoProxyMonitor::taskSync called with an asynchronous task!" << std::endl;
RS_ERR("called with an asynchronous task!");
print_stacktrace();
}
taskTicket *tt = getTicket();
@ -244,7 +256,8 @@ void rsAutoProxyMonitor::taskDone(taskTicket *t, autoProxyStatus::autoProxyStatu
t->cb->taskFinished(t);
if (t != NULL) {
// callack did not clean up properly
std::cerr << "(WW) rsAutoProxyMonitor::taskFinish callback did not clean up!" << std::endl;
RS_ERR("callback did not clean up!");
print_stacktrace();
cleanUp = true;
}
} else if (t->async){
@ -252,12 +265,13 @@ void rsAutoProxyMonitor::taskDone(taskTicket *t, autoProxyStatus::autoProxyStatu
// we must take care of deleting
cleanUp = true;
if(t->data)
std::cerr << "(WW) rsAutoProxyMonitor::taskFinish async call with data attached but no callback set!" << std::endl;
RS_ERR("async call with data attached but no callback set!");
}
if (cleanUp) {
if (t->data) {
std::cerr << "(WW) rsAutoProxyMonitor::taskFinish will try to delete void pointer!" << std::endl;
RS_ERR("will try to delete void pointer!");
print_stacktrace();
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdelete-incomplete"
delete t->data;
@ -290,7 +304,8 @@ void rsAutoProxyMonitor::taskFinished(taskTicket *&ticket)
// clean up
if (ticket->data) {
std::cerr << "rsAutoProxyMonitor::taskFinished data set. Will try to delete void pointer" << std::endl;
RS_ERR(" data set. Will try to delete void pointer");
print_stacktrace();
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdelete-incomplete"
delete ticket->data;
@ -308,7 +323,7 @@ autoProxyService *rsAutoProxyMonitor::lookUpService(autoProxyType::autoProxyType
if ((itService = mProxies.find(t)) != mProxies.end()) {
return itService->second;
}
std::cerr << "sAutoProxyMonitor::lookUpService no service for type " << t << " found!" << std::endl;
RS_DBG("no service for type ", t, " found!");
return NULL;
}

View File

@ -1187,11 +1187,15 @@ bool p3MsgService::MessageSend(MessageInfo &info)
/* use processMsg to get the new msgId */
msg->recvTime = time(NULL);
msg->msgId = getNewUniqueMsgId();
msg->msgFlags |= RS_MSG_OUTGOING;
imsg[msg->msgId] = msg;
// Update info for caller
info.msgId = std::to_string(msg->msgId);
info .msgflags = msg->msgFlags;
RsServer::notify()->notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_ADD);
}

View File

@ -102,3 +102,8 @@ android-* {
CONFIG *= qt
QT *= network
}
################################### Pkg-Config Stuff #############################
LIBS *= $$system(pkg-config --libs $$PKGCONFIG)

View File

@ -0,0 +1,163 @@
#include "i2pcommon.h"
#include "util/rsbase64.h"
#include "util/rsdebug.h"
namespace i2p {
std::string keyToBase32Addr(const std::string &key)
{
std::string copy(key);
// replace I2P specific chars
std::replace(copy.begin(), copy.end(), '~', '/');
// replacing the - with a + is not necessary, as RsBase64 can handle base64url encoding, too
// std::replace(copy.begin(), copy.end(), '-', '+');
// decode
std::vector<uint8_t> bin;
RsBase64::decode(copy, bin);
// hash
std::vector<uint8_t> sha256 = RsUtil::BinToSha256(bin);
// encode
std::string out = Radix32::encode(sha256);
// i2p uses lowercase
std::transform(out.begin(), out.end(), out.begin(), ::tolower);
out.append(".b32.i2p");
return out;
}
const std::string makeOption(const std::string &lhs, const int8_t &rhs) {
return lhs + "=" + std::to_string(rhs);
}
uint16_t readTwoBytesBE(std::vector<uint8_t>::const_iterator &p)
{
uint16_t val = 0;
val += *p++;
val <<= 8;
val += *p++;
return val;
}
std::string publicKeyFromPrivate(std::string const &priv)
{
/*
* https://geti2p.net/spec/common-structures#destination
* https://geti2p.net/spec/common-structures#keysandcert
* https://geti2p.net/spec/common-structures#certificate
*/
if (priv.length() < 884) // base64 ( = 663 bytes = KeyCert + priv Keys)
return std::string();
// creat a copy to work on, need to convert it to standard base64
auto priv_copy(priv);
std::replace(priv_copy.begin(), priv_copy.end(), '~', '/');
// replacing the - with a + is not necessary, as RsBase64 can handle base64url encoding, too
// std::replace(copy.begin(), copy.end(), '-', '+');
// get raw data
std::vector<uint8_t> dataPriv;
RsBase64::decode(priv_copy, dataPriv);
auto p = dataPriv.cbegin();
RS_DBG("dataPriv.size ", dataPriv.size());
size_t publicKeyLen = 256 + 128; // default length (bytes)
uint8_t certType = 0;
uint16_t len = 0;
uint16_t signingKeyType = 0;
uint16_t cryptKey = 0;
// only used for easy break
do {
try {
// jump to certificate
p += publicKeyLen;
// try to read type and length
certType = *p++;
len = readTwoBytesBE(p);
// only 0 and 5 are used / valid at this point
// check for == 0
if (certType == static_cast<typename std::underlying_type<CertType>::type>(CertType::Null)) {
/*
* CertType.Null
* type null is followed by 0x00 0x00 <END>
* so has to be 0!
*/
RS_DBG("cert is CertType.Null");
publicKeyLen += 3; // add 0x00 0x00 0x00
if (len != 0)
// weird
RS_DBG("cert is CertType.Null but len != 0");
break;
}
// check for != 5
if (certType != static_cast<typename std::underlying_type<CertType>::type>(CertType::Key)) {
// unsupported
RS_DBG("cert type ", certType, " is unsupported");
return std::string();
}
RS_DBG("cert is CertType.Key");
publicKeyLen += 7; // <type 1B> <len 2B> <keyType1 2B> <keyType2 2B> = 1 + 2 + 2 + 2 = 7 bytes
/*
* "Key certificates were introduced in release 0.9.12. Prior to that release, all PublicKeys were 256-byte ElGamal keys, and all SigningPublicKeys were 128-byte DSA-SHA1 keys."
* --> there is space for 256+128 bytes, longer keys are splitted and appended to the certificate
* We don't need to bother with the splitting here as only the lenght is important!
*/
// Signing Public Key
// likely 7
signingKeyType = readTwoBytesBE(p);
RS_DBG("signing pubkey type ", certType);
if (signingKeyType >= 3 && signingKeyType <= 6) {
RS_DBG("signing pubkey type ", certType, " has oversize");
// calculate oversize
if (signingKeyType >= signingKeyLengths.size()) {
// just in case
RS_DBG("signing pubkey type ", certType, " cannot be found in size data!");
return std::string();
}
auto values = signingKeyLengths[signingKeyType];
if (values.first <= 128) {
// just in case, it's supposed to be larger!
RS_DBG("signing pubkey type ", certType, " is oversize but size calculation would underflow!");
return std::string();
}
publicKeyLen += values.first - 128; // 128 = default DSA key length = the space than can be used before the key must be splitted
}
// Crypto Public Key
// likely 0
cryptKey = readTwoBytesBE(p);
RS_DBG("crypto pubkey type ", cryptKey);
// info: these are all smaller than the default 256 bytes, so no oversize calculation is needed
break;
} catch (const std::out_of_range &e) {
RS_DBG("hit exception! ", e.what());
return std::string();
}
} while(false);
std::string pub;
auto data2 = std::vector<uint8_t>(dataPriv.cbegin(), dataPriv.cbegin() + publicKeyLen);
RsBase64::encode(data2.data(), data2.size(), pub, false, false);
return pub;
}
} // namespace i2p

View File

@ -0,0 +1,211 @@
#ifndef I2PCOMMON_H
#define I2PCOMMON_H
#include <algorithm>
#include <map>
#include "util/rsrandom.h"
#include "util/radix32.h"
#include "util/rsbase64.h"
#include "util/rsprint.h"
#include "util/rsdebug.h"
/*
* This header provides common code for i2p related code, namely BOB and SAM3 support.
*/
namespace i2p {
static constexpr int8_t kDefaultLength = 3; // i2p default
static constexpr int8_t kDefaultQuantity = 3; // i2p default + 1
static constexpr int8_t kDefaultVariance = 0;
static constexpr int8_t kDefaultBackupQuantity = 0;
/**
* @brief The address struct
* This structure is a container for any i2p address/key. The public key is used for addressing and can be (optionally) hashed to generate the .b32.i2p address.
*/
struct address {
std::string base32;
std::string publicKey;
std::string privateKey;
void clear() {
base32.clear();
publicKey.clear();
privateKey.clear();
}
};
/**
* @brief The settings struct
* Common structure with all settings that are shared between any i2p backends
*/
struct settings {
bool enable;
struct address address;
// connection parameter
int8_t inLength;
int8_t inQuantity;
int8_t inVariance;
int8_t inBackupQuantity;
int8_t outLength;
int8_t outQuantity;
int8_t outVariance;
int8_t outBackupQuantity;
void initDefault() {
enable = false;
address.clear();
inLength = kDefaultLength;
inQuantity = kDefaultQuantity;
inVariance = kDefaultVariance;
inBackupQuantity = kDefaultBackupQuantity;
outLength = kDefaultLength;
outQuantity = kDefaultQuantity;
outVariance = kDefaultVariance;
outBackupQuantity = kDefaultBackupQuantity;
}
};
/*
Type Type Code Payload Length Total Length Notes
Null 0 0 3
HashCash 1 varies varies Experimental, unused. Payload contains an ASCII colon-separated hashcash string.
Hidden 2 0 3 Experimental, unused. Hidden routers generally do not announce that they are hidden.
Signed 3 40 or 72 43 or 75 Experimental, unused. Payload contains a 40-byte DSA signature, optionally followed by the 32-byte Hash of the signing Destination.
Multiple 4 varies varies Experimental, unused. Payload contains multiple certificates.
Key 5 4+ 7+ Since 0.9.12. See below for details.
*/
enum class CertType : uint8_t {
Null = 0,
HashCash = 1,
Hidden = 2,
Signed = 3,
Multiple = 4,
Key = 5
};
/*
* public
Type Type Code Total Public Key Length Since Usage
DSA_SHA1 0 128 0.9.12 Legacy Router Identities and Destinations, never explicitly set
ECDSA_SHA256_P256 1 64 0.9.12 Older Destinations
ECDSA_SHA384_P384 2 96 0.9.12 Rarely if ever used for Destinations
ECDSA_SHA512_P521 3 132 0.9.12 Rarely if ever used for Destinations
RSA_SHA256_2048 4 256 0.9.12 Offline only; never used in Key Certificates for Router Identities or Destinations
RSA_SHA384_3072 5 384 0.9.12 Offline only; never used in Key Certificates for Router Identities or Destinations
RSA_SHA512_4096 6 512 0.9.12 Offline only; never used in Key Certificates for Router Identities or Destinations
EdDSA_SHA512_Ed25519 7 32 0.9.15 Recent Router Identities and Destinations
EdDSA_SHA512_Ed25519ph 8 32 0.9.25 Offline only; never used in Key Certificates for Router Identities or Destinations
reserved (GOST) 9 64 Reserved, see proposal 134
reserved (GOST) 10 128 Reserved, see proposal 134
RedDSA_SHA512_Ed25519 11 32 0.9.39 For Destinations and encrypted leasesets only; never used for Router Identities
reserved 65280-65534 Reserved for experimental use
reserved 65535 Reserved for future expansion
* private
Type Length (bytes) Since Usage
DSA_SHA1 20 Legacy Router Identities and Destinations
ECDSA_SHA256_P256 32 0.9.12 Recent Destinations
ECDSA_SHA384_P384 48 0.9.12 Rarely used for Destinations
ECDSA_SHA512_P521 66 0.9.12 Rarely used for Destinations
RSA_SHA256_2048 512 0.9.12 Offline signing, never used for Router Identities or Destinations
RSA_SHA384_3072 768 0.9.12 Offline signing, never used for Router Identities or Destinations
RSA_SHA512_4096 1024 0.9.12 Offline signing, never used for Router Identities or Destinations
EdDSA_SHA512_Ed25519 32 0.9.15 Recent Router Identities and Destinations
EdDSA_SHA512_Ed25519ph 32 0.9.25 Offline signing, never used for Router Identities or Destinations
RedDSA_SHA512_Ed25519 32 0.9.39 For Destinations and encrypted leasesets only, never used for Router Identities
*/
enum class SigningKeyType : uint16_t {
DSA_SHA1 = 0,
ECDSA_SHA256_P256 = 1,
ECDSA_SHA384_P384 = 2,
ECDSA_SHA512_P521 = 3,
RSA_SHA256_2048 = 4,
RSA_SHA384_3072 = 5,
RSA_SHA512_4096 = 6,
EdDSA_SHA512_Ed25519 = 7,
EdDSA_SHA512_Ed25519ph = 8,
RedDSA_SHA512_Ed25519 = 11
};
/*
* public
Type Type Code Total Public Key Length Usage
ElGamal 0 256 All Router Identities and Destinations
P256 1 64 Reserved, see proposal 145
P384 2 96 Reserved, see proposal 145
P521 3 132 Reserved, see proposal 145
X25519 4 32 Not for use in key certs. See proposal 144
reserved 65280-65534 Reserved for experimental use
reserved 65535 Reserved for future expansion
* private
Type Length (bytes) Since Usage
ElGamal 256 All Router Identities and Destinations
P256 32 TBD Reserved, see proposal 145
P384 48 TBD Reserved, see proposal 145
P521 66 TBD Reserved, see proposal 145
X25519 32 0.9.38 Little-endian. See proposal 144
*/
enum class CryptoKeyType : uint16_t {
ElGamal = 0,
P256 = 1,
P384 = 2,
P521 = 3,
X25519 = 4
};
static const std::array<std::pair<uint16_t, uint16_t>, 5> cryptoKeyLengths {
/*CryptoKeyType::ElGamal*/ std::make_pair<uint16_t, uint16_t>(256, 256),
/*CryptoKeyType::P256, */ std::make_pair<uint16_t, uint16_t>( 64, 32),
/*CryptoKeyType::P384, */ std::make_pair<uint16_t, uint16_t>( 96, 48),
/*CryptoKeyType::P521, */ std::make_pair<uint16_t, uint16_t>(132, 66),
/*CryptoKeyType::X25519,*/ std::make_pair<uint16_t, uint16_t>( 32, 32),
};
static const std::array<std::pair<uint16_t, uint16_t>, 12> signingKeyLengths {
/*SigningKeyType::DSA_SHA1, */ std::make_pair<uint16_t, uint16_t>(128, 128),
/*SigningKeyType::ECDSA_SHA256_P256, */ std::make_pair<uint16_t, uint16_t>( 64, 32),
/*SigningKeyType::ECDSA_SHA384_P384, */ std::make_pair<uint16_t, uint16_t>( 96, 48),
/*SigningKeyType::ECDSA_SHA512_P521, */ std::make_pair<uint16_t, uint16_t>(132, 66),
/*SigningKeyType::RSA_SHA256_2048, */ std::make_pair<uint16_t, uint16_t>(256, 512),
/*SigningKeyType::RSA_SHA384_3072, */ std::make_pair<uint16_t, uint16_t>(384, 768),
/*SigningKeyType::RSA_SHA512_4096, */ std::make_pair<uint16_t, uint16_t>(512,1024),
/*SigningKeyType::EdDSA_SHA512_Ed25519 */ std::make_pair<uint16_t, uint16_t>( 32, 32),
/*SigningKeyType::EdDSA_SHA512_Ed25519ph */ std::make_pair<uint16_t, uint16_t>( 32, 32),
/*reserved (GOST) */ std::make_pair<uint16_t, uint16_t>( 64, 0),
/*reserved (GOST) */ std::make_pair<uint16_t, uint16_t>(128, 0),
/*SigningKeyType::RedDSA_SHA512_Ed25519 */ std::make_pair<uint16_t, uint16_t>( 32, 32),
};
/**
* @brief makeOption Creates the string "lhs=rhs" used by BOB and SAM. Converts rhs
* @param lhs option to set
* @param rhs value to set
* @return concatenated string
*/
const std::string makeOption(const std::string &lhs, const int8_t &rhs);
/**
* @brief keyToBase32Addr generated a base32 address (.b32.i2p) from a given public key
* @param key public key
* @return generated base32 address
*/
std::string keyToBase32Addr(const std::string &key);
/**
* @brief publicKeyFromPrivate parses the private key and calculates the lenght of the public key
* @param priv private key (which includes the public key) to read
* @return public key used for addressing
*/
std::string publicKeyFromPrivate(const std::string &priv);
} // namespace i2p
#endif // I2PCOMMON_H

View File

@ -21,8 +21,6 @@
* *
*******************************************************************************/
#include <cmath>
#include "util/rsbase64.h"
#include "util/rsdebug.h"
@ -40,6 +38,12 @@
rs_view_ptr<const uint8_t> data, size_t len, std::string& outString,
bool padding, bool urlSafe )
{
if(!data || !len)
{
outString.clear();
return;
}
const char* sDict = urlSafe ? uDict : bDict;
// Workaround if input and output are the same buffer.
@ -137,9 +141,11 @@
/*static*/ size_t RsBase64::encodedSize(size_t decodedSize, bool padding)
{
if(padding) return 4 * (decodedSize + 2) / 3;
return static_cast<size_t>(
std::ceil(4L * static_cast<double>(decodedSize) / 3L) );
if(!decodedSize) return 0;
// Thanks https://stackoverflow.com/a/45401395
if(padding) return ceilDivision(decodedSize, 3) * 4;
return ceilDivision(decodedSize * 8, 6);
}
/*static*/ std::tuple<size_t, std::error_condition> RsBase64::decodedSize(

View File

@ -137,4 +137,8 @@ private:
*/
static inline bool isBase64Char(char c)
{ return rDict[static_cast<uint8_t>(c)] >= 0; }
/** Perform ceil division without floating point operations */
static inline size_t ceilDivision(size_t dividend, size_t divisor)
{ return (dividend + divisor - 1) / divisor; }
};

View File

@ -30,6 +30,12 @@ std::ostream &operator<<(std::ostream& out, const std::error_condition& err)
<< " category: " << err.category().name();
}
std::string rsErrorNotInCategory(int errNum, const std::string& categoryName)
{
return "Error message for error: " + std::to_string(errNum) +
" not available in category: " + categoryName;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

View File

@ -21,17 +21,23 @@
*******************************************************************************/
#pragma once
#include <ostream>
#include <string>
#include <sstream>
#include <system_error>
/** Stream helper for std::error_condition */
std::ostream &operator<<(std::ostream& out, const std::error_condition& err);
#ifdef __ANDROID__
# include <android/log.h>
# include <sstream>
# include <string>
#else // def __ANDROID__
# include <iostream>
# include <chrono>
# include <iomanip>
#endif // def __ANDROID__
#include "util/rsjson.h"
#ifdef __ANDROID__
enum class RsLoggerCategories
{
DEBUG = ANDROID_LOG_DEBUG,
@ -40,53 +46,7 @@ enum class RsLoggerCategories
ERROR = ANDROID_LOG_ERROR,
FATAL = ANDROID_LOG_FATAL
};
template <RsLoggerCategories CATEGORY>
struct t_RsLogger
{
inline t_RsLogger() = default;
/** On other platforms expose the type of underlying stream.
* On Android it cannot work like that so return the class type itself
* just for code compatibility with other platforms */
using stream_type = t_RsLogger;
template<typename T>
inline stream_type& operator<<(const T& val)
{ ostr << val; return *this; }
/// needed for manipulators and things like std::endl
stream_type& operator<<(std::ostream& (*pf)(std::ostream&))
{
if(pf == static_cast<std::ostream& (*)(std::ostream&)>(
&std::endl< char, std::char_traits<char> > ))
{
__android_log_write(
static_cast<int>(CATEGORY),
"RetroShare", ostr.str().c_str() );
ostr.str() = "";
}
else ostr << pf;
return *this;
}
/** On other platforms return underlying stream to write avoiding additional
* prefixes. On Android it cannot work like that so return the object itself
* just for code compatibility with other platforms */
inline stream_type& uStream() { return *this; }
private:
std::ostringstream ostr;
};
#else // def __ANDROID__
#include <iostream>
#include <chrono>
#include <iomanip>
#include <sstream>
enum class RsLoggerCategories
{
DEBUG = 'D',
@ -95,71 +55,105 @@ enum class RsLoggerCategories
ERROR = 'E',
FATAL = 'F'
};
#endif // def __ANDROID__
/** Stream helper for std::error_condition */
std::ostream &operator<<(std::ostream& out, const std::error_condition& err);
/** Provide unkown error message for all error categories to avoid duplicating
* the message around */
std::string rsErrorNotInCategory(int errNum, const std::string& categoryName);
template <RsLoggerCategories CATEGORY>
struct t_RsLogger
struct t_RsLogger : std::ostringstream
{
inline t_RsLogger() = default;
t_RsLogger() { setPrefix(); }
~t_RsLogger() { flush(); }
/// Expose the type of underlying stream
using stream_type = decltype(std::cerr);
/** Offer variadic style, this doesn't supports things like std::endl as
* paramether but when used toghether with conditional debugging macros
* reduces binary size as paramethers of suppressed calls are not evaluated
* and literally disappear in preprocessing fase @see RsDbg */
template <typename... Args>
explicit inline t_RsLogger(Args&&... args)
{
setPrefix();
template<typename T>
inline stream_type& operator<<(const T& val)
/* Combine initializer list and comma operator so the compiler unpack
* template arguments and feed our own stream without recursion
* see https://stackoverflow.com/a/27375675 */
using expander = int[];
(void) expander {0, (void((*this) << std::forward<Args>(args)), 0)...};
}
/** Dump buffer stream to log */
void flush()
{
#ifdef __ANDROID__
__android_log_write(
static_cast<int>(CATEGORY),
"RetroShare", str().c_str() );
#else // def __ANDROID__
(*this) << std::endl;
std::cerr << str();
#endif // def __ANDROID__
str() = "";
}
private:
#ifdef __ANDROID__
inline void setPrefix() {}
#else // def __ANDROID__
void setPrefix()
{
using namespace std::chrono;
const auto now = system_clock::now();
const auto sec = time_point_cast<seconds>(now);
const auto msec = duration_cast<milliseconds>(now - sec);
std::stringstream tstream;
tstream << static_cast<char>(CATEGORY) << " "
(*this) << static_cast<char>(CATEGORY) << " "
<< sec.time_since_epoch().count() << "."
<< std::setfill('0') << std::setw(3) << msec.count()
<< " " << val;
return std::cerr << tstream.str();
<< std::setfill('0') << std::setw(3) << msec.count() << " ";
}
/// needed for manipulators and things like std::endl
stream_type& operator<<(std::ostream& (*pf)(std::ostream&))
{ return std::cerr << pf; }
/// Return underlying stream to write avoiding additional prefixes
inline stream_type& uStream() const { return std::cerr; }
};
#endif // def __ANDROID__
};
/**
* Comfortable debug message loggin, supports chaining like std::cerr but can
* be easly and selectively disabled at compile time to reduce generated binary
* size and performance impact without too many \#ifdef around.
* Comfortable debug message logging, supports both variadic style and chaining
* style like std::cerr.
* Can be easly and selectively disabled at compile time.
* To reduce generated binary size and performance impact when debugging is
* disabled without too many \#ifdef around the code combining the variadic
* style with the leveled debugging macros is the way to go.
*
* To selectively debug your context you can just add something like this in
* in that context, as an example for a class you can just add a line like this
* inside class declaration:
* To selectively debug your file you just need to include the header of desired
* debugging level (0 to 4)
@code{.cpp}
RS_SET_CONTEXT_DEBUG_LEVEL(2)
#include "util/rsdebuglevel2.h"
@endcode
* And the you can write debug messages around the code of the class like this:
* Then where you want to print debug messages use
@code{.cpp}
Dbg1() << "Level 1 debug message example, this will be compiled and "
<< "printed" << std::endl;
Dbg2() << "Level 2 debug message example, this will be compiled and "
<< "printed" << std::endl;
Dbg3() << "Level 3 debug message example, this will not be compiled and "
<< "printed, and without #ifdef around!!" << std::endl;
Dbg4() << "Level 4 debug message example, this will not be compiled and "
<< "printed, and without #ifdef around!!" << std::endl;
RS_DBG0("Hello 0 ", "my debug ", my_variable) << " message " << variable2;
RS_DBG1("Hello 1 ", "my debug ", my_variable) << " message " << variable2;
RS_DBG2("Hello 2 ", "my debug ", my_variable) << " message " << variable2;
RS_DBG3("Hello 3 ", "my debug ", my_variable) << " message " << variable2;
RS_DBG4("Hello 4 ", "my debug ", my_variable) << " message " << variable2;
@endcode
* To change the debugging level, for example to completely disable debug
* messages you can change it to 0
@code{.cpp}
RS_SET_CONTEXT_DEBUG_LEVEL(0)
@endcode
* While to set it to maximim level you have to pass 4.
* To change the debugging level just include a different level header like
* `util/rsdebuglevel1.h`, debug messages with lower or equal level then the
* included header will be printed, the others will not.
* Remember then on messages with debug level higher then the included the
* paramethers you pass as macro arguments (variadic style) will disappear in
* the preprocessing phase, so their evaluation will not be included in the
* final binary and not executed at runtime, instead the paramether passed with
* `<<` (chaining style) will be in the compiled binary and evaluated at runtime
* even if are not printed, due to how C++ is made it is not possible to avoid
* this, so we suggest to use variadic style for debug messages.
*/
using RsDbg = t_RsLogger<RsLoggerCategories::DEBUG>;
using RsDbg = t_RsLogger<RsLoggerCategories::DEBUG>;
#define RS_DBG(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__)
/**
* Comfortable log information reporting helper, supports chaining like
@ -169,17 +163,22 @@ using RsDbg = t_RsLogger<RsLoggerCategories::DEBUG>;
RsInfo() << __PRETTY_FUNCTION__ << "My information message" << std::cerr;
@endcode
*/
using RsInfo = t_RsLogger<RsLoggerCategories::INFO>;
using RsInfo = t_RsLogger<RsLoggerCategories::INFO>;
#define RS_INFO(...) RsInfo(__PRETTY_FUNCTION__, " ", __VA_ARGS__)
/// Similar to @see RsInfo but for warning messages
using RsWarn = t_RsLogger<RsLoggerCategories::WARNING>;
using RsWarn = t_RsLogger<RsLoggerCategories::WARNING>;
#define RS_WARN(...) RsWarn(__PRETTY_FUNCTION__, " ", __VA_ARGS__)
/// Similar to @see RsInfo but for error messages
using RsErr = t_RsLogger<RsLoggerCategories::ERROR>;
using RsErr = t_RsLogger<RsLoggerCategories::ERROR>;
#define RS_ERR(...) RsErr(__PRETTY_FUNCTION__, " ", __VA_ARGS__)
/** Similar to @see RsInfo but for fatal errors (the ones which cause RetroShare
* to terminate) messages */
using RsFatal = t_RsLogger<RsLoggerCategories::FATAL>;
using RsFatal = t_RsLogger<RsLoggerCategories::FATAL>;
#define RS_FATAL(...) RsFatal(__PRETTY_FUNCTION__, " ", __VA_ARGS__)
/**
* Keeps compatible syntax with RsDbg but explicitely do nothing in a way that
@ -189,25 +188,31 @@ using RsFatal = t_RsLogger<RsLoggerCategories::FATAL>;
struct RsNoDbg
{
inline RsNoDbg() = default;
/** Defined as the type itself just for code compatibility with other
* logging classes */
using stream_type = RsNoDbg;
template <typename... Args> inline explicit RsNoDbg(Args...) {}
/** This match most of the types, but might be not enough for templated
* types */
template<typename T>
inline stream_type& operator<<(const T&) { return *this; }
inline RsNoDbg& operator<<(const T&) { return *this; }
/// needed for manipulators and things like std::endl
inline stream_type& operator<<(std::ostream& (*/*pf*/)(std::ostream&))
inline RsNoDbg& operator<<(std::ostream& (*/*pf*/)(std::ostream&))
{ return *this; }
/** Return the object itself just for code compatibility with other
* logging classes */
inline stream_type& uStream() { return *this; }
/** Do nothing. Just for code compatibility with other logging classes */
inline void flush() {}
};
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// All the following lines are DEPRECATED!!
#include "util/rsdeprecate.h"
/**
* Concatenate preprocessor tokens A and B without expanding macro definitions
* (however, if invoked from a macro, macro arguments are expanded).
@ -226,41 +231,30 @@ struct RsNoDbg
// A bunch of boilerplate, but just in one place
#define RS_SET_CONTEXT_DEBUG_LEVEL0 \
using Dbg1 = RsNoDbg; \
using Dbg2 = RsNoDbg; \
using Dbg3 = RsNoDbg; \
using Dbg4 = RsNoDbg;
using Dbg1 RS_DEPRECATED_FOR(RS_DBG1) = RsNoDbg; \
using Dbg2 RS_DEPRECATED_FOR(RS_DBG2) = RsNoDbg; \
using Dbg3 RS_DEPRECATED_FOR(RS_DBG3) = RsNoDbg; \
using Dbg4 RS_DEPRECATED_FOR(RS_DBG4) = RsNoDbg;
#define RS_SET_CONTEXT_DEBUG_LEVEL1 \
using Dbg1 = RsDbg; \
using Dbg2 = RsNoDbg; \
using Dbg3 = RsNoDbg; \
using Dbg4 = RsNoDbg;
using Dbg1 RS_DEPRECATED_FOR(RS_DBG1) = RsDbg; \
using Dbg2 RS_DEPRECATED_FOR(RS_DBG2) = RsNoDbg; \
using Dbg3 RS_DEPRECATED_FOR(RS_DBG3) = RsNoDbg; \
using Dbg4 RS_DEPRECATED_FOR(RS_DBG4) = RsNoDbg;
#define RS_SET_CONTEXT_DEBUG_LEVEL2 \
using Dbg1 = RsDbg; \
using Dbg2 = RsDbg; \
using Dbg3 = RsNoDbg; \
using Dbg4 = RsNoDbg;
using Dbg1 RS_DEPRECATED_FOR(RS_DBG1) = RsDbg; \
using Dbg2 RS_DEPRECATED_FOR(RS_DBG2) = RsDbg; \
using Dbg3 RS_DEPRECATED_FOR(RS_DBG3) = RsNoDbg; \
using Dbg4 RS_DEPRECATED_FOR(RS_DBG4) = RsNoDbg;
#define RS_SET_CONTEXT_DEBUG_LEVEL3 \
using Dbg1 = RsDbg; \
using Dbg2 = RsDbg; \
using Dbg3 = RsDbg; \
using Dbg4 = RsNoDbg;
using Dbg1 RS_DEPRECATED_FOR(RS_DBG1) = RsDbg; \
using Dbg2 RS_DEPRECATED_FOR(RS_DBG2) = RsDbg; \
using Dbg3 RS_DEPRECATED_FOR(RS_DBG3) = RsDbg; \
using Dbg4 RS_DEPRECATED_FOR(RS_DBG4) = RsNoDbg;
#define RS_SET_CONTEXT_DEBUG_LEVEL4 \
using Dbg1 = RsDbg; \
using Dbg2 = RsDbg; \
using Dbg3 = RsDbg; \
using Dbg4 = RsDbg;
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// All the following lines are DEPRECATED!!
#include <string>
#include "util/rsdeprecate.h"
using Dbg1 RS_DEPRECATED_FOR(RS_DBG1) = RsDbg; \
using Dbg2 RS_DEPRECATED_FOR(RS_DBG2) = RsDbg; \
using Dbg3 RS_DEPRECATED_FOR(RS_DBG3) = RsDbg; \
using Dbg4 RS_DEPRECATED_FOR(RS_DBG4) = RsDbg;
namespace RsLog {
enum RS_DEPRECATED_FOR("RsErr, RsDbg, RsNoDbg") logLvl {

View File

@ -0,0 +1,42 @@
/*******************************************************************************
* RetroShare debugging level *
* *
* Copyright (C) 2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
// #pragma once // This is commented out on purpose!
#include <util/rsdebug.h>
#undef RS_DEBUG_LEVEL
#define RS_DEBUG_LEVEL 0
#undef RS_DBG0
#define RS_DBG0(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__)
#undef RS_DBG1
#define RS_DBG1(...) RsNoDbg("")
#undef RS_DBG2
#define RS_DBG2(...) RsNoDbg("")
#undef RS_DBG3
#define RS_DBG3(...) RsNoDbg("")
#undef RS_DBG4
#define RS_DBG4(...) RsNoDbg("")

View File

@ -0,0 +1,42 @@
/*******************************************************************************
* RetroShare debugging level *
* *
* Copyright (C) 2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
// #pragma once // This is commented out on purpose!
#include <util/rsdebug.h>
#undef RS_DEBUG_LEVEL
#define RS_DEBUG_LEVEL 1
#undef RS_DBG0
#define RS_DBG0(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__)
#undef RS_DBG1
#define RS_DBG1(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__)
#undef RS_DBG2
#define RS_DBG2(...) RsNoDbg()
#undef RS_DBG3
#define RS_DBG3(...) RsNoDbg()
#undef RS_DBG4
#define RS_DBG4(...) RsNoDbg()

View File

@ -0,0 +1,42 @@
/*******************************************************************************
* RetroShare debugging level *
* *
* Copyright (C) 2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
// #pragma once // This is commented out on purpose!
#include <util/rsdebug.h>
#undef RS_DEBUG_LEVEL
#define RS_DEBUG_LEVEL 2
#undef RS_DBG0
#define RS_DBG0(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__)
#undef RS_DBG1
#define RS_DBG1(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__)
#undef RS_DBG2
#define RS_DBG2(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__)
#undef RS_DBG3
#define RS_DBG3(...) RsNoDbg()
#undef RS_DBG4
#define RS_DBG4(...) RsNoDbg()

View File

@ -0,0 +1,42 @@
/*******************************************************************************
* RetroShare debugging level *
* *
* Copyright (C) 2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
// #pragma once // This is commented out on purpose!
#include <util/rsdebug.h>
#undef RS_DEBUG_LEVEL
#define RS_DEBUG_LEVEL 3
#undef RS_DBG0
#define RS_DBG0(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__)
#undef RS_DBG1
#define RS_DBG1(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__)
#undef RS_DBG2
#define RS_DBG2(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__)
#undef RS_DBG3
#define RS_DBG3(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__)
#undef RS_DBG4
#define RS_DBG4(...) RsNoDbg()

View File

@ -0,0 +1,42 @@
/*******************************************************************************
* RetroShare debugging level *
* *
* Copyright (C) 2020 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2020 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
// #pragma once // This is commented out on purpose!
#include <util/rsdebug.h>
#undef RS_DEBUG_LEVEL
#define RS_DEBUG_LEVEL 4
#undef RS_DBG0
#define RS_DBG0(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__)
#undef RS_DBG1
#define RS_DBG1(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__)
#undef RS_DBG2
#define RS_DBG2(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__)
#undef RS_DBG3
#define RS_DBG3(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__)
#undef RS_DBG4
#define RS_DBG4(...) RsDbg(__PRETTY_FUNCTION__, " ", __VA_ARGS__)

View File

@ -29,7 +29,7 @@
typedef rapidjson::Document RsJson;
/**
* Print out RsJson to a stream, use std::stringstream to get the string
* Print out RsJson to a stream, use std::ostringstream to get the string
* @param[out] out output stream
* @param[in] jDoc JSON document to print
* @return same output stream passed as out parameter

View File

@ -121,13 +121,26 @@ double RsRandom::random_f64()
return random_u64() / (double)(~(uint64_t)0) ;
}
std::string RsRandom::random_alphaNumericString(uint32_t len)
/*static*/ std::string RsRandom::alphaNumeric(uint32_t length)
{
std::string s = "" ;
std::string s;
while(s.size() < length)
{
uint8_t rChar; random_bytes(&rChar, 1); rChar = rChar % 123;
/* if(isalnum(val)) isalnum result may vary depend on locale!! */
if( (rChar >= 48 && rChar <= 57) /* 0-9 */ ||
(rChar >= 65 && rChar <= 90) /* A-Z */ ||
(rChar >= 97 && rChar <= 122) /* a-z */ )
s += static_cast<char>(rChar);
}
for(uint32_t i=0;i<len;++i)
s += (char)( (random_u32()%94) + 33) ;
return s ;
return s;
}
/*static*/ std::string RsRandom::printable(uint32_t length)
{
std::string ret(length, 0);
random_bytes(reinterpret_cast<uint8_t*>(&ret[0]), length);
for(uint32_t i=0; i<length; ++i) ret[i] = (ret[i] % 94) + 33;
return ret;
}

View File

@ -46,9 +46,19 @@ public:
static bool seed(uint32_t s);
static std::string random_alphaNumericString(uint32_t length);
static void random_bytes(uint8_t* data, uint32_t length);
/// Return a random alphanumeric *[0-9,A-Z,a-z] string of the given lenght
static std::string alphaNumeric(uint32_t length);
/** Return a random printable string of the given lenght */
static std::string printable(uint32_t length);
/** This return a printable string not an alphanumeric one @deprecated */
RS_DEPRECATED_FOR("RsRandom::printable")
static inline std::string random_alphaNumericString(uint32_t length)
{ return printable(length); }
private:
static RsMutex rndMtx;

View File

@ -22,6 +22,7 @@
/** \file
*/
#include <openssl/bio.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/dsa.h>

View File

@ -340,6 +340,10 @@ void GenCertDialog::setupState()
ui.hiddenport_spinBox->setVisible(hidden_state && !tor_auto);
ui.cbUseBob->setVisible(hidden_state && !tor_auto);
#ifndef RS_USE_I2P_BOB
ui.cbUseBob->setDisabled(true);
ui.cbUseBob->setToolTip(tr("BOB support is not available"));
#endif
if(!mAllFieldsOk)
{

View File

@ -1575,6 +1575,14 @@ void IdDialog::loadIdentities(const std::map<RsGxsGroupId,RsGxsIdGroup>& ids_set
/* count items */
int itemCount = contactsItem->childCount() + allItem->childCount() + ownItem->childCount();
ui->label_count->setText( "(" + QString::number( itemCount ) + ")" );
int contactsCount = contactsItem->childCount() ;
int allCount = allItem->childCount() ;
int ownCount = ownItem->childCount();
contactsItem->setText(0, tr("My contacts") + " (" + QString::number( contactsCount ) + ")" );
allItem->setText(0, tr("All") + " (" + QString::number( allCount ) + ")" );
ownItem->setText(0, tr("My own identities") + " (" + QString::number( ownCount ) + ")" );
navigate(RsGxsId(oldCurrentId));
filterIds();

View File

@ -146,6 +146,8 @@ void PostedCardView::setup()
QAction *CopyLinkAction = new QAction(QIcon(""),tr("Copy RetroShare Link"), this);
connect(CopyLinkAction, SIGNAL(triggered()), this, SLOT(copyMessageLink()));
QAction *showInPeopleAct = new QAction(QIcon(), tr("Show author in people tab"), this);
connect(showInPeopleAct, SIGNAL(triggered()), this, SLOT(showAuthorInPeople()));
int S = QFontMetricsF(font()).height() ;
@ -157,6 +159,8 @@ void PostedCardView::setup()
QMenu *menu = new QMenu();
menu->addAction(CopyLinkAction);
menu->addSeparator();
menu->addAction(showInPeopleAct);
ui->shareButton->setMenu(menu);
ui->clearButton->hide();
@ -172,90 +176,106 @@ void PostedCardView::fill()
// return;
// }
QPixmap sqpixmap2 = QPixmap(":/images/thumb-default.png");
RsReputationLevel overall_reputation = rsReputations->overallReputationLevel(mPost.mMeta.mAuthorId);
bool redacted = (overall_reputation == RsReputationLevel::LOCALLY_NEGATIVE);
mInFill = true;
int desired_height = 1.5*(ui->voteDownButton->height() + ui->voteUpButton->height() + ui->scoreLabel->height());
int desired_width = sqpixmap2.width()*desired_height/(float)sqpixmap2.height();
QDateTime qtime;
qtime.setTime_t(mPost.mMeta.mPublishTs);
QString timestamp = qtime.toString("hh:mm dd-MMM-yyyy");
QString timestamp2 = misc::timeRelativeToNow(mPost.mMeta.mPublishTs);
ui->dateLabel->setText(timestamp2);
ui->dateLabel->setToolTip(timestamp);
ui->fromLabel->setId(mPost.mMeta.mAuthorId);
// Use QUrl to check/parse our URL
// The only combination that seems to work: load as EncodedUrl, extract toEncoded().
QByteArray urlarray(mPost.mLink.c_str());
QUrl url = QUrl::fromEncoded(urlarray.trimmed());
QString urlstr = "Invalid Link";
QString sitestr = "Invalid Link";
bool urlOkay = url.isValid();
if (urlOkay)
{
QString scheme = url.scheme();
if ((scheme != "https")
&& (scheme != "http")
&& (scheme != "ftp")
&& (scheme != "retroshare"))
{
urlOkay = false;
sitestr = "Invalid Link Scheme";
}
}
if (urlOkay)
{
urlstr = QString("<a href=\"");
urlstr += QString(url.toEncoded());
urlstr += QString("\" ><span style=\" text-decoration: underline; color:#2255AA;\"> ");
urlstr += messageName();
urlstr += QString(" </span></a>");
QString siteurl = url.toEncoded();
sitestr = QString("<a href=\"%1\" ><span style=\" text-decoration: underline; color:#0079d3;\"> %2 </span></a>").arg(siteurl).arg(siteurl);
ui->titleLabel->setText(urlstr);
}else
{
ui->titleLabel->setText(messageName());
}
if (urlarray.isEmpty())
{
ui->siteLabel->hide();
}
ui->siteLabel->setText(sitestr);
if(mPost.mImage.mData != NULL)
{
QPixmap pixmap;
GxsIdDetails::loadPixmapFromData(mPost.mImage.mData, mPost.mImage.mSize, pixmap,GxsIdDetails::ORIGINAL);
// Wiping data - as its been passed to thumbnail.
QPixmap scaledpixmap;
if(pixmap.width() > 800){
QPixmap scaledpixmap = pixmap.scaledToWidth(800, Qt::SmoothTransformation);
ui->pictureLabel->setPixmap(scaledpixmap);
}else{
ui->pictureLabel->setPixmap(pixmap);
}
}
else if (mPost.mImage.mData == NULL)
{
if(redacted) {
ui->commentButton->setDisabled(true);
ui->voteUpButton->setDisabled(true);
ui->voteDownButton->setDisabled(true);
ui->picture_frame->hide();
}
else
{
ui->picture_frame->show();
}
ui->fromLabel->setId(mPost.mMeta.mAuthorId);
ui->titleLabel->setText(tr( "<p><font color=\"#ff0000\"><b>The author of this message (with ID %1) is banned.</b>").arg(QString::fromStdString(mPost.mMeta.mAuthorId.toStdString()))) ;
QDateTime qtime;
qtime.setTime_t(mPost.mMeta.mPublishTs);
QString timestamp = qtime.toString("hh:mm dd-MMM-yyyy");
ui->dateLabel->setText(timestamp);
} else {
QPixmap sqpixmap2 = FilesDefs::getPixmapFromQtResourcePath(":/images/thumb-default.png");
mInFill = true;
int desired_height = 1.5*(ui->voteDownButton->height() + ui->voteUpButton->height() + ui->scoreLabel->height());
int desired_width = sqpixmap2.width()*desired_height/(float)sqpixmap2.height();
QDateTime qtime;
qtime.setTime_t(mPost.mMeta.mPublishTs);
QString timestamp = qtime.toString("hh:mm dd-MMM-yyyy");
QString timestamp2 = misc::timeRelativeToNow(mPost.mMeta.mPublishTs);
ui->dateLabel->setText(timestamp2);
ui->dateLabel->setToolTip(timestamp);
ui->fromLabel->setId(mPost.mMeta.mAuthorId);
// Use QUrl to check/parse our URL
// The only combination that seems to work: load as EncodedUrl, extract toEncoded().
QByteArray urlarray(mPost.mLink.c_str());
QUrl url = QUrl::fromEncoded(urlarray.trimmed());
QString urlstr = "Invalid Link";
QString sitestr = "Invalid Link";
bool urlOkay = url.isValid();
if (urlOkay)
{
QString scheme = url.scheme();
if ((scheme != "https")
&& (scheme != "http")
&& (scheme != "ftp")
&& (scheme != "retroshare"))
{
urlOkay = false;
sitestr = "Invalid Link Scheme";
}
}
if (urlOkay)
{
urlstr = QString("<a href=\"");
urlstr += QString(url.toEncoded());
urlstr += QString("\" ><span style=\" text-decoration: underline; color:#2255AA;\"> ");
urlstr += messageName();
urlstr += QString(" </span></a>");
QString siteurl = url.toEncoded();
sitestr = QString("<a href=\"%1\" ><span style=\" text-decoration: underline; color:#0079d3;\"> %2 </span></a>").arg(siteurl).arg(siteurl);
ui->titleLabel->setText(urlstr);
}else
{
ui->titleLabel->setText(messageName());
}
if (urlarray.isEmpty())
{
ui->siteLabel->hide();
}
ui->siteLabel->setText(sitestr);
if(mPost.mImage.mData != NULL)
{
QPixmap pixmap;
GxsIdDetails::loadPixmapFromData(mPost.mImage.mData, mPost.mImage.mSize, pixmap,GxsIdDetails::ORIGINAL);
// Wiping data - as its been passed to thumbnail.
QPixmap scaledpixmap;
if(pixmap.width() > 800){
QPixmap scaledpixmap = pixmap.scaledToWidth(800, Qt::SmoothTransformation);
ui->pictureLabel->setPixmap(scaledpixmap);
}else{
ui->pictureLabel->setPixmap(pixmap);
}
}
else if (mPost.mImage.mData == NULL)
{
ui->picture_frame->hide();
}
else
{
ui->picture_frame->show();
}
}
//QString score = "Hot" + QString::number(post.mHotScore);
//score += " Top" + QString::number(post.mTopScore);

View File

@ -32,6 +32,8 @@
#include "gui/common/FilesDefs.h"
#include "util/qtthreadsutils.h"
#include "util/HandleRichText.h"
#include "gui/MainWindow.h"
#include "gui/Identity/IdDialog.h"
#include "PhotoView.h"
#include "ui_PostedItem.h"
@ -338,6 +340,24 @@ void BasePostedItem::viewPicture()
/* window will destroy itself! */
}
void BasePostedItem::showAuthorInPeople()
{
if(mPost.mMeta.mAuthorId.isNull())
{
std::cerr << "(EE) GxsForumThreadWidget::loadMsgData_showAuthorInPeople() ERROR Missing Message Data...";
std::cerr << std::endl;
}
/* window will destroy itself! */
IdDialog *idDialog = dynamic_cast<IdDialog*>(MainWindow::getPage(MainWindow::People));
if (!idDialog)
return ;
MainWindow::showWindow(MainWindow::People);
idDialog->navigate(RsGxsId(mPost.mMeta.mAuthorId));
}
//========================================================================================
// PostedItem //
//========================================================================================
@ -394,6 +414,8 @@ void PostedItem::setup()
QAction *CopyLinkAction = new QAction(QIcon(""),tr("Copy RetroShare Link"), this);
connect(CopyLinkAction, SIGNAL(triggered()), this, SLOT(copyMessageLink()));
QAction *showInPeopleAct = new QAction(QIcon(), tr("Show author in people tab"), this);
connect(showInPeopleAct, SIGNAL(triggered()), this, SLOT(showAuthorInPeople()));
int S = QFontMetricsF(font()).height() ;
@ -407,6 +429,8 @@ void PostedItem::setup()
QMenu *menu = new QMenu();
menu->addAction(CopyLinkAction);
menu->addSeparator();
menu->addAction(showInPeopleAct);
ui->shareButton->setMenu(menu);
ui->clearButton->hide();
@ -438,8 +462,6 @@ void PostedItem::makeUpVote()
emit vote(msgId, true);
}
void PostedItem::setComment(const RsGxsComment& cmt)
{
ui->newCommentLabel->show();
@ -459,97 +481,115 @@ void PostedItem::setCommentsSize(int comNb)
void PostedItem::fill()
{
RetroShareLink link = RetroShareLink::createGxsGroupLink(RetroShareLink::TYPE_POSTED, mGroupMeta.mGroupId, groupName());
ui->nameLabel->setText(link.toHtml());
RsReputationLevel overall_reputation = rsReputations->overallReputationLevel(mPost.mMeta.mAuthorId);
bool redacted = (overall_reputation == RsReputationLevel::LOCALLY_NEGATIVE);
QPixmap sqpixmap2 = QPixmap(":/images/thumb-default.png");
if(redacted) {
ui->expandButton->setDisabled(true);
ui->commentButton->setDisabled(true);
ui->voteUpButton->setDisabled(true);
ui->voteDownButton->setDisabled(true);
mInFill = true;
int desired_height = 1.5*(ui->voteDownButton->height() + ui->voteUpButton->height() + ui->scoreLabel->height());
int desired_width = sqpixmap2.width()*desired_height/(float)sqpixmap2.height();
ui->thumbnailLabel->setPixmap( QPixmap(":/images/thumb-default.png"));
ui->fromLabel->setId(mPost.mMeta.mAuthorId);
ui->titleLabel->setText(tr( "<p><font color=\"#ff0000\"><b>The author of this message (with ID %1) is banned.</b>").arg(QString::fromStdString(mPost.mMeta.mAuthorId.toStdString()))) ;
QDateTime qtime;
qtime.setTime_t(mPost.mMeta.mPublishTs);
QString timestamp = qtime.toString("hh:mm dd-MMM-yyyy");
ui->dateLabel->setText(timestamp);
} else {
RetroShareLink link = RetroShareLink::createGxsGroupLink(RetroShareLink::TYPE_POSTED, mGroupMeta.mGroupId, groupName());
ui->nameLabel->setText(link.toHtml());
QDateTime qtime;
qtime.setTime_t(mPost.mMeta.mPublishTs);
QString timestamp = qtime.toString("hh:mm dd-MMM-yyyy");
QString timestamp2 = misc::timeRelativeToNow(mPost.mMeta.mPublishTs);
ui->dateLabel->setText(timestamp2);
ui->dateLabel->setToolTip(timestamp);
QPixmap sqpixmap2 = FilesDefs::getPixmapFromQtResourcePath(":/images/thumb-default.png");
ui->fromLabel->setId(mPost.mMeta.mAuthorId);
mInFill = true;
int desired_height = 1.5*(ui->voteDownButton->height() + ui->voteUpButton->height() + ui->scoreLabel->height());
int desired_width = sqpixmap2.width()*desired_height/(float)sqpixmap2.height();
// Use QUrl to check/parse our URL
// The only combination that seems to work: load as EncodedUrl, extract toEncoded().
QByteArray urlarray(mPost.mLink.c_str());
QUrl url = QUrl::fromEncoded(urlarray.trimmed());
QString urlstr = "Invalid Link";
QString sitestr = "Invalid Link";
QDateTime qtime;
qtime.setTime_t(mPost.mMeta.mPublishTs);
QString timestamp = qtime.toString("hh:mm dd-MMM-yyyy");
QString timestamp2 = misc::timeRelativeToNow(mPost.mMeta.mPublishTs);
ui->dateLabel->setText(timestamp2);
ui->dateLabel->setToolTip(timestamp);
bool urlOkay = url.isValid();
if (urlOkay)
{
QString scheme = url.scheme();
if ((scheme != "https")
&& (scheme != "http")
&& (scheme != "ftp")
&& (scheme != "retroshare"))
ui->fromLabel->setId(mPost.mMeta.mAuthorId);
// Use QUrl to check/parse our URL
// The only combination that seems to work: load as EncodedUrl, extract toEncoded().
QByteArray urlarray(mPost.mLink.c_str());
QUrl url = QUrl::fromEncoded(urlarray.trimmed());
QString urlstr = "Invalid Link";
QString sitestr = "Invalid Link";
bool urlOkay = url.isValid();
if (urlOkay)
{
urlOkay = false;
sitestr = "Invalid Link Scheme";
QString scheme = url.scheme();
if ((scheme != "https")
&& (scheme != "http")
&& (scheme != "ftp")
&& (scheme != "retroshare"))
{
urlOkay = false;
sitestr = "Invalid Link Scheme";
}
}
}
if (urlOkay)
{
urlstr = QString("<a href=\"");
urlstr += QString(url.toEncoded());
urlstr += QString("\" ><span style=\" text-decoration: underline; color:#2255AA;\"> ");
urlstr += messageName();
urlstr += QString(" </span></a>");
if (urlOkay)
{
urlstr = QString("<a href=\"");
urlstr += QString(url.toEncoded());
urlstr += QString("\" ><span style=\" text-decoration: underline; color:#2255AA;\"> ");
urlstr += messageName();
urlstr += QString(" </span></a>");
QString siteurl = url.toEncoded();
sitestr = QString("<a href=\"%1\" ><span style=\" text-decoration: underline; color:#0079d3;\"> %2 </span></a>").arg(siteurl).arg(siteurl);
QString siteurl = url.toEncoded();
sitestr = QString("<a href=\"%1\" ><span style=\" text-decoration: underline; color:#0079d3;\"> %2 </span></a>").arg(siteurl).arg(siteurl);
ui->titleLabel->setText(urlstr);
}else
{
ui->titleLabel->setText(messageName());
ui->titleLabel->setText(urlstr);
}else
{
ui->titleLabel->setText(messageName());
}
if (urlarray.isEmpty())
{
ui->siteLabel->hide();
}
ui->siteLabel->setText(sitestr);
if(mPost.mImage.mData != NULL)
{
QPixmap pixmap;
GxsIdDetails::loadPixmapFromData(mPost.mImage.mData, mPost.mImage.mSize, pixmap,GxsIdDetails::ORIGINAL);
// Wiping data - as its been passed to thumbnail.
QPixmap sqpixmap = pixmap.scaled(desired_width,desired_height, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
ui->thumbnailLabel->setPixmap(sqpixmap);
ui->thumbnailLabel->setToolTip(tr("Click to view Picture"));
QPixmap scaledpixmap;
if(pixmap.width() > 800){
QPixmap scaledpixmap = pixmap.scaledToWidth(800, Qt::SmoothTransformation);
ui->pictureLabel->setPixmap(scaledpixmap);
}else{
ui->pictureLabel->setPixmap(pixmap);
}
}
else if (urlOkay && (mPost.mImage.mData == NULL))
{
ui->expandButton->setDisabled(true);
ui->thumbnailLabel->setPixmap(FilesDefs::getPixmapFromQtResourcePath(LINK_IMAGE));
}
else
{
ui->expandButton->setDisabled(true);
ui->thumbnailLabel->setPixmap(sqpixmap2);
if (urlarray.isEmpty())
{
ui->siteLabel->hide();
}
ui->siteLabel->setText(sitestr);
if(mPost.mImage.mData != NULL)
{
QPixmap pixmap;
GxsIdDetails::loadPixmapFromData(mPost.mImage.mData, mPost.mImage.mSize, pixmap,GxsIdDetails::ORIGINAL);
// Wiping data - as its been passed to thumbnail.
QPixmap sqpixmap = pixmap.scaled(desired_width,desired_height, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
ui->thumbnailLabel->setPixmap(sqpixmap);
ui->thumbnailLabel->setToolTip(tr("Click to view Picture"));
QPixmap scaledpixmap;
if(pixmap.width() > 800){
QPixmap scaledpixmap = pixmap.scaledToWidth(800, Qt::SmoothTransformation);
ui->pictureLabel->setPixmap(scaledpixmap);
}else{
ui->pictureLabel->setPixmap(pixmap);
}
}
else if (urlOkay && (mPost.mImage.mData == NULL))
{
ui->expandButton->setDisabled(true);
ui->thumbnailLabel->setPixmap(FilesDefs::getPixmapFromQtResourcePath(LINK_IMAGE));
}
else
{
ui->expandButton->setDisabled(true);
ui->thumbnailLabel->setPixmap(sqpixmap2);
}
}
@ -701,5 +741,3 @@ void PostedItem::toggleNotes()
}
}

View File

@ -55,6 +55,7 @@ private slots:
void readAndClearItem();
void copyMessageLink();
void viewPicture();
void showAuthorInPeople();
signals:
void vote(const RsGxsGrpMsgIdPair& msgId, bool up);

View File

@ -298,199 +298,10 @@
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="logoLabel">
<property name="minimumSize">
<size>
<width>64</width>
<height>64</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>64</width>
<height>64</height>
</size>
</property>
<property name="pixmap">
<pixmap resource="../icons.qrc">:/icons/png/postedlinks.png</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="namelabel">
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QFormLayout" name="formLayout">
<property name="topMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Popularity</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="poplabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="infoPostsLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Posts</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="infoPosts">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">0</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="createdlabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Created</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="createdinfolabel">
<property name="text">
<string>unknown</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Administrator:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="GxsIdLabel" name="infoAdministrator">
<property name="text">
<string>unknown</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_3">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Distribution:</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="infoDistribution">
<property name="text">
<string>unknown</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="infoLastPostLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Last Post:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="infoLastPost">
<property name="text">
<string notr="true">unknown</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="1">
<property name="topMargin">
<number>6</number>
</property>
<item row="0" column="1">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@ -503,7 +314,7 @@
</property>
</spacer>
</item>
<item row="2" column="0" colspan="2">
<item row="1" column="0" colspan="2">
<widget class="QTextBrowser" name="infoDescription">
<property name="styleSheet">
<string notr="true"/>
@ -526,6 +337,194 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item row="0" column="0">
<layout class="QFormLayout" name="formLayout">
<property name="topMargin">
<number>0</number>
</property>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Popularity</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="poplabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="infoPostsLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Posts</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="infoPosts">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string notr="true">0</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="createdlabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Created</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLabel" name="createdinfolabel">
<property name="text">
<string>unknown</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Administrator:</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="GxsIdLabel" name="infoAdministrator">
<property name="text">
<string>unknown</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_3">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Distribution:</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="infoDistribution">
<property name="text">
<string>unknown</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="infoLastPostLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Last Post:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="infoLastPost">
<property name="text">
<string notr="true">unknown</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="logoLabel">
<property name="minimumSize">
<size>
<width>64</width>
<height>64</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>64</width>
<height>64</height>
</size>
</property>
<property name="pixmap">
<pixmap resource="../icons.qrc">:/icons/png/postedlinks.png</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="namelabel">
<property name="font">
<font>
<pointsize>14</pointsize>
</font>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>

View File

@ -39,19 +39,19 @@
//#define DEBUG_EID_PAINT 1
/* To test it you can make an empty.qss file with:
QTreeView::item, QTreeWidget::item{
QTreeView::item, QTreeWidget::item, QListWidget::item{
color: #AB0000;
background-color: #00DC00;
}
QTreeView::item:selected, QTreeWidget::item:selected{
QTreeView::item:selected, QTreeWidget::item:selected, QListWidget::item:selected{
color: #00CD00;
background-color: #0000BA;
}
QTreeView::item:hover, QTreeWidget::item:hover{
QTreeView::item:hover, QTreeWidget::item:hover, QListWidget::item:hover{
color: #0000EF;
background-color: #FEDCBA;
}
QQTreeView::item:selected:hover, TreeWidget::item:selected:hover{
QQTreeView::item:selected:hover, TreeWidget::item:selected:hover, QListWidget::item:selected:hover{
color: #ABCDEF;
background-color: #FE0000;
}

View File

@ -23,6 +23,10 @@
#ifndef ELNODE_H
#define ELNODE_H
#include "graphwidget.h"
#include <retroshare/rstypes.h>
#include <QApplication>
#if QT_VERSION >= 0x040600
#include <QGraphicsObject>
@ -30,9 +34,7 @@
#include <QGraphicsItem>
#endif
#include <QList>
#include <retroshare/rstypes.h>
#include "graphwidget.h"
#include <QPainterPath>
class Edge;
QT_BEGIN_NAMESPACE

View File

@ -937,5 +937,7 @@
<file>emojione/1F1FF-1F1FC.png</file>
<file>emojione/flags.png</file>
<file>emojione/flags2.png</file>
<file>emojione/man-facepalming.png</file>
<file>emojione/woman-facepalming.png</file>
</qresource>
</RCC>

View File

@ -113,6 +113,8 @@
"emojione/people2.png"|":man_with_gua_pi_mao:":"emojione/1F472.png";
"emojione/people2.png"|":levitate:|:man_in_business_suit_levitating:":"emojione/1F574.png";
"emojione/people2.png"|":dancer:":"emojione/1F483.png";
"emojione/people2.png"|":man_facepalming:":"emojione/man-facepalming.png";
"emojione/people2.png"|":woman_facepalming:":"emojione/woman-facepalming.png";
"emojione/people2.png"|":bust_in_silhouette:":"emojione/1F464.png";
"emojione/people2.png"|":busts_in_silhouette:":"emojione/1F465.png";
"emojione/people2.png"|":family:":"emojione/1F46A.png";

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -18,6 +18,14 @@
* *
*******************************************************************************/
#include "GxsCommentTreeWidget.h"
#include "gui/common/FilesDefs.h"
#include "gui/common/RSElidedItemDelegate.h"
#include "gui/common/RSTreeWidgetItem.h"
#include "gui/gxs/GxsCreateCommentDialog.h"
#include "gui/gxs/GxsIdTreeWidgetItem.h"
#include <QAbstractTextDocumentLayout>
#include <QApplication>
#include <QClipboard>
@ -28,13 +36,6 @@
#include <QPainterPath>
#include <QTextDocument>
#include "gui/common/RSElidedItemDelegate.h"
#include "gui/common/FilesDefs.h"
#include "gui/gxs/GxsCommentTreeWidget.h"
#include "gui/gxs/GxsCreateCommentDialog.h"
#include "gui/gxs/GxsIdTreeWidgetItem.h"
#include "gui/common/RSTreeWidgetItem.h"
#include <iostream>
#define PCITEM_COLUMN_COMMENT 0

View File

@ -18,22 +18,23 @@
* *
*******************************************************************************/
#include <QApplication>
#include <QThread>
#include <QTimerEvent>
#include <QMutexLocker>
#include <math.h>
#include <util/rsdir.h>
#include "gui/common/AvatarDialog.h"
#include "GxsIdDetails.h"
#include "gui/common/AvatarDialog.h"
#include "retroshare-gui/RsAutoUpdatePage.h"
#include <retroshare/rspeers.h>
#include <util/rsdir.h>
#include <iostream>
#include <QApplication>
#include <QMutexLocker>
#include <QPainter>
#include <QPainterPath>
#include <QThread>
#include <QTimerEvent>
#include <iostream>
#include <cmath>
/* Images for tag icons */
#define IMAGE_LOADING ":/images/folder-draft.png"

View File

@ -301,6 +301,7 @@
<file>icons/png/arrow-left.png</file>
<file>icons/png/next-unread.png</file>
<file>icons/mail/compose.png</file>
<file>icons/mail/downloadall.png</file>
<file>icons/mail/delete.png</file>
<file>icons/mail/tags.png</file>
<file>icons/mail/quote.png</file>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -1206,6 +1206,12 @@ MessageComposer *MessageComposer::replyMsg(const std::string &msgId, bool all)
// needed to send system flags with reply
msgComposer->msgFlags = (msgInfo.msgflags & RS_MSG_SYSTEM);
MsgTagInfo tagInfo;
rsMail->getMessageTag(msgId, tagInfo);
msgComposer->m_tagIds = tagInfo.tagIds;
msgComposer->showTagLabels();
msgComposer->calculateTitle();
/* window will destroy itself! */

View File

@ -36,6 +36,7 @@
#include "gui/common/TagDefs.h"
#include "gui/common/PeerDefs.h"
#include "gui/common/Emoticons.h"
#include "gui/common/FilesDefs.h"
#include "gui/settings/rsharesettings.h"
#include "MessageComposer.h"
#include "MessageWidget.h"
@ -51,8 +52,8 @@
#include <retroshare/rsmsgs.h>
/* Images for context menu icons */
#define IMAGE_DOWNLOAD ":/images/start.png"
#define IMAGE_DOWNLOADALL ":/images/startall.png"
#define IMAGE_DOWNLOAD ":/icons/png/download.png"
#define IMAGE_DOWNLOADALL ":/icons/mail/downloadall.png"
#define COLUMN_FILE_NAME 0
#define COLUMN_FILE_SIZE 1
@ -555,6 +556,7 @@ void MessageWidget::fill(const std::string &msgId)
for (it = recList.begin(); it != recList.end(); ++it) {
QTreeWidgetItem *item = new QTreeWidgetItem;
item->setText(COLUMN_FILE_NAME, QString::fromUtf8(it->fname.c_str()));
item->setIcon(COLUMN_FILE_NAME, FilesDefs::getIconFromFileType(it->fname.c_str()));
item->setText(COLUMN_FILE_SIZE, misc::friendlyUnit(it->size));
item->setData(COLUMN_FILE_SIZE, Qt::UserRole, QVariant(qulonglong(it->size)) );
item->setText(COLUMN_FILE_HASH, QString::fromStdString(it->hash.toStdString()));
@ -667,10 +669,14 @@ void MessageWidget::fill(const std::string &msgId)
}
ui.subjectText->setText(QString::fromUtf8(msgInfo.title.c_str()));
unsigned int formatTextFlag = RSHTML_FORMATTEXT_EMBED_LINKS ;
// emoticons disabled because of crazy cost.
//text = RsHtmlMsg(msgInfo.msgflags).formatText(ui.msgText->document(), QString::fromUtf8(msgInfo.msg.c_str()), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS);
text = RsHtmlMsg(msgInfo.msgflags).formatText(ui.msgText->document(), QString::fromUtf8(msgInfo.msg.c_str()), RSHTML_FORMATTEXT_EMBED_LINKS);
// embed smileys ?
if (Settings->valueFromGroup(QString("Messages"), QString::fromUtf8("Emoticons"), true).toBool()) {
formatTextFlag |= RSHTML_FORMATTEXT_EMBED_SMILEYS ;
}
text = RsHtmlMsg(msgInfo.msgflags).formatText(ui.msgText->document(), QString::fromUtf8(msgInfo.msg.c_str()), formatTextFlag);
ui.msgText->resetImagesStatus(Settings->getMsgLoadEmbeddedImages() || (msgInfo.msgflags & RS_MSG_LOAD_EMBEDDED_IMAGES));
ui.msgText->setHtml(text);

View File

@ -53,6 +53,7 @@
#include <algorithm>
/* Images for context menu icons */
#define IMAGE_MAIL ":/icons/png/message.png"
#define IMAGE_MESSAGE ":/icons/mail/compose.png"
#define IMAGE_MESSAGEREMOVE ":/icons/mail/delete.png"
#define IMAGE_STAR_ON ":/images/star-on-16.png"
@ -766,7 +767,7 @@ void MessagesDialog::openAsTab()
return;
}
ui.tabWidget->addTab(msgWidget, msgWidget->subject(true));
ui.tabWidget->addTab(msgWidget,QIcon(IMAGE_MAIL), msgWidget->subject(true));
ui.tabWidget->setCurrentWidget(msgWidget);
connect(msgWidget, SIGNAL(messageRemoved()), this, SLOT(messageRemoved()));
@ -1104,7 +1105,10 @@ void MessagesDialog::removemessage()
void MessagesDialog::messageRemoved()
{
ui.messageTreeWidget->setCurrentIndex(lastSelectedIndex);
if (lastSelectedIndex.isValid())
ui.messageTreeWidget->setCurrentIndex(lastSelectedIndex);
else
insertMsgTxtAndFiles(QModelIndex());
}
void MessagesDialog::undeletemessage()

View File

@ -904,6 +904,16 @@ MessagesDialog QWidget#messageTreeWidget::item {
padding: 2px;
}
MessagesDialog QWidget#messageTreeWidget::item:selected {
background-color: #cde8ff;
color: black;
}
MessagesDialog QWidget#messageTreeWidget::item:hover {
background-color: #e5f3ff;
color: black;
}
GxsForumThreadWidget QWidget#threadTreeWidget::item {
padding: 2px;
}

View File

@ -39,7 +39,6 @@ MessagePage::MessagePage(QWidget * parent, Qt::WindowFlags flags)
connect (ui.editpushButton, SIGNAL(clicked(bool)), this, SLOT (editTag()));
connect (ui.deletepushButton, SIGNAL(clicked(bool)), this, SLOT (deleteTag()));
connect (ui.defaultTagButton, SIGNAL(clicked(bool)), this, SLOT (defaultTag()));
//connect (ui.encryptedMsgs_CB, SIGNAL(toggled(bool)), this, SLOT (toggleEnableEncryptedDistantMsgs(bool)));
connect (ui.tags_listWidget, SIGNAL(currentRowChanged(int)), this, SLOT(currentRowChangedTag(int)));
@ -54,6 +53,7 @@ MessagePage::MessagePage(QWidget * parent, Qt::WindowFlags flags)
connect(ui.setMsgToReadOnActivate,SIGNAL(toggled(bool)), this,SLOT(updateMsgToReadOnActivate()));
connect(ui.loadEmbeddedImages, SIGNAL(toggled(bool)), this,SLOT(updateLoadEmbededImages() ));
connect(ui.openComboBox, SIGNAL(currentIndexChanged(int)),this,SLOT(updateMsgOpen() ));
connect(ui.emoticonscheckBox, SIGNAL(toggled(bool)), this,SLOT(updateLoadEmoticons() ));
}
MessagePage::~MessagePage()
@ -84,6 +84,7 @@ void MessagePage::updateMsgToReadOnActivate() { Settings->setMsgSetToReadOnActiv
void MessagePage::updateLoadEmbededImages() { Settings->setMsgLoadEmbeddedImages(ui.loadEmbeddedImages->isChecked()); }
void MessagePage::updateMsgOpen() { Settings->setMsgOpen( static_cast<RshareSettings::enumMsgOpen>(ui.openComboBox->itemData(ui.openComboBox->currentIndex()).toInt()) ); }
void MessagePage::updateDistantMsgs() { Settings->setValue("DistantMessages", ui.comboBox->currentIndex()); }
void MessagePage::updateLoadEmoticons() { Settings->setValueToGroup("Messages", "Emoticons", ui.emoticonscheckBox->isChecked()); }
void MessagePage::updateMsgTags()
{
@ -110,9 +111,12 @@ void MessagePage::updateMsgTags()
void
MessagePage::load()
{
Settings->beginGroup(QString("Messages"));
whileBlocking(ui.setMsgToReadOnActivate)->setChecked(Settings->getMsgSetToReadOnActivate());
whileBlocking(ui.loadEmbeddedImages)->setChecked(Settings->getMsgLoadEmbeddedImages());
whileBlocking(ui.openComboBox)->setCurrentIndex(ui.openComboBox->findData(Settings->getMsgOpen()));
whileBlocking(ui.emoticonscheckBox)->setChecked(Settings->value("Emoticons", true).toBool());
Settings->endGroup();
// state of filter combobox
@ -267,3 +271,4 @@ void MessagePage::currentRowChangedTag(int row)
ui.editpushButton->setEnabled(bEditEnable);
ui.deletepushButton->setEnabled(bDeleteEnable);
}

View File

@ -58,6 +58,7 @@ private slots:
void updateMsgOpen() ;
void updateDistantMsgs() ;
void updateMsgTags() ;
void updateLoadEmoticons();
private:
void fillTags();

View File

@ -65,14 +65,7 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="loadEmbeddedImages">
<property name="text">
<string>Load embedded images</string>
</property>
</widget>
</item>
<item row="2" column="0">
<item row="3" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="openLabel">
@ -86,6 +79,20 @@
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="loadEmbeddedImages">
<property name="text">
<string>Load embedded images</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="emoticonscheckBox">
<property name="text">
<string>Load Emoticons</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -23,6 +23,7 @@
#include <gui/notifyqt.h>
#include "rshare.h"
#include "rsharesettings.h"
#include "util/i2pcommon.h"
#include "util/RsNetUtil.h"
#include "util/misc.h"
@ -82,6 +83,10 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags)
manager = NULL ;
mOngoingConnectivityCheck = -1;
#ifndef RS_USE_I2P_BOB
ui.hiddenServiceTab->removeTab(TAB_HIDDEN_SERVICE_I2P_BOB); // warning: the order of operation here is very important.
#endif
if(RsAccounts::isHiddenNode())
{
if(RsAccounts::isTorAuto())
@ -1352,7 +1357,7 @@ void ServerPage::updateInProxyIndicator()
ui.iconlabel_service_incoming->setMovie(movie);
movie->start();
if (mHiddenType == RS_HIDDEN_TYPE_I2P && mBobSettings.enableBob) {
if (mHiddenType == RS_HIDDEN_TYPE_I2P && mBobSettings.enable) {
QTcpSocket tcpSocket;
@ -1439,15 +1444,16 @@ void ServerPage::getNewKey()
void ServerPage::loadKey()
{
mBobSettings.keys = ui.pteBobServerKey->toPlainText().toStdString();
mBobSettings.addr = p3I2pBob::keyToBase32Addr(mBobSettings.keys);
mBobSettings.address.privateKey = ui.pteBobServerKey->toPlainText().toStdString();
mBobSettings.address.publicKey = i2p::publicKeyFromPrivate(mBobSettings.address.privateKey);
mBobSettings.address.base32 = i2p::keyToBase32Addr(mBobSettings.address.publicKey);
rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &mBobSettings);
}
void ServerPage::enableBob(bool checked)
{
mBobSettings.enableBob = checked;
mBobSettings.enable = checked;
rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &mBobSettings);
@ -1487,7 +1493,7 @@ void ServerPage::toggleBobAdvancedSettings(bool checked)
{
ui.swBobAdvanced->setCurrentIndex(checked ? 1 : 0);
if (!mBobSettings.keys.empty()) {
if (!mBobSettings.address.privateKey.empty()) {
if (checked) {
ui.pbBobGenAddr->show();
} else {
@ -1578,9 +1584,9 @@ void ServerPage::loadCommon()
whileBlocking(ui.hiddenpage_proxyPort_i2p_2)->setValue(proxyport); // this one is for bob tab
// don't use whileBlocking here
ui.cb_enableBob->setChecked(mBobSettings.enableBob);
ui.cb_enableBob->setChecked(mBobSettings.enable);
if (!mBobSettings.keys.empty()) {
if (!mBobSettings.address.privateKey.empty()) {
ui.lBobB32Addr->show();
ui.leBobB32Addr->show();
}
@ -1623,13 +1629,13 @@ void ServerPage::saveBob()
void ServerPage::updateStatusBob()
{
QString addr = QString::fromStdString(mBobSettings.addr);
QString addr = QString::fromStdString(mBobSettings.address.base32);
if (ui.leBobB32Addr->text() != addr) {
ui.leBobB32Addr->setText(addr);
ui.hiddenpage_serviceAddress->setText(addr);
ui.pteBobServerKey->setPlainText(QString::fromStdString(mBobSettings.keys));
ui.pteBobServerKey->setPlainText(QString::fromStdString(mBobSettings.address.privateKey));
if (!mBobSettings.keys.empty()) {
if (!mBobSettings.address.privateKey.empty()) {
// we have an addr -> show fields
ui.lBobB32Addr->show();
ui.leBobB32Addr->show();
@ -1655,7 +1661,7 @@ void ServerPage::updateStatusBob()
QString bobSimpleText = QString();
bobSimpleText.append(tr("RetroShare uses BOB to set up a %1 tunnel at %2:%3 (named %4)\n\n"
"When changing options (e.g. port) use the buttons at the bottom to restart BOB.\n\n").
arg(mBobSettings.keys.empty() ? tr("client") : tr("server"),
arg(mBobSettings.address.privateKey.empty() ? tr("client") : tr("server"),
ui.hiddenpage_proxyAddress_i2p_2->text(),
ui.hiddenpage_proxyPort_i2p_2->text(),
bs.tunnelName.empty() ? tr("unknown") :
@ -1777,15 +1783,15 @@ void ServerPage::updateStatusBob()
void ServerPage::setUpBobElements()
{
ui.gbBob->setEnabled(mBobSettings.enableBob);
if (mBobSettings.enableBob) {
ui.gbBob->setEnabled(mBobSettings.enable);
if (mBobSettings.enable) {
ui.hiddenpage_proxyAddress_i2p->setEnabled(false);
ui.hiddenpage_proxyAddress_i2p->setToolTip("Use I2P/BOB settings to change this value");
ui.hiddenpage_proxyPort_i2p->setEnabled(false);
ui.hiddenpage_proxyPort_i2p->setToolTip("Use I2P/BOB settings to change this value");
ui.leBobB32Addr->setText(QString::fromStdString(mBobSettings.addr));
ui.pteBobServerKey->setPlainText(QString::fromStdString(mBobSettings.keys));
ui.leBobB32Addr->setText(QString::fromStdString(mBobSettings.address.base32));
ui.pteBobServerKey->setPlainText(QString::fromStdString(mBobSettings.address.privateKey));
// cast to int to avoid problems
int li, lo, qi, qo, vi, vo;

View File

@ -49,6 +49,9 @@
#include "gui/gxs/GxsIdLabel.h"
#include "gui/gxs/GxsIdDetails.h"
#include "gui/gxs/GxsIdTreeWidgetItem.h"
#include "gui/Identity/IdDialog.h"
#include "gui/MainWindow.h"
#include "gui/common/FilesDefs.h"
#define COL_PENDING_ID 0
#define COL_PENDING_DESTINATION 1
@ -61,11 +64,13 @@
#define COL_PENDING_DESTINATION_ID 8
#define COL_GROUP_GRP_ID 0
#define COL_GROUP_NUM_MSGS 1
#define COL_GROUP_SIZE_MSGS 2
#define COL_GROUP_SUBSCRIBED 3
#define COL_GROUP_POPULARITY 4
#define COL_GROUP_UNIQUE_ID 5
#define COL_GROUP_PUBLISHTS 1
#define COL_GROUP_NUM_MSGS 2
#define COL_GROUP_SIZE_MSGS 3
#define COL_GROUP_SUBSCRIBED 4
#define COL_GROUP_POPULARITY 5
#define COL_GROUP_UNIQUE_ID 6
#define COL_GROUP_AUTHOR_ID 7
//static const int PARTIAL_VIEW_SIZE = 9 ;
//static const int MAX_TUNNEL_REQUESTS_DISPLAY = 10 ;
@ -94,8 +99,10 @@ GxsTransportStatistics::GxsTransportStatistics(QWidget *parent)
QHeaderView_setSectionResizeMode(groupTreeWidget->header(), QHeaderView::ResizeToContents);
connect(treeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(CustomPopupMenu(QPoint)));
treeWidget->setColumnHidden(COL_PENDING_DESTINATION_ID,true);
connect(groupTreeWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(CustomPopupMenuGroups(QPoint)));
treeWidget->setColumnHidden(COL_PENDING_DESTINATION_ID,true);
groupTreeWidget->setColumnHidden(COL_GROUP_AUTHOR_ID,true);
// load settings
processSettings(true);
@ -139,7 +146,20 @@ void GxsTransportStatistics::CustomPopupMenu( QPoint )
QTreeWidgetItem *item = treeWidget->currentItem();
if (item) {
contextMnu.addAction(QIcon(":/images/info16.png"), tr("Details"), this, SLOT(personDetails()));
contextMnu.addAction(FilesDefs::getIconFromQtResourcePath(":/images/info16.png"), tr("View details"), this, SLOT(personDetails()));
}
contextMnu.exec(QCursor::pos());
}
void GxsTransportStatistics::CustomPopupMenuGroups( QPoint )
{
QMenu contextMnu( this );
QTreeWidgetItem *item = groupTreeWidget->currentItem();
if (item) {
contextMnu.addAction(FilesDefs::getIconFromQtResourcePath(":/images/info16.png"), tr("View details"), this, SLOT(showAuthorInPeople()));
}
@ -275,9 +295,10 @@ void GxsTransportStatistics::updateContent()
groupTreeWidget->addTopLevelItem(item);
groupTreeWidget->setItemExpanded(item,openned_groups.find(it->first) != openned_groups.end());
QString msg_time_string = (stat.last_publish_TS>0)?QString(" (Last msg: %1)").arg(QDateTime::fromTime_t((uint)stat.last_publish_TS).toString()):"" ;
QString msg_time_string = (stat.last_publish_TS>0)?QString("(Last msg: %1)").arg(QDateTime::fromTime_t((uint)stat.last_publish_TS).toString()):"" ;
item->setData(COL_GROUP_NUM_MSGS, Qt::DisplayRole, QString::number(stat.mNumMsgs) + msg_time_string) ;
item->setData(COL_GROUP_PUBLISHTS, Qt::DisplayRole, msg_time_string) ;
item->setData(COL_GROUP_NUM_MSGS, Qt::DisplayRole, QString::number(stat.mNumMsgs) ) ;
item->setData(COL_GROUP_GRP_ID, Qt::DisplayRole, QString::fromStdString(it->first.toStdString())) ;
item->setData(COL_GROUP_SIZE_MSGS, Qt::DisplayRole, QString::number(stat.mTotalSizeOfMsgs)) ;
item->setData(COL_GROUP_SUBSCRIBED,Qt::DisplayRole, stat.subscribed?tr("Yes"):tr("No")) ;
@ -308,6 +329,8 @@ void GxsTransportStatistics::updateContent()
rsIdentity->getIdDetails(meta.mAuthorId,idDetails);
QPixmap pixmap ;
QDateTime qdatetime;
qdatetime.setTime_t(meta.mPublishTs);
if(idDetails.mAvatar.mSize == 0 || !GxsIdDetails::loadPixmapFromData(idDetails.mAvatar.mData, idDetails.mAvatar.mSize, pixmap,GxsIdDetails::SMALL))
pixmap = GxsIdDetails::makeDefaultIcon(meta.mAuthorId,GxsIdDetails::SMALL);
@ -315,7 +338,9 @@ void GxsTransportStatistics::updateContent()
sitem->setIcon(COL_GROUP_GRP_ID, QIcon(pixmap));
sitem->setData(COL_GROUP_UNIQUE_ID, Qt::DisplayRole,QString::fromStdString(meta.mMsgId.toStdString()));
sitem->setData(COL_GROUP_NUM_MSGS,Qt::DisplayRole, QDateTime::fromTime_t(meta.mPublishTs).toString());
sitem->setData(COL_GROUP_AUTHOR_ID, Qt::DisplayRole, QString::fromStdString(meta.mAuthorId.toStdString())) ;
sitem->setText(COL_GROUP_PUBLISHTS, QDateTime::fromTime_t(meta.mPublishTs).toString());
sitem->setData(COL_GROUP_PUBLISHTS, Qt::UserRole, qdatetime);
}
}
}
@ -333,6 +358,25 @@ void GxsTransportStatistics::personDetails()
dialog->show();
}
void GxsTransportStatistics::showAuthorInPeople()
{
QTreeWidgetItem *item = groupTreeWidget->currentItem();
std::string id = item->text(COL_GROUP_AUTHOR_ID).toStdString();
if (id.empty()) {
return;
}
/* window will destroy itself! */
IdDialog *idDialog = dynamic_cast<IdDialog*>(MainWindow::getPage(MainWindow::People));
if (!idDialog)
return ;
MainWindow::showWindow(MainWindow::People);
idDialog->navigate(RsGxsId(id));
}
#ifdef TO_REMOVE
void GxsTransportStatistics::loadGroupMeta(const std::vector<RsGroupMetaData>& groupInfo)
{

View File

@ -51,7 +51,10 @@ public:
private slots:
/** Create the context popup menu and it's submenus */
void CustomPopupMenu( QPoint point );
void CustomPopupMenuGroups( QPoint point ) ;
void personDetails();
void showAuthorInPeople();
private:
void updateDisplay(bool complete) ;

View File

@ -41,7 +41,7 @@
<bool>true</bool>
</property>
<attribute name="headerShowSortIndicator" stdset="0">
<bool>false</bool>
<bool>true</bool>
</attribute>
<column>
<property name="text">
@ -108,6 +108,12 @@
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="headerShowSortIndicator" stdset="0">
<bool>true</bool>
</attribute>
<column>
<property name="text">
<string>Group ID / Author</string>
@ -115,7 +121,12 @@
</column>
<column>
<property name="text">
<string>Number of messages / Publish TS</string>
<string>Publish TS</string>
</property>
</column>
<column>
<property name="text">
<string>Number of messages </string>
</property>
</column>
<column>

View File

@ -51,6 +51,10 @@ background: black;
color: lightgray;
border-color: transparent;
}
QTreeView::item, QTreeWidget::item, QListWidget::item{
color: lightgray;
}
QDialog, QMainWindow{
background-color: qlineargradient(spread:reflect, x1:0, y1:0, x2:0, y2:1, stop:0 rgb(25, 25, 25), stop:0.05 rgb(0, 0, 0), stop:0.95 rgb(0, 0, 0), stop:1 rgb(25, 25, 25));
}
@ -255,6 +259,12 @@ QTextEdit {
color: white;
}
RSTextBrowser, MimeTextEdit
{
/*qproperty-textColorQuote: rgb(125, 125, 255);*/
qproperty-textColorQuotes: ColorList(#789922 #039bd5 #800000 #800080 #008080 #b10dc9 #85144b #3d9970);
}
/* OpModeStatus need to be at end to overload other values*/
OpModeStatus {
qproperty-opMode_Full_Color: #007000;

View File

@ -51,6 +51,9 @@ QWidget {
selection-background-color: #1464A0;
selection-color: #F0F0F0;
}
QTreeView::item, QTreeWidget::item, QListWidget::item{
color: #F0F0F0;
}
QWidget:disabled {
background-color: #19232D;
@ -2152,5 +2155,5 @@ GxsChannelDialog GroupTreeWidget QTreeWidget#treeWidget::item{
RSTextBrowser, MimeTextEdit
{
/*qproperty-textColorQuote: rgb(125, 125, 255);*/
qproperty-textColorQuotes: ColorList(#0000ff #00ff00 #00ffff #ff0000 #ff00ff #ffff00 #ffffff);
qproperty-textColorQuotes: ColorList(#789922 #039bd5 #800000 #800080 #008080 #b10dc9 #85144b #3d9970);
}

View File

@ -60,6 +60,9 @@ QWidget
border-image: none;
outline: 0;
}
QTreeView::item, QTreeWidget::item, QListWidget::item{
color: silver;
}
QWidget:item:hover
{
@ -1299,7 +1302,7 @@ WireGroupItem QFrame#frame{
RSTextBrowser, MimeTextEdit
{
/*qproperty-textColorQuote: rgb(125, 125, 255);*/
qproperty-textColorQuotes: ColorList(#0000ff #00ff00 #00ffff #ff0000 #ff00ff #ffff00 #ffffff);
qproperty-textColorQuotes: ColorList(#789922 #039bd5 #800000 #800080 #008080 #b10dc9 #85144b #3d9970);
}
ChatWidget QFrame#pluginTitleFrame

View File

@ -345,12 +345,16 @@ openbsd-* {
LIBS *= -rdynamic
}
################################### COMMON stuff ##################################
wikipoos {
PRE_TARGETDEPS *= $$OUT_PWD/../../supportlibs/pegmarkdown/lib/libpegmarkdown.a
LIBS *= $$OUT_PWD/../../supportlibs/pegmarkdown/lib/libpegmarkdown.a
LIBS *= -lglib-2.0
}
################################### HEADERS & SOURCES #############################
# Tor controller
HEADERS += TorControl/AddOnionCommand.h \

View File

@ -29,6 +29,8 @@ QT -= gui
SOURCES += retroshare-service.cc
################################# Linux ##########################################
android-* {
QT += androidextras
@ -56,11 +58,14 @@ appimage {
INSTALLS += desktop_files
}
unix {
target.path = "$${RS_BIN_DIR}"
INSTALLS += target
}
################################# MacOSX ##########################################
macx {
# ENABLE THIS OPTION FOR Univeral Binary BUILD.
#CONFIG += ppc x86
@ -81,6 +86,8 @@ macx {
INCLUDEPATH += . $$INC_DIR
}
################################# Windows ##########################################
win32-g++|win32-clang-g++ {
CONFIG(debug, debug|release) {
# show console output
@ -130,3 +137,6 @@ win32-g++|win32-clang-g++ {
QMAKE_PRE_LINK = $(CHK_DIR_EXISTS) lib || $(MKDIR) lib
}
}
################################### COMMON stuff ##################################

View File

@ -140,6 +140,11 @@ rs_macos10.15:CONFIG -= rs_macos10.11
CONFIG *= no_rs_jsonapi
rs_jsonapi:CONFIG -= no_rs_jsonapi
# Disable i2p BOB support for automatically setting up an i2p tunnel for RS
# "CONFIG+=no_rs_bob"
CONFIG *= rs_bob
no_rs_bob:CONFIG -= rs_bob
# To enable channel indexing append the following assignation to qmake command
# line "CONFIG+=rs_deep_channels_index"
CONFIG *= no_rs_deep_channels_index
@ -550,6 +555,10 @@ rs_webui {
DEFINES *= RS_WEBUI
}
rs_bob {
DEFINES *= RS_USE_I2P_BOB
}
rs_deep_channels_index:DEFINES *= RS_DEEP_CHANNEL_INDEX
rs_deep_files_index:DEFINES *= RS_DEEP_FILES_INDEX