diff --git a/libretroshare/src/pqi/Makefile b/libretroshare/src/pqi/Makefile index 37e0db158..b61b9f135 100644 --- a/libretroshare/src/pqi/Makefile +++ b/libretroshare/src/pqi/Makefile @@ -34,10 +34,10 @@ RSOBJ = $(BASE_OBJ) $(LOOP_OBJ) \ $(GRP_OBJ) \ $(OTHER_OBJ) -TESTOBJ = xpgp_id.o net_test.o dht_test.o +TESTOBJ = xpgp_id.o net_test.o dht_test.o net_test1.o #conn_test.o -TESTS = xpgp_id net_test dht_test +TESTS = xpgp_id net_test dht_test net_test1 #conn_test @@ -55,6 +55,9 @@ conn_test: conn_test.o net_test: net_test.o $(CC) $(CFLAGS) -o net_test net_test.o $(LIBS) +net_test1: net_test1.o + $(CC) $(CFLAGS) -o net_test1 net_test1.o $(LIBS) + ############################################################### include $(RS_TOP_DIR)/scripts/rules.mk ############################################################### diff --git a/libretroshare/src/pqi/p3connmgr.cc b/libretroshare/src/pqi/p3connmgr.cc index cdd049942..2611cf0d3 100644 --- a/libretroshare/src/pqi/p3connmgr.cc +++ b/libretroshare/src/pqi/p3connmgr.cc @@ -45,7 +45,7 @@ const uint32_t RS_STUN_DONE = 0x0002; const uint32_t RS_STUN_LIST_MIN = 100; const uint32_t RS_STUN_FOUND_MIN = 10; -const uint32_t MAX_UPNP_INIT = 30; /* seconds UPnP timeout */ +const uint32_t MAX_UPNP_INIT = 10; /* seconds UPnP timeout */ /**** * #define CONN_DEBUG 1 @@ -300,6 +300,21 @@ void p3ConnectMgr::tick() } +bool p3ConnectMgr::shutdown() /* blocking shutdown call */ +{ + connMtx.lock(); /* LOCK MUTEX */ + + bool upnpActive = ownState.netMode & RS_NET_MODE_UPNP; + + connMtx.unlock(); /* UNLOCK MUTEX */ + + if (upnpActive) + { + mUpnpMgr->shutdownUPnP(); + } + return true; +} + void p3ConnectMgr::statusTick() { diff --git a/libretroshare/src/pqi/p3connmgr.h b/libretroshare/src/pqi/p3connmgr.h index 0271f3476..724ff605b 100644 --- a/libretroshare/src/pqi/p3connmgr.h +++ b/libretroshare/src/pqi/p3connmgr.h @@ -165,6 +165,8 @@ void setUpnpMgr(p3UpnpMgr *umgr) { mUpnpMgr = umgr; } bool checkNetAddress(); /* check our address is sensible */ /*************** External Control ****************/ +bool shutdown(); /* blocking shutdown call */ + bool retryConnect(std::string id); bool getUPnPState(); diff --git a/libretroshare/src/pqi/p3upnpmgr.h b/libretroshare/src/pqi/p3upnpmgr.h index 05a98cda7..033ae2c35 100644 --- a/libretroshare/src/pqi/p3upnpmgr.h +++ b/libretroshare/src/pqi/p3upnpmgr.h @@ -31,15 +31,16 @@ #include "util/rsthreads.h" #include "pqi/pqinetwork.h" -class p3UpnpMgr: public RsThread +class p3UpnpMgr { public: virtual ~p3UpnpMgr() { return; } /* External Interface */ -virtual void enableUPnP(bool on) = 0; -virtual void shutdownUPnP() = 0; +virtual void enableUPnP(bool on) = 0; /* launches thread to start it up */ +virtual void shutdownUPnP() = 0; /* blocking shutdown call */ +virtual void restartUPnP() = 0; /* must be called if ports change */ virtual bool getUPnPEnabled() = 0; virtual bool getUPnPActive() = 0; diff --git a/libretroshare/src/rsiface/rsforums.h b/libretroshare/src/rsiface/rsforums.h new file mode 100644 index 000000000..4fa85790c --- /dev/null +++ b/libretroshare/src/rsiface/rsforums.h @@ -0,0 +1,120 @@ +#ifndef RS_FORUM_GUI_INTERFACE_H +#define RS_FORUM_GUI_INTERFACE_H + +/* + * libretroshare/src/rsiface: rsforums.h + * + * RetroShare C++ Interface. + * + * Copyright 2007-2008 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + + +#include +#include +#include + +#include "rsiface/rstypes.h" + +#define RS_FORUM_PUBLIC 0x0001 /* anyone can publish */ +#define RS_FORUM_PRIVATE 0x0002 /* anyone with key can publish */ +#define RS_FORUM_ENCRYPTED 0x0004 /* need admin key */ + +#define RS_FORUM_ADMIN 0x0100 /* anyone can publish */ +#define RS_FORUM_SUBSCRIBED 0x0200 /* anyone can publish */ + + +class ForumInfo +{ + public: + ForumInfo() {} + std::string forumId; + std::wstring forumName; + std::wstring forumDesc; + + uint32_t forumFlags; + uint32_t pop; + + time_t lastPost; +}; + +class ForumMsgInfo +{ + public: + ForumMsgInfo() {} + std::string forumId; + std::string threadId; + std::string msgId; + + unsigned int msgflags; + + std::wstring title; + std::wstring msg; + time_t ts; +}; + + +class ThreadInfoSummary +{ + public: + ThreadInfoSummary() {} + + std::string msgId; + std::string srcId; + + uint32_t msgflags; + + std::wstring title; + int count; /* file count */ + time_t ts; + +}; + +std::ostream &operator<<(std::ostream &out, const ForumInfo &info); +std::ostream &operator<<(std::ostream &out, const ThreadInfoSummary &info); +std::ostream &operator<<(std::ostream &out, const ForumMsgInfo &info); + +class RsForums; +extern RsForums *rsForums; + +class RsForums +{ + public: + + RsForums() { return; } +virtual ~RsForums() { return; } + +/****************************************/ + +virtual bool forumsChanged(std::list &forumIds) = 0; + +virtual bool getForumList(std::list &forumList) = 0; +virtual bool getForumThreadList(std::string fId, std::list &msgs) = 0; +virtual bool getForumThreadMsgList(std::string fId, std::string tId, std::list &msgs) = 0; +virtual bool getForumMessage(std::string fId, std::string mId, ForumMsgInfo &msg) = 0; + +virtual bool ForumMessageSend(ForumMsgInfo &info) = 0; + +/****************************************/ + +}; + + +#endif diff --git a/libretroshare/src/rsserver/p3face-config.cc b/libretroshare/src/rsserver/p3face-config.cc index 1cfd3bb02..764299a05 100644 --- a/libretroshare/src/rsserver/p3face-config.cc +++ b/libretroshare/src/rsserver/p3face-config.cc @@ -329,9 +329,6 @@ int RsServer::UpdateAllConfig() } - - - void RsServer::ConfigFinalSave() { /* force saving of transfers */ @@ -344,4 +341,6 @@ void RsServer::ConfigFinalSave() void RsServer::rsGlobalShutDown() { ConfigFinalSave(); // save configuration before exit + mConnMgr->shutdown(); /* Handles UPnP */ } + diff --git a/libretroshare/src/rsserver/p3face-startup.cc b/libretroshare/src/rsserver/p3face-startup.cc index 869f18da1..443e42c05 100644 --- a/libretroshare/src/rsserver/p3face-startup.cc +++ b/libretroshare/src/rsserver/p3face-startup.cc @@ -48,6 +48,7 @@ #include "services/p3gamelauncher.h" #include "services/p3ranking.h" #include "services/p3photoservice.h" +#include "services/p3forums.h" #include #include @@ -68,8 +69,10 @@ #include "pqi/p3notify.h" // HACK - moved to pqi for compilation order. -// UNCOMMENT THIS FOR UNFINISHED SERVICES +// COMMENT THIS FOR UNFINISHED SERVICES +/**** #define RS_RELEASE 1 +****/ /**************** PQI_USE_XPGP ******************/ @@ -557,6 +560,8 @@ int RsServer::StartupRetroShare(RsInit *config) CachePair cp2(photoService, photoService, CacheId(RS_SERVICE_TYPE_PHOTO, 0)); mCacheStrapper -> addCachePair(cp2); + + #else mRanking = NULL; @@ -682,7 +687,6 @@ int RsServer::StartupRetroShare(RsInit *config) /**************************************************************************/ server->StartupMonitor(); - mUpnpMgr->start(); mDhtMgr->start(); @@ -710,10 +714,12 @@ int RsServer::StartupRetroShare(RsInit *config) rsGameLauncher = gameLauncher; rsPhoto = new p3Photo(photoService); rsRanks = new p3Rank(mRanking); + rsForums = new p3Forums(); #else rsGameLauncher = NULL; rsPhoto = NULL; rsRanks = NULL; + rsForums = NULL; #endif diff --git a/libretroshare/src/services/Makefile b/libretroshare/src/services/Makefile index 4af2b0804..bae9bda70 100644 --- a/libretroshare/src/services/Makefile +++ b/libretroshare/src/services/Makefile @@ -9,7 +9,10 @@ include $(RS_TOP_DIR)/scripts/config.mk RSOBJ = p3service.o p3chatservice.o p3msgservice.o \ p3gamelauncher.o p3ranking.o p3disc.o \ - p3photoservice.o + p3photoservice.o \ + p3forums.o + +# p3distrib.o #TESTOBJ = diff --git a/libretroshare/src/services/p3distrib.cc b/libretroshare/src/services/p3distrib.cc new file mode 100644 index 000000000..6fc50e3ef --- /dev/null +++ b/libretroshare/src/services/p3distrib.cc @@ -0,0 +1,976 @@ +/* + * libretroshare/src/services: p3distrib.h + * + * 3P/PQI network interface for RetroShare. + * + * Copyright 2004-2008 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + +#include "services/p3distrib.h" +#include "pqi/pqibin.h" + + +//#include "pqi/pqiservice.h" +//#include "util/rsthreads.h" + +/* + * Group Messages.... + * + * Forums / Channels / Blogs... + * + * + * Plan. + * + * (1) First create basic structures .... algorithms. + * + * (2) integrate with Cache Source/Store for data transmission. + * (3) integrate with Serialiser for messages + * (4) bring over the final key parts from existing p3channel. + * + ***************************************************************** + * + * Group Description: + * + * Master Public/Private Key: (Admin Key) used to control + * Group Name/Description/Icon. + * Filter Lists. + * Publish Keys. + * + * Publish Keys. (multiple possible) + * Filters: blacklist or whitelist. + * TimeStore Length ??? (could make it a minimum of this and system one) + * + * Everyone gets: + * Master Public Key. + * Publish Public Keys. + * blacklist, or whitelist filter. (Only useful for Non-Anonymous groups) + * Name, Desc, + * etc. + * + * Admins get Master Private Key. + * Publishers get Publish Private Key. + * - Channels only some get publish key. + * - Forums everyone gets publish private key. + * + * Create a Signing structure for Messages in general. + * + */ + + +p3GroupDistrib::p3GroupDistrib(uint16_t subtype, + CacheStrapper *cs, CacheTransfer *cft, + std::string sourcedir, std::string storedir, + uint32_t configId, + uint32_t storePeriod, uint32_t pubPeriod) + + :CacheSource(subtype, true, cs, sourcedir), + CacheStore(subtype, true, cs, cft, storedir), + p3Config(configId), + mStorePeriod(storePeriod), + mPubPeriod(pubPeriod) +{ + /* not much yet */ + time_t now = time(NULL); + + /* set this a little in the future -> so we can + * adjust the publish point if needed + */ + + mNextPublishTime = now + mPubPeriod / 4; + + return; +} + + +void p3GroupDistrib::tick() +{ + time_t now = time(NULL); + bool toPublish; + + { + RsStackMutex stack(distribMtx); /**** STACK LOCKED MUTEX ****/ + toPublish = (now > mNextPublishTime); + } + + if (toPublish) + { + publishPendingMsgs(); + + RsStackMutex stack(distribMtx); /**** STACK LOCKED MUTEX ****/ + mNextPublishTime = now + mPubPeriod; + } +} + + +/***************************************************************************************/ +/***************************************************************************************/ + /********************** overloaded functions from Cache Store ******************/ +/***************************************************************************************/ +/***************************************************************************************/ + +int p3GroupDistrib::loadAnyCache(const CacheData &data, bool local) +{ + /* if subtype = 0 -> FileGroup, else -> FileMsgs */ + + std::string file = data.path; + file += "/"; + file += data.name; + + if (data.cid.subid == 0) + { + loadFileGroups(file, data.pid, local); + } + else + { + loadFileMsgs(file, data.cid.subid, data.pid, local); + } + return true; +} + +int p3GroupDistrib::loadCache(const CacheData &data) +{ + return loadAnyCache(data, false); +} + +bool p3GroupDistrib::loadLocalCache(const CacheData &data) +{ + return loadAnyCache(data, true); +} + + +/***************************************************************************************/ +/***************************************************************************************/ + /********************** load Cache Files ***************************************/ +/***************************************************************************************/ +/***************************************************************************************/ + + +/* No need for special treatment for 'own' groups. + * configuration should be loaded before cache files. + */ +void p3GroupDistrib::loadFileGroups(std::string filename, std::string src, bool local) +{ + /* create the serialiser to load info */ + BinInterface *bio = new BinFileInterface(filename.c_str(), BIN_FLAGS_READABLE); + pqistreamer *streamer = createStreamer(bio, src, 0); + + RsItem *item; + RsDistribGrp *newGrp; + while(NULL != (item = streamer->GetItem())) + { + if (NULL == (newGrp = dynamic_cast(item))) + { + /* wrong message type */ + delete item; + continue; + } + loadGroup(newGrp); + } + + delete streamer; + + return; +} + + +void p3GroupDistrib::loadFileMsgs(std::string filename, uint16_t cacheSubId, std::string src, bool local) +{ + time_t now = time(NULL); + time_t start = now; + time_t end = 0; + + /* create the serialiser to load msgs */ + BinInterface *bio = new BinFileInterface(filename.c_str(), BIN_FLAGS_READABLE); + pqistreamer *streamer = createStreamer(bio, src, 0); + + RsItem *item; + RsDistribMsg *newMsg; + while(NULL != (item = streamer->GetItem())) + { + if (NULL == (newMsg = dynamic_cast(item))) + { + /* wrong message type */ + delete item; + continue; + } + + if (local) + { + /* calc the range */ + if (newMsg->timestamp < start) + start = newMsg->timestamp; + if (newMsg->timestamp > end) + end = newMsg->timestamp; + } + + loadMsg(newMsg, src, local); + } + + /* Check the Hash? */ + + delete streamer; + + if (local) + { + GroupCache newCache; + + newCache.filename = filename; + newCache.cacheSubId = cacheSubId; + newCache.start = start; + newCache.end = end; + + distribMtx.lock(); /******************** LOCKED MUTEX ************/ + + mLocalCaches.push_back(newCache); + + +/******************** This probably ain't necessary *******************/ +#if 0 + /* adjust next Publish Time if needed */ + if ((end < now) && (end + mPubPeriod > mNextPublishTime)) + { + mNextPublishTime = end + mPubPeriod; + } +#endif +/******************** This probably ain't necessary *******************/ + + distribMtx.unlock(); /******************** UNLOCKED MUTEX ************/ + + } + + return; +} + + +/******************************* +******************************** +******************************** +***** COMPLETED TO HERE ****** +******************************** +******************************** +********************************/ + + +/***************************************************************************************/ +/***************************************************************************************/ + /********************** load Cache Msgs ***************************************/ +/***************************************************************************************/ +/***************************************************************************************/ + + +void p3GroupDistrib::loadGroup(RsDistribGrp *newGrp) +{ + /* load groupInfo */ + + /* look for duplicate */ + + + /* check signature */ + + /* add in */ + + /* */ +} + + +void p3GroupDistrib::loadMsg(RsDistribMsg *msg, std::string src, bool local) +{ + /****************** check the msg ******************/ + /* Do the most likely checks to fail first.... + * + * timestamp (too old) + * group (non existant) + * msg (already have it) + * + * -> then do the expensive Hash / signature checks. + */ + + distribMtx.lock(); /******************** LOCKED MUTEX ************/ + + /* check timestamp */ + time_t now = time(NULL); + time_t min = now - mStorePeriod; + time_t minPub = now - mStorePeriod / 2.0; + time_t max = now + GROUP_MAX_FWD_OFFSET; + + distribMtx.unlock(); /******************** UNLOCKED MUTEX ************/ + + if ((msg->timestamp < min) || (msg->timestamp > max)) + { + /* if outside range -> remove */ + delete msg; + return; + } + + + distribMtx.lock(); /******************** LOCKED MUTEX ************/ + + /* find group */ + std::map::iterator git; + if (mGroups.end() == (git = mGroups.find(msg->grpId))) + { + /* if not there -> remove */ + distribMtx.unlock(); /******************** UNLOCKED MUTEX ************/ + + delete msg; + return; + } + + /* check for duplicate message */ + std::map::iterator mit; + if ((git->second).msgs.end() != (git->second).msgs.find(msg->msgId)) + { + distribMtx.unlock(); /******************** UNLOCKED MUTEX ************/ + + /* if already there -> remove */ + delete msg; + return; + } + + distribMtx.unlock(); /******************** UNLOCKED MUTEX ************/ + + /* save and reset hash/signatures */ + std::string hash = msg->msgId; + std::string grpSign = msg->grpSignature; + std::string srcSign = msg->sourceSignature; + + msg->msgId = ""; + msg->grpSignature = ""; + msg->sourceSignature = ""; + + std::string computedHash = HashRsItem(msg); + + /* restore data */ + msg->msgId = hash; + msg->grpSignature = grpSign; + msg->sourceSignature = srcSign; + + if (computedHash != hash) + { + /* hash is wrong */ + delete msg; + return; + } + + /* calc group signature */ + /* if fails -> remove */ + + /* check peer signature */ + /* if !allowedAnon & anon -> remove */ + /* if !allowedUnknown & unknown -> remove */ + + /****************** check the msg ******************/ + + /* accept message */ + (git->second).msgs[msg->msgId] = msg; + + if (local) + { + /* if from local -> already published */ + /* All local loads - will also come in as Remote loads. + * but should be discarded because of duplicates + * (Local load must happen first!) + */ + //delete msg; + return; + } + + if (msg->timestamp < minPub) + { + /* outside publishing range */ + //delete msg; + return; + } + + /* else if group = subscribed | listener -> publish */ + toPublishMsg(msg); +} + + +/***************************************************************************************/ +/***************************************************************************************/ + /****************** create/mod Cache Content **********************************/ +/***************************************************************************************/ +/***************************************************************************************/ + +void p3GroupDistrib::toPublishMsg(RsDistribMsg *msg) +{ + RsStackMutex stack(distribMtx); /****** STACK MUTEX LOCKED *******/ + + mPendingPublish.push_back(msg); +} + +void p3GroupDistrib::locked_publishPendingMsgs() +{ + /* get the next message id */ + CacheData newCache; + + newCache.pid = mOwnId; + newCache.cid.type = CacheSource::getCacheType(); + newCache.cid.subid = determineCacheSubId(); // NOT fixed - should rotate. + + /* create filename */ + std::string path = CacheSource::getCacheDir(); + std::ostringstream out; + out << "grpdist-t" << CacheSource::getCacheType() << "-msgs-" << time(NULL) << ".dist"; + + std::string tmpname = out.str(); + std::string filename = path + "/" + tmpname; + + BinInterface *bio = new BinFileInterface(filename.c_str(), + BIN_FLAGS_WRITEABLE | BIN_FLAGS_HASH_DATA); + pqistreamer *streamer = createStreamer(bio, mOwnId, + BIN_FLAGS_NO_DELETE); + + RsStackMutex stack(distribMtx); /****** STACK MUTEX LOCKED *******/ + + + std::list::iterator it; + for(it = mPendingPublish.begin(); it != mPendingPublish.end(); it++) + { + streamer->SendItem(*it); /* doesnt delete it */ + } + + /* cleanup */ + mPendingPublish.clear(); + delete streamer; + + /* Extract File Information from pqistreamer */ + newCache.path = path; + newCache.name = tmpname; + + newCache.hash = bio->gethash(); + newCache.size = bio->bytecount(); + newCache.recvd = time(NULL); + + /* push file to CacheSource */ + refreshCache(newCache); + + /* flag to store config (saying we've published messages) */ + IndicateConfigChanged(); /**** INDICATE CONFIG CHANGED! *****/ +} + + +void p3GroupDistrib::publishDistribGroups() +{ + /* set subid = 0 */ + CacheData newCache; + + newCache.pid = mOwnId; + newCache.cid.type = CacheSource::getCacheType(); + newCache.cid.subid = 0; + + /* create filename */ + std::string path = CacheSource::getCacheDir(); + std::ostringstream out; + out << "grpdist-t" << CacheSource::getCacheType() << "-grps-" << time(NULL) << ".dist"; + + std::string tmpname = out.str(); + std::string filename = path + "/" + tmpname; + + BinInterface *bio = new BinFileInterface(filename.c_str(), + BIN_FLAGS_WRITEABLE | BIN_FLAGS_HASH_DATA); + pqistreamer *streamer = createStreamer(bio, mOwnId, 0); + + RsStackMutex stack(distribMtx); /****** STACK MUTEX LOCKED *******/ + + + /* Iterate through all the Groups */ + std::map::iterator it; + for(it = mGroups.begin(); it != mGroups.end(); it++) + { + /* if subscribed or listener -> do stuff */ + + /* extract public info to RsDistribGrp */ + RsDistribGrp *grp = new RsDistribGrp(); + + + /* store in Cache File */ + streamer->SendItem(grp); /* deletes it */ + } + + /* Extract File Information from pqistreamer */ + newCache.path = path; + newCache.name = tmpname; + + newCache.hash = bio->gethash(); + newCache.size = bio->bytecount(); + newCache.recvd = time(NULL); + + /* cleanup */ + delete streamer; + + /* push file to CacheSource */ + refreshCache(newCache); +} + + + /* clearing old data */ +void p3GroupDistrib::clear_local_caches(time_t now) +{ + RsStackMutex stack(distribMtx); /****** STACK MUTEX LOCKED *******/ + + time_t cutoff = now - mStorePeriod; + std::list::iterator it; + for(it = mLocalCaches.begin(); it != mLocalCaches.end();) + { + if (it->end < cutoff) + { + /* Call to CacheSource Function */ + CacheId cid(CacheSource::getCacheType(), it->cacheSubId); + clearCache(cid); + it = mLocalCaches.erase(it); + } + else + { + it++; + } + } +} + + + +/***************************************************************************************/ +/***************************************************************************************/ + /********************** Access Content ***************************************/ +/***************************************************************************************/ +/***************************************************************************************/ + + +/* get Group Lists */ +bool p3GroupDistrib::getAllGroupList(std::list &grpids) +{ + RsStackMutex stack(distribMtx); /************* STACK MUTEX ************/ + std::map::iterator git; + for(git = mGroups.begin(); git != mGroups.end(); git++) + { + grpids.push_back(git->first); + } + return true; +} + +bool p3GroupDistrib::getSubscribedGroupList(std::list &grpids) +{ + RsStackMutex stack(distribMtx); /************* STACK MUTEX ************/ + std::map::iterator git; + for(git = mGroups.begin(); git != mGroups.end(); git++) + { + if (git->second.flags & RS_GRPDISTRIB_SUBSCRIBED) + { + grpids.push_back(git->first); + } + } + return true; +} + +bool p3GroupDistrib::getPublishGroupList(std::list &grpids) +{ + RsStackMutex stack(distribMtx); /************* STACK MUTEX ************/ + std::map::iterator git; + for(git = mGroups.begin(); git != mGroups.end(); git++) + { + if (git->second.flags & RS_GRPDISTRIB_PUBLISH) + { + grpids.push_back(git->first); + } + } + return true; +} + +bool p3GroupDistrib::getPopularGroupList(uint32_t popMin, uint32_t popMax, std::list &grpids) +{ + RsStackMutex stack(distribMtx); /************* STACK MUTEX ************/ + std::map::iterator git; + for(git = mGroups.begin(); git != mGroups.end(); git++) + { + if ((git->second.pop >= popMin) && + (git->second.pop <= popMax)) + { + grpids.push_back(git->first); + } + } + return true; +} + + +/* get Msg Lists */ +bool p3GroupDistrib::getAllMsgList(std::string grpId, std::list &msgIds) +{ + RsStackMutex stack(distribMtx); /************* STACK MUTEX ************/ + std::map::iterator git; + if (mGroups.end() == (git = mGroups.find(grpId))) + { + return false; + } + + std::map::iterator mit; + std::map msgs; + + for(mit = git->second.msgs.begin(); mit != git->second.msgs.end(); mit++) + { + msgIds.push_back(mit->first); + } + return true; +} + +bool p3GroupDistrib::getTimePeriodMsgList(std::string grpId, uint32_t timeMin, + uint32_t timeMax, std::list &msgIds) +{ + RsStackMutex stack(distribMtx); /************* STACK MUTEX ************/ + std::map::iterator git; + if (mGroups.end() == (git = mGroups.find(grpId))) + { + return false; + } + + std::map::iterator mit; + + for(mit = git->second.msgs.begin(); mit != git->second.msgs.end(); mit++) + { + if ((mit->second->timestamp >= timeMin) && + (mit->second->timestamp <= timeMax)) + { + msgIds.push_back(mit->first); + } + } + return true; +} + + +GroupInfo *p3GroupDistrib::locked_getGroupInfo(std::string grpId) +{ + /************* ALREADY LOCKED ************/ + std::map::iterator git; + if (mGroups.end() == (git = mGroups.find(grpId))) + { + return NULL; + } + return &(git->second); +} + + +RsDistribMsg *p3GroupDistrib::locked_getGroupMsg(std::string grpId, std::string msgId) +{ + /************* ALREADY LOCKED ************/ + std::map::iterator git; + if (mGroups.end() == (git = mGroups.find(grpId))) + { + return NULL; + } + + std::map::iterator mit; + if (git->second.msgs.end() == (mit = git->second.msgs.find(msgId))) + { + return NULL; + } + + return mit->second; +} + + +/**** These must be created in derived classes ****/ + +#if 0 + +/* get Group Details */ +bool p3GroupDistrib::getGroupDetails(std::string grpId, RsExternalDistribGroup &grp) +{ + RsStackMutex stack(distribMtx); /************* STACK MUTEX ************/ + std::map::iterator git; + if (mGroups.end() == (git = mGroups.find(grpId))) + { + return false; + } + + /* Fill in details */ + + return true; +} + +/* get Msg */ +bool p3GroupDistrib::getGroupMsgDetails(std::string grpId, std::string msgId, RsExternalDistribMsg &msg) +{ + RsStackMutex stack(distribMtx); /************* STACK MUTEX ************/ + std::map::iterator git; + if (mGroups.end() == (git = mGroups.find(grpId))) + { + return false; + } + + std::map::iterator mit; + if (git->second.msgs.end() == (mit = git->second.msgs.find(msgId))) + { + return false; + } + + /* Fill in the message details */ + + + return true; +} + +#endif + + +/************************************* p3Config *************************************/ + +RsSerialiser *p3GroupDistrib::setupSerialiser() +{ + RsSerialiser *rss = new RsSerialiser(); + + rss->addSerialType(new RsSerialDistrib()); + rss->addSerialType(new RsConfigDistrib()); + + return rss; +} + +std::list p3GroupDistrib::saveList(bool &cleanup) +{ + std::list saveData; + + /* store private information for OUR lists */ + /* store information on subscribed lists */ + /* store messages for pending Publication */ + + return saveData; +} + +bool p3GroupDistrib::loadList(std::list load) +{ + std::list::iterator lit; + for(lit = load.begin(); lit != load.end(); lit++) + { + /* decide what type it is */ + } + return true; +} + +/************************************* p3Config *************************************/ + +pqistreamer *p3GroupDistrib::createStreamer(BinInterface *bio, std::string src, uint32_t bioflags) +{ + RsSerialiser *rsSerialiser = new RsSerialiser(); + RsSerialType *serialType = new RsSerialDistrib(); /* TODO */ + + rsSerialiser->addSerialType(serialType); + + pqistreamer *streamer = new pqistreamer(rsSerialiser, src, bio, bioflags); + + return streamer; +} + + +std::string HashRsItem(RsItem *item) +{ + /* calc/check hash (of serialised data) */ + RsSerialType *serial = new RsSerialDistrib(); + + uint32_t size = serial->size(item); + RsRawItem *ri = new RsRawItem(0, size); + serial->serialise(item, ri->getRawData(), &size); + + pqihash hash; + std::string computedHash; + + hash.addData(ri->getRawData(), size); + hash.Complete(computedHash); + + delete ri; + delete serial; + + return computedHash; +} + + + +/***************************************************************************************/ +/***************************************************************************************/ + /********************** Create Content ***************************************/ +/***************************************************************************************/ +/***************************************************************************************/ + +std::string p3GroupDistrib::createGroup(std::string name, uint32_t flags) +{ + /* Create a Group */ + GroupInfo grpInfo; + std::string grpId; + +#ifdef GROUP_SIGNATURES + + /* Create Key Set (Admin) */ + EVP_PKEY *key_admin = EVP_PKEY_new(); + mAuthMgr->generateKeyPair(key_admin, 0); + + /* extract AdminKey Id -> groupId */ + grpId = mAuthMgr->getKeyId(key_admin); + + /* setup GroupInfo */ + grpInfo.adminKey = key_admin; + +#else + grpInfo.id = generateRandomId(); +#endif + + grpInfo.id = grpId; + grpInfo.flags = flags; + grpInfo.name = name; + + /* generate a set of keys */ + + /* generate RsDistribGrp */ + + /* sign Grp (with date) */ + + /* store new GroupInfo */ + + return grpId; +} + +std::string p3GroupDistrib::addPublishKey(std::string grpId, uint32_t keyflags, time_t startDate, time_t endDate) +{ + /* Find the Group */ + GroupInfo *grpInfo = locked_getGroupInfo(grpId); + std::string keyId; + + if (!grpInfo) + { + return keyId; + } + + /* if we don't have the admin key -> then we cannot add a key */ + if (!(grpInfo->grpFlags & RS_GRPDISTRIB_ADMIN_KEY)) + { + return keyId; + } + + /* Create Key Set (Publish) */ + EVP_PKEY *key_publish = EVP_PKEY_new(); + mAuthMgr->generateKeyPair(key_publish, 0); + + /* extract Key Id -> keyId */ + keyId = mAuthMgr->getKeyId(key_publish); + + /* setup RsKey */ + RsKey *publishKey = new RsKey(); + publishKey -> key = key_publish; + publishKey -> keyId = keyId; + publishKey -> startDate = startDate; + publishKey -> endDate = endDate; + + /* setup data packet for signing */ + + + /* sign key with Admin Key */ + publishKey -> adminSignature = ...; + + + grpInfo.publishKeys.push_back(publishKey); + + return keyId; +} + + + + + +int p3channel::signRsKey(RsKey *pubkey, EVP_PKEY *signKey, std::string &signature) +{ + /* + + + + + + // sslroot will generate the pair... + // we need to split it into an pub/private. + + EVP_PKEY *keypair = EVP_PKEY_new(); + EVP_PKEY *pubkey = EVP_PKEY_new(); + + mAuthMgr->generateKeyPair(keypair, 0); + + RSA *rsa1 = EVP_PKEY_get1_RSA(keypair); + RSA *rsa2 = RSAPublicKey_dup(rsa1); + + { + std::ostringstream out; + out << "p3channel::generateRandomKeys()" << std::endl; + out << "Rsa1: " << (void *) rsa1 << " & Rsa2: "; + out << (void *) rsa2 << std::endl; + + pqioutput(PQL_DEBUG_BASIC, pqichannelzone, out.str()); + } + + EVP_PKEY_assign_RSA(pubkey, rsa1); + RSA_free(rsa1); // decrement ref count! + + priv -> setKey(keypair); + pub -> setKey(pubkey); + + { + std::ostringstream out; + out << "p3channel::generateRandomKey(): "; + priv -> print(out); + pqioutput(PQL_DEBUG_BASIC, pqichannelzone, out.str()); + } + return 1; + } + + +void p3GroupDistrib::publishMsg(RsDistribMsg *msg, bool personalSign) +{ + /* extract grpId */ + std::string grpId = msg->grpId; + + /* ensure Group exists */ + + /* hash message */ + + /* sign message */ + + /* personal signature? */ + + /* Message now Complete */ + + /* Insert in Group */ + + /* add to PublishPending */ + + /* done */ + return; +} + + + +#if 0 + +/* Modify Group */ +std::string p3GroupDistrib::modGroupDescription(std::string grpId, std::string description) +{ + return; +} + +std::string p3GroupDistrib::modGroupIcon(std::string grpId, PIXMAP icon) +{ + return; +} + +#endif + diff --git a/libretroshare/src/services/p3distrib.h b/libretroshare/src/services/p3distrib.h new file mode 100644 index 000000000..c499e3d6a --- /dev/null +++ b/libretroshare/src/services/p3distrib.h @@ -0,0 +1,375 @@ +/* + * libretroshare/src/services: p3distrib.h + * + * 3P/PQI network interface for RetroShare. + * + * Copyright 2004-2008 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + +#ifndef P3_GENERIC_DISTRIB_HEADER +#define P3_GENERIC_DISTRIB_HEADER + +#include "pqi/pqi.h" +#include "pqi/pqistreamer.h" +#include "pqi/p3cfgmgr.h" +#include "services/p3service.h" +#include "dbase/cachestrapper.h" + +//#include "util/rsthreads.h" + + +/* + * Group Messages.... + * + * Forums / Channels / Blogs... + * + * + * Plan. + * + * (1) First create basic structures .... algorithms. + * + * (2) integrate with Cache Source/Store for data transmission. + * (3) integrate with Serialiser for messages + * (4) bring over the final key parts from existing p3channel. + * + ***************************************************************** + * + * Group Description: + * + * Master Public/Private Key: (Admin Key) used to control + * Group Name/Description/Icon. + * Filter Lists. + * Publish Keys. + * + * Publish Keys. (multiple possible) + * Filters: blacklist or whitelist. + * TimeStore Length ??? (could make it a minimum of this and system one) + * + * Everyone gets: + * Master Public Key. + * Publish Public Keys. + * blacklist, or whitelist filter. (Only useful for Non-Anonymous groups) + * Name, Desc, + * etc. + * + * Admins get Master Private Key. + * Publishers get Publish Private Key. + * - Channels only some get publish key. + * - Forums everyone gets publish private key. + * + * Create a Signing structure for Messages in general. + * + */ + +/* Our Mode for the Group */ +const uint32_t RS_GRPDISTRIB_SUBSCRIBED = 0x0001; +const uint32_t RS_GRPDISTRIB_PUBLISH = 0x0002; + + + +/* Group Type */ +const uint32_t RS_DISTRIB_PRIVATE = 0x0001; /* retain Private Key ( Default ) */ +const uint32_t RS_DISTRIB_PUBLIC = 0x0002; /* share All Keys */ +const uint32_t RS_DISTRIB_ENCRYPTED = 0x0004; /* encrypt Msgs */ + +class RsSignature +{ + public: + + uint32_t type; /* MASTER, PUBLISH, PERSONAL */ + std::string signerId; + std::string signature; +}; + +class RsAuthMsg +{ + public: + + RsItem *msg; + std::string hash; + std::map signs; +}; + + +class RsKey +{ + public: + + uint32_t type; /* PUBLIC, PRIVATE */ + uint32_t type2; /* MASTER, PUBLISH, PERSONAL (not sent) */ + + EVP_PKEY *key; +}; + + +const uint32_t GROUP_MAX_FWD_OFFSET = (60 * 60 * 24 * 2); /* 2 Days */ + +/************* The Messages that are serialised ****************/ +class RsDistribMsg: public RsItem +{ + public: + RsDistribMsg(); //uint16_t type); + +virtual void clear(); +virtual std::ostream& print(std::ostream&, uint16_t); + + std::string grpId; + std::string headId; /* head of the thread */ + std::string parentId; /* parent id */ + time_t timestamp; + + /* This data is not Hashed (set to zero - before hash calced) */ + std::string msgId; /* SHA1 Hash */ + std::string grpSignature; /* sign of msgId */ + std::string sourceSignature; /* sign of msgId */ + +}; + +class RsDistribGrp: public RsItem +{ + public: + RsDistribGrp(); //uint16_t type); + +virtual void clear(); +virtual std::ostream& print(std::ostream&, uint16_t); + + RsKey rsKey; +}; + +class RsConfigDistrib: public RsSerialType +{ + public: + + RsConfigDistrib(); + +}; + +class RsSerialDistrib: public RsSerialType +{ + public: + + RsSerialDistrib(); + +}; + + + +/************* The Messages that are serialised ****************/ + +//class PIXMAP; + +class GroupInfo +{ + public: + + std::string grpId; + std::string grpName; + std::string grpDesc; + + std::string category; + //PIXMAP *GroupIcon; + + //RSA_KEY privateKey; + //RSA_KEY publicKey; + + bool publisher, allowAnon, allowUnknown; + bool subscribed, listener; + + uint32_t type; + uint32_t pop; + uint32_t flags; + + std::list sources; + + std::map msgs; +}; + +class GroupCache +{ + public: + + std::string filename; + time_t start, end; + uint16_t cacheSubId; +}; + + +class p3GroupDistrib: public CacheSource, public CacheStore, public p3Config +{ + public: + + p3GroupDistrib(uint16_t subtype, + CacheStrapper *cs, CacheTransfer *cft, + std::string sourcedir, std::string storedir, + uint32_t configId, + uint32_t storePeriod, uint32_t pubPeriod); + + +/***************************************************************************************/ +/******************************* CACHE SOURCE / STORE Interface ************************/ +/***************************************************************************************/ +/* TO FINISH */ + + public: +virtual bool loadLocalCache(const CacheData &data); /* overloaded from Cache Source */ +virtual int loadCache(const CacheData &data); /* overloaded from Cache Store */ + + private: + /* top level load */ +int loadAnyCache(const CacheData &data, bool local); + + /* load cache files */ +void loadFileGroups(std::string filename, std::string src, bool local); +void loadFileMsgs(std::string filename, uint16_t cacheSubId, std::string src, bool local); + + /* load cache msgs */ +void loadMsg(RsDistribMsg *msg, std::string src, bool local); +void loadGroup(RsDistribGrp *newGrp); + +/***************************************************************************************/ +/***************************************************************************************/ + +/***************************************************************************************/ +/**************************** Create Content *******************************************/ +/***************************************************************************************/ +/* TO FINISH */ + + public: +std::string createGroup(std::string name, uint32_t flags); +//std::string modGroupDescription(std::string grpId, std::string discription); +//std::string modGroupIcon(std::string grpId, PIXMAP *icon); + +void publishMsg(RsDistribMsg *msg, bool personalSign); + +/***************************************************************************************/ +/***************************************************************************************/ + +/***************************************************************************************/ +/****************************** Access Content ***************************************/ +/***************************************************************************************/ + public: + /* get Group Lists */ +bool getAllGroupList(std::list &grpids); +bool getSubscribedGroupList(std::list &grpids); +bool getPublishGroupList(std::list &grpids); +bool getPopularGroupList(uint32_t popMin, uint32_t popMax, std::list &grpids); + + + /* get Msg Lists */ +bool getAllMsgList(std::string grpId, std::list &msgIds); +bool getTimePeriodMsgList(std::string grpId, uint32_t timeMin, + uint32_t timeMax, std::list &msgIds); + +RsDistribMsg *locked_getGroupMsg(std::string grpId, std::string msgId); + +/* TO FINISH DEFINITIONS */ + + /* get Details */ +//bool getGroupDetails(std::string grpId, RsExternalDistribGroup &grp); +//bool getGroupMsgDetails(std::string grpId, std::string msgId, RsExternalDistribMsg &msg); + + /* Filter Messages */ + +/***************************************************************************************/ +/***************************************************************************************/ + +/***************************************************************************************/ +/********************************* p3Config ********************************************/ +/***************************************************************************************/ +/* TO FINISH */ + + protected: + +virtual RsSerialiser *setupSerialiser(); +virtual std::list saveList(bool &cleanup); +virtual bool loadList(std::list load); + +/***************************************************************************************/ +/***************************************************************************************/ +/* TO FINISH */ + + + public: +void tick(); + +/***************************************************************************************/ +/**************************** Publish Content ******************************************/ +/***************************************************************************************/ +/* TO FINISH */ + protected: + + /* create/mod cache content */ +void toPublishMsg(RsDistribMsg *msg); +void publishPendingMsgs(); +void publishDistribGroups(); +void clear_local_caches(time_t now); + +void locked_publishPendingMsgs(); +uint16_t determineCacheSubId(); + + +/***************************************************************************************/ +/***************************************************************************************/ + +/***************************************************************************************/ +/***************************** Utility Functions ***************************************/ +/***************************************************************************************/ +/* TO FINISH */ + /* utilities */ +pqistreamer *createStreamer(BinInterface *bio, std::string src, uint32_t bioflags); +std::string HashRsItem(const RsItem *item); + +/***************************************************************************************/ +/***************************************************************************************/ + + /* key cache functions - we use .... (not overloaded) + */ + + private: + + /* storage */ + + RsMutex distribMtx; /* Protects All Data Below */ + + std::string mOwnId; + std::list mLocalCaches; + std::map mGroups; + uint32_t mStorePeriod, mPubPeriod; + time_t mNextPublishTime; + + std::list mPendingPublish; +}; + + +/***************************************************************************************/ +/***************************************************************************************/ +/* + * Structure of the Storage: + * + * map GroupInfo> + * + * + * + * + */ +/***************************************************************************************/ +/***************************************************************************************/ + +#endif // P3_GENERIC_DISTRIB_HEADER diff --git a/libretroshare/src/services/p3forums.cc b/libretroshare/src/services/p3forums.cc new file mode 100644 index 000000000..96d4c9c20 --- /dev/null +++ b/libretroshare/src/services/p3forums.cc @@ -0,0 +1,216 @@ +/* + * libretroshare/src/services: rsforums.cc + * + * RetroShare C++ Interface. + * + * Copyright 2007-2008 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + +#include "services/p3forums.h" + +std::ostream &operator<<(std::ostream &out, const ForumInfo &info) +{ + std::string name(info.forumName.begin(), info.forumName.end()); + std::string desc(info.forumDesc.begin(), info.forumDesc.end()); + + out << "ForumInfo:"; + out << std::endl; + out << "ForumId: " << info.forumId << std::endl; + out << "ForumName: " << name << std::endl; + out << "ForumDesc: " << desc << std::endl; + out << "ForumFlags: " << info.forumFlags << std::endl; + out << "Pop: " << info.pop << std::endl; + out << "LastPost: " << info.lastPost << std::endl; + + return out; +} + +std::ostream &operator<<(std::ostream &out, const ThreadInfoSummary &info) +{ + out << "ThreadInfoSummary:"; + out << std::endl; + //out << "ForumId: " << forumId << std::endl; + //out << "ThreadId: " << threadId << std::endl; + + return out; +} + +std::ostream &operator<<(std::ostream &out, const ForumMsgInfo &info) +{ + out << "ForumMsgInfo:"; + out << std::endl; + //out << "ForumId: " << forumId << std::endl; + //out << "ThreadId: " << threadId << std::endl; + + return out; +} + + +RsForums *rsForums = NULL; + +p3Forums::p3Forums() + :mForumsChanged(false) +{ + loadDummyData(); + return; +} + +p3Forums::~p3Forums() +{ + return; +} + +/****************************************/ + +bool p3Forums::forumsChanged(std::list &forumIds) +{ + bool changed = mForumsChanged; + mForumsChanged = false; + return changed; +} + + +bool p3Forums::getForumList(std::list &forumList) +{ + std::list::iterator it; + for(it = mForums.begin(); it != mForums.end(); it++) + { + forumList.push_back(*it); + } + return true; +} + +bool p3Forums::getForumThreadList(std::string fId, std::list &msgs) +{ + return true; +} + +bool p3Forums::getForumThreadMsgList(std::string fId, std::string tId, std::list &msgs) +{ + return true; +} + +bool p3Forums::getForumMessage(std::string fId, std::string mId, ForumMsgInfo &msg) +{ + return true; +} + +bool p3Forums::ForumMessageSend(ForumMsgInfo &info) +{ + return true; +} + + +/****************************************/ + +void p3Forums::loadDummyData() +{ + ForumInfo fi; + time_t now = time(NULL); + + fi.forumId = "FID1234"; + fi.forumName = L"Forum 1"; + fi.forumDesc = L"Forum 1"; + fi.forumFlags = RS_FORUM_ADMIN; + fi.pop = 2; + fi.lastPost = now - 123; + + mForums.push_back(fi); + + fi.forumId = "FID2345"; + fi.forumName = L"Forum 2"; + fi.forumDesc = L"Forum 2"; + fi.forumFlags = RS_FORUM_SUBSCRIBED; + fi.pop = 3; + fi.lastPost = now - 1234; + + mForums.push_back(fi); + + fi.forumId = "FID3456"; + fi.forumName = L"Forum 3"; + fi.forumDesc = L"Forum 3"; + fi.forumFlags = 0; + fi.pop = 3; + fi.lastPost = now - 1234; + + mForums.push_back(fi); + + fi.forumId = "FID4567"; + fi.forumName = L"Forum 4"; + fi.forumDesc = L"Forum 4"; + fi.forumFlags = 0; + fi.pop = 5; + fi.lastPost = now - 1234; + + mForums.push_back(fi); + fi.forumId = "FID5678"; + fi.forumName = L"Forum 5"; + fi.forumDesc = L"Forum 5"; + fi.forumFlags = 0; + fi.pop = 1; + fi.lastPost = now - 1234; + + mForums.push_back(fi); + fi.forumId = "FID6789"; + fi.forumName = L"Forum 6"; + fi.forumDesc = L"Forum 6"; + fi.forumFlags = 0; + fi.pop = 2; + fi.lastPost = now - 1234; + + mForums.push_back(fi); + fi.forumId = "FID7890"; + fi.forumName = L"Forum 7"; + fi.forumDesc = L"Forum 7"; + fi.forumFlags = 0; + fi.pop = 4; + fi.lastPost = now - 1234; + + mForums.push_back(fi); + fi.forumId = "FID8901"; + fi.forumName = L"Forum 8"; + fi.forumDesc = L"Forum 8"; + fi.forumFlags = 0; + fi.pop = 3; + fi.lastPost = now - 1234; + + mForums.push_back(fi); + fi.forumId = "FID9012"; + fi.forumName = L"Forum 9"; + fi.forumDesc = L"Forum 9"; + fi.forumFlags = 0; + fi.pop = 2; + fi.lastPost = now - 1234; + + mForums.push_back(fi); + + fi.forumId = "FID9123"; + fi.forumName = L"Forum 10"; + fi.forumDesc = L"Forum 10"; + fi.forumFlags = 0; + fi.pop = 1; + fi.lastPost = now - 1234; + + mForums.push_back(fi); + + mForumsChanged = true; +} + + diff --git a/libretroshare/src/services/p3forums.h b/libretroshare/src/services/p3forums.h new file mode 100644 index 000000000..230722438 --- /dev/null +++ b/libretroshare/src/services/p3forums.h @@ -0,0 +1,60 @@ +#ifndef RS_P3_FORUMS_INTERFACE_H +#define RS_P3_FORUMS_INTERFACE_H + +/* + * libretroshare/src/services: p3forums.h + * + * RetroShare C++ Interface. + * + * Copyright 2008 by Robert Fernie. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License Version 2 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems to "retroshare@lunamutt.com". + * + */ + +#include "rsiface/rsforums.h" + +class p3Forums: public RsForums +{ + public: + + p3Forums(); +virtual ~p3Forums(); + +/****************************************/ +/********* rsForums Interface ***********/ + +virtual bool forumsChanged(std::list &forumIds); + +virtual bool getForumList(std::list &forumList); +virtual bool getForumThreadList(std::string fId, std::list &msgs); +virtual bool getForumThreadMsgList(std::string fId, std::string tId, std::list &msgs); +virtual bool getForumMessage(std::string fId, std::string mId, ForumMsgInfo &msg); + +virtual bool ForumMessageSend(ForumMsgInfo &info); + +/****************************************/ + + private: + +void loadDummyData(); +std::list mForums; +bool mForumsChanged; +}; + + +#endif diff --git a/libretroshare/src/upnp/upnphandler.cc b/libretroshare/src/upnp/upnphandler.cc index fb5077c52..46ce58d3f 100644 --- a/libretroshare/src/upnp/upnphandler.cc +++ b/libretroshare/src/upnp/upnphandler.cc @@ -27,106 +27,6 @@ class uPnPConfigData #include "util/rsnet.h" - -void upnphandler::run() -{ - - /* infinite loop */ - while(1) - { - std::cerr << "UPnPHandler::Run()" << std::endl; - int allowedSleep = 30; /* check every 30 seconds */ - - /* lock it up */ - dataMtx.lock(); /* LOCK MUTEX */ - - bool shutdown = toShutdown; - int state = upnpState; - - dataMtx.unlock(); /* UNLOCK MUTEX */ - - if (shutdown) - { - return; - } - - /* do the work! */ - checkUPnPState(); - - /* check new state for sleep period */ - - dataMtx.lock(); /* LOCK MUTEX */ - - state = upnpState; - - dataMtx.unlock(); /* UNLOCK MUTEX */ - - - /* state machine */ - switch(state) - { - case RS_UPNP_S_UNINITIALISED: - case RS_UPNP_S_UNAVAILABLE: - /* failed ... try again in 30 min. */ - allowedSleep = 1800; - break; - - case RS_UPNP_S_READY: - case RS_UPNP_S_TCP_FAILED: - case RS_UPNP_S_UDP_FAILED: - case RS_UPNP_S_ACTIVE: - /* working ... normal 10 seconds */ - allowedSleep = 10; - break; - - default: - /* default??? how did it get here? */ - break; - } - - std::cerr << "UPnPHandler::Run() sleeping for:" << allowedSleep << std::endl; -/********************************** WINDOWS/UNIX SPECIFIC PART ******************/ -#ifndef WINDOWS_SYS - sleep(allowedSleep); -#else - Sleep(1000 * allowedSleep); -#endif -/********************************** WINDOWS/UNIX SPECIFIC PART ******************/ - } - return; -} - -void upnphandler::checkUPnPState() -{ - dataMtx.lock(); /* LOCK MUTEX */ - - int state = upnpState; - - dataMtx.unlock(); /* UNLOCK MUTEX */ - - /* state machine */ - switch(state) - { - case RS_UPNP_S_UNINITIALISED: - case RS_UPNP_S_UNAVAILABLE: - initUPnPState(); - break; - - case RS_UPNP_S_READY: - case RS_UPNP_S_TCP_FAILED: - case RS_UPNP_S_UDP_FAILED: - case RS_UPNP_S_ACTIVE: - printUPnPState(); - checkUPnPActive(); - updateUPnP(); - break; - - } - - return; -} - - bool upnphandler::initUPnPState() { /* allocate memory */ @@ -160,13 +60,15 @@ bool upnphandler::initUPnPState() upnp_iaddr.sin_port = htons(iport); upnpState = RS_UPNP_S_READY; + if (upnpConfig) + { + delete upnpConfig; + } upnpConfig = upcd; /* */ dataMtx.unlock(); /* UNLOCK MUTEX */ - - /* done -> READY */ return 1; @@ -240,6 +142,7 @@ bool upnphandler::checkUPnPActive() char eport2[256]; struct sockaddr_in localAddr = upnp_iaddr; + uint32_t linaddr = ntohl(localAddr.sin_addr.s_addr); snprintf(in_port1, 256, "%d", ntohs(localAddr.sin_port)); snprintf(in_port2, 256, "%d", ntohs(localAddr.sin_port)); @@ -249,6 +152,12 @@ bool upnphandler::checkUPnPActive() ((localAddr.sin_addr.s_addr >> 16) & 0xff), ((localAddr.sin_addr.s_addr >> 24) & 0xff)); + snprintf(in_addr, 256, "%d.%d.%d.%d", + ((linaddr >> 24) & 0xff), + ((linaddr >> 16) & 0xff), + ((linaddr >> 8) & 0xff), + ((linaddr >> 0) & 0xff)); + snprintf(eport1, 256, "%d", eport_curr); snprintf(eport2, 256, "%d", eport_curr); @@ -280,13 +189,63 @@ bool upnphandler::checkUPnPActive() return true; } +class upnpThreadData +{ + public: + upnphandler *handler; + bool start; + bool stop; +}; + /* Thread routines */ +extern "C" void* doSetupUPnP(void* p) +{ + upnpThreadData *data = (upnpThreadData *) p; + if ((!data) || (!data->handler)) + { + pthread_exit(NULL); + } -bool upnphandler::updateUPnP() + /* publish it! */ + if (data -> stop) + { + data->handler->shutdown_upnp(); + } + + if (data -> start) + { + data->handler->initUPnPState(); + data->handler->start_upnp(); + } + + data->handler->printUPnPState(); + + delete data; + pthread_exit(NULL); + + return NULL; +} + +bool upnphandler::background_setup_upnp(bool start, bool stop) +{ + pthread_t tid; + + /* launch thread */ + upnpThreadData *data = new upnpThreadData(); + data->handler = this; + data->start = start; + data->stop = stop; + + pthread_create(&tid, 0, &doSetupUPnP, (void *) data); + pthread_detach(tid); /* so memory is reclaimed in linux */ + + return true; +} + +bool upnphandler::start_upnp() { dataMtx.lock(); /* LOCK MUTEX */ - uPnPConfigData *config = upnpConfig; if (!((upnpState >= RS_UPNP_S_READY) && (config))) { @@ -296,10 +255,117 @@ bool upnphandler::updateUPnP() char eprot1[] = "TCP"; char eprot2[] = "UDP"; - /* if we're to unload -> unload */ - if ((toStop) && (eport_curr > 0)) + /* if we're to load -> load */ + /* select external ports */ + eport_curr = eport; + if (!eport_curr) + { + /* use local port if eport is zero */ + eport_curr = iport; + std::cerr << "Using LocalPort for extPort!"; + std::cerr << std::endl; + } + + if (!eport_curr) + { + std::cerr << "Invalid eport ... "; + std::cerr << std::endl; + return false; + } + + + /* our port */ + char in_addr[256]; + char in_port1[256]; + char in_port2[256]; + char eport1[256]; + char eport2[256]; + + upnp_iaddr.sin_port = htons(iport); + struct sockaddr_in localAddr = upnp_iaddr; + uint32_t linaddr = ntohl(localAddr.sin_addr.s_addr); + + snprintf(in_port1, 256, "%d", ntohs(localAddr.sin_port)); + snprintf(in_port2, 256, "%d", ntohs(localAddr.sin_port)); + snprintf(in_addr, 256, "%d.%d.%d.%d", + ((linaddr >> 24) & 0xff), + ((linaddr >> 16) & 0xff), + ((linaddr >> 8) & 0xff), + ((linaddr >> 0) & 0xff)); + + snprintf(eport1, 256, "%d", eport_curr); + snprintf(eport2, 256, "%d", eport_curr); + + std::cerr << "Attempting Redirection: InAddr: " << in_addr; + std::cerr << " InPort: " << in_port1; + std::cerr << " ePort: " << eport1; + std::cerr << " eProt: " << eprot1; + std::cerr << std::endl; + + if (!SetRedirectAndTest(&(config -> urls), &(config->data), + in_addr, in_port1, eport1, eprot1)) + { + upnpState = RS_UPNP_S_TCP_FAILED; + } + else if (!SetRedirectAndTest(&(config -> urls), &(config->data), + in_addr, in_port2, eport2, eprot2)) + { + upnpState = RS_UPNP_S_UDP_FAILED; + } + else + { + upnpState = RS_UPNP_S_ACTIVE; + } + + + /* now store the external address */ + char externalIPAddress[32]; + UPNP_GetExternalIPAddress(config -> urls.controlURL, + config->data.servicetype, + externalIPAddress); + + sockaddr_clear(&upnp_eaddr); + + if(externalIPAddress[0]) + { + std::cerr << "Stored External address: " << externalIPAddress; + std::cerr << ":" << eport_curr; + std::cerr << std::endl; + + inet_aton(externalIPAddress, &(upnp_eaddr.sin_addr)); + upnp_eaddr.sin_family = AF_INET; + upnp_eaddr.sin_port = htons(eport_curr); + } + else + { + std::cerr << "FAILED To get external Address"; + std::cerr << std::endl; + } + + toStart = false; + + dataMtx.unlock(); /* UNLOCK MUTEX */ + + return true; + +} + +bool upnphandler::shutdown_upnp() +{ + dataMtx.lock(); /* LOCK MUTEX */ + + uPnPConfigData *config = upnpConfig; + if (!((upnpState >= RS_UPNP_S_READY) && (config))) + { + return false; + } + + char eprot1[] = "TCP"; + char eprot2[] = "UDP"; + + /* always attempt this (unless no port number) */ + if (eport_curr > 0) { - toStop = false; char eport1[256]; char eport2[256]; @@ -323,97 +389,7 @@ bool upnphandler::updateUPnP() eport2, eprot2); upnpState = RS_UPNP_S_READY; - } - - - /* if we're to load -> load */ - if (toStart) - { - /* select external ports */ - eport_curr = eport; - if (!eport_curr) - { - /* use local port if eport is zero */ - eport_curr = iport; - std::cerr << "Using LocalPort for extPort!"; - std::cerr << std::endl; - } - - if (!eport_curr) - { - std::cerr << "Invalid eport ... "; - std::cerr << std::endl; - return false; - } - - toStart = false; - - /* our port */ - char in_addr[256]; - char in_port1[256]; - char in_port2[256]; - char eport1[256]; - char eport2[256]; - - upnp_iaddr.sin_port = htons(iport); - struct sockaddr_in localAddr = upnp_iaddr; - - snprintf(in_port1, 256, "%d", ntohs(localAddr.sin_port)); - snprintf(in_port2, 256, "%d", ntohs(localAddr.sin_port)); - snprintf(in_addr, 256, "%d.%d.%d.%d", - ((localAddr.sin_addr.s_addr >> 0) & 0xff), - ((localAddr.sin_addr.s_addr >> 8) & 0xff), - ((localAddr.sin_addr.s_addr >> 16) & 0xff), - ((localAddr.sin_addr.s_addr >> 24) & 0xff)); - - snprintf(eport1, 256, "%d", eport_curr); - snprintf(eport2, 256, "%d", eport_curr); - - std::cerr << "Attempting Redirection: InAddr: " << in_addr; - std::cerr << " InPort: " << in_port1; - std::cerr << " ePort: " << eport1; - std::cerr << " eProt: " << eprot1; - std::cerr << std::endl; - - if (!SetRedirectAndTest(&(config -> urls), &(config->data), - in_addr, in_port1, eport1, eprot1)) - { - upnpState = RS_UPNP_S_TCP_FAILED; - } - else if (!SetRedirectAndTest(&(config -> urls), &(config->data), - in_addr, in_port2, eport2, eprot2)) - { - upnpState = RS_UPNP_S_UDP_FAILED; - } - else - { - upnpState = RS_UPNP_S_ACTIVE; - } - - - /* now store the external address */ - char externalIPAddress[32]; - UPNP_GetExternalIPAddress(config -> urls.controlURL, - config->data.servicetype, - externalIPAddress); - - sockaddr_clear(&upnp_eaddr); - - if(externalIPAddress[0]) - { - std::cerr << "Stored External address: " << externalIPAddress; - std::cerr << ":" << eport_curr; - std::cerr << std::endl; - - inet_aton(externalIPAddress, &(upnp_eaddr.sin_addr)); - upnp_eaddr.sin_family = AF_INET; - upnp_eaddr.sin_port = htons(eport_curr); - } - else - { - std::cerr << "FAILED To get external Address"; - std::cerr << std::endl; - } + toStop = false; } dataMtx.unlock(); /* UNLOCK MUTEX */ @@ -422,7 +398,6 @@ bool upnphandler::updateUPnP() } - /************************ External Interface ***************************** * * @@ -430,8 +405,7 @@ bool upnphandler::updateUPnP() */ upnphandler::upnphandler() - :toShutdown(false), toEnable(false), - toStart(false), toStop(false), + :toEnable(false), toStart(false), toStop(false), eport(0), eport_curr(0), upnpState(RS_UPNP_S_UNINITIALISED), upnpConfig(NULL) @@ -462,19 +436,36 @@ void upnphandler::enableUPnP(bool active) } toEnable = active; + bool start = toStart; + dataMtx.unlock(); /*** UNLOCK MUTEX ***/ + + if (start) + { + /* make background thread to startup UPnP */ + background_setup_upnp(true, false); + } + + } + void upnphandler::shutdownUPnP() { - dataMtx.lock(); /*** LOCK MUTEX ***/ + /* blocking call to shutdown upnp */ - toShutdown = true; - - dataMtx.unlock(); /*** UNLOCK MUTEX ***/ + shutdown_upnp(); } +void upnphandler::restartUPnP() +{ + /* non-blocking call to shutdown upnp, and startup again. */ + background_setup_upnp(true, true); +} + + + bool upnphandler::getUPnPEnabled() { dataMtx.lock(); /*** LOCK MUTEX ***/ diff --git a/libretroshare/src/upnp/upnphandler.h b/libretroshare/src/upnp/upnphandler.h index fac6eb900..8696af42d 100644 --- a/libretroshare/src/upnp/upnphandler.h +++ b/libretroshare/src/upnp/upnphandler.h @@ -52,6 +52,7 @@ virtual ~upnphandler(); /* External Interface */ virtual void enableUPnP(bool active); virtual void shutdownUPnP(); +virtual void restartUPnP(); virtual bool getUPnPEnabled(); virtual bool getUPnPActive(); @@ -61,25 +62,24 @@ virtual void setExternalPort(unsigned short eport_in); virtual bool getInternalAddress(struct sockaddr_in &addr); virtual bool getExternalAddress(struct sockaddr_in &addr); - /* must run thread */ -virtual void run(); +/* Public functions - for background thread operation, + * but effectively private from rest of RS, as in derived class + */ + +bool start_upnp(); +bool shutdown_upnp(); + +bool initUPnPState(); +bool printUPnPState(); private: -bool initUPnPState(); -void checkUPnPState(); -bool printUPnPState(); - +bool background_setup_upnp(bool, bool); bool checkUPnPActive(); -bool updateUPnP(); - /* Mutex for data below */ RsMutex dataMtx; - /* requested from rs */ - bool toShutdown; /* if set shuts down the thread. */ - bool toEnable; /* overall on/off switch */ bool toStart; /* if set start forwarding */ bool toStop; /* if set stop forwarding */ diff --git a/libretroshare/src/upnp/upnptest.cc b/libretroshare/src/upnp/upnptest.cc index e4ea45457..48c5c4253 100644 --- a/libretroshare/src/upnp/upnptest.cc +++ b/libretroshare/src/upnp/upnptest.cc @@ -47,7 +47,6 @@ int main(int argc, char **argv) upnphandler upnp; - upnp.start(); upnp.setInternalPort(12122); for(int i = 0; 1; i++) @@ -62,19 +61,24 @@ int main(int argc, char **argv) #endif /********************************** WINDOWS/UNIX SPECIFIC PART ******************/ - if (i % 300 == 10) + if (i % 120 == 10) { /* start up a forward */ upnp.enableUPnP(true); } - if (i % 300 == 120) + if (i % 120 == 60) { /* shutdown a forward */ - upnp.enableUPnP(false); + upnp.restartUPnP(); } + if (i % 120 == 100) + { + /* shutdown a forward */ + upnp.shutdownUPnP(); + } } } diff --git a/libretroshare/src/upnp/upnputil.c b/libretroshare/src/upnp/upnputil.c index c90383a51..e6aba078a 100644 --- a/libretroshare/src/upnp/upnputil.c +++ b/libretroshare/src/upnp/upnputil.c @@ -142,7 +142,10 @@ bool SetRedirectAndTest(struct UPNPUrls * urls, // Unix at the moment! r = UPNP_AddPortMapping(urls->controlURL, data->servicetype, - eport, iport, iaddr, 0, leaseDuration, proto); + eport, iport, iaddr, 0, 0, proto); + +// r = UPNP_AddPortMapping(urls->controlURL, data->servicetype, +// eport, iport, iaddr, 0, leaseDuration, proto); // r = UPNP_AddPortMapping(urls->controlURL, data->servicetype, // eport, iport, iaddr, 0, proto);