Addition of next stage of new FileTransfer Code:

* Completed rough ftExtraList class (with Test Case)
 * Added data flow interface (ftData.h)
 * Added ftDataMultiplex (server + client modules).
 * Finished parts of ftcontroller / ftserver.
 * Minor Tweaks to ftTransferModules interface for compilation.
Related Changes in other parts of the code:
 * Added new Job/Queue Thread Class.
 * Added more user-friendly directory functions.
 * Added FileInfo print operator.




git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@650 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
drbob 2008-07-23 22:01:59 +00:00
parent a9bda83565
commit 79727897dd
19 changed files with 1245 additions and 106 deletions

View File

@ -7,19 +7,23 @@ RS_TOP_DIR = ..
include $(RS_TOP_DIR)/scripts/config.mk
###############################################################
RSOBJ = ftfileprovider.o ftfilecreator.o
RSOBJ = ftfileprovider.o ftfilecreator.o ftextralist.o ftdatamultiplex.o
#ftservermodule.o
TESTOBJ = ftfileprovidertest.o ftfilecreatortest.o
TESTOBJ = ftfileprovidertest.o ftfilecreatortest.o ftextralisttest.o
TESTS = ftfileprovidertest ftfilecreatortest
TESTS = ftfileprovidertest ftfilecreatortest ftextralisttest
all: librs tests
ftfilecreatortest : ftfilecreatortest.o $(RSOBJ)
$(CC) $(CFLAGS) -o ftfilecreatortest ftfilecreatortest.o $(RSOBJ) $(LIBS)
ftfilecreatortest : ftfilecreatortest.o
$(CC) $(CFLAGS) -o ftfilecreatortest ftfilecreatortest.o $(LIBS)
ftfileprovidertest : ftfileprovidertest.o $(RSOBJ)
$(CC) $(CFLAGS) -o ftfileprovidertest ftfileprovidertest.o $(RSOBJ) $(LIBS)
ftfileprovidertest : ftfileprovidertest.o
$(CC) $(CFLAGS) -o ftfileprovidertest ftfileprovidertest.o $(LIBS)
ftextralisttest : ftextralisttest.o
$(CC) $(CFLAGS) -o ftextralisttest ftextralisttest.o $(LIBS)
###############################################################
include $(RS_TOP_DIR)/scripts/rules.mk

View File

@ -0,0 +1,364 @@
/*
* libretroshare/src/ft: ftcontroller.cc
*
* File Transfer for RetroShare.
*
* 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".
*
*/
#ifndef FT_CONTROLLER_HEADER
#define FT_CONTROLLER_HEADER
/*
* ftController
*
* Top level download controller.
*
* inherits configuration (save downloading files)
* inherits pqiMonitor (knows which peers are online).
* inherits CacheTransfer (transfers cache files too)
* inherits RsThread (to control transfers)
*
*/
class ftController: public CacheTransfer, public RsThread, public pqiMonitor, public p3Config
{
public:
/* Setup */
ftController::ftController(std::string configDir);
void ftController::setFtSearch(ftSearch *search)
{
mSearch = search;
}
virtual void ftController::run()
{
/* check the queues */
}
/* Called every 10 seconds or so */
void ftController::checkDownloadQueue()
{
/* */
}
bool ftController::completeFile(std::string hash)
{
RsStackMutex stack(ctrlMutex); /******* LOCKED ********/
std::map<std::string, ftFileControl>::iterator it;
it = mDownloads.find(hash);
if (it == mDownloads.end())
{
return false;
}
/* check if finished */
if (!(it->second).mCreator->finished())
{
/* not done! */
return false;
}
ftFileControl *fc = &(it->second);
/* done - cleanup */
fc->mTransfer->done();
mClientModule->removeTransferModule(fc->mTransfer);
mServerModule->removeFileCreator(fc->mCreator);
delete fc->mTransfer;
fc->mTransfer = NULL;
delete fc->mCreator;
fc->mCreator = NULL;
fc->state = COMPLETE;
/* switch map */
mCompleted[fc->hash] = *fc;
mDownloads.erase(it);
return true;
}
/***************************************************************/
/********************** Controller Access **********************/
/***************************************************************/
bool ftController::FileRequest(std::string fname, std::string hash,
uint64_t size, std::string dest, uint32_t flags,
std::list<std::string> srcIds)
{
/* check if we have the file */
if (ftSearch->findFile(LOCAL))
{
/* have it already */
/* add in as completed transfer */
return true;
}
/* do a source search - for any extra sources */
if (ftSearch->findFile(REMOTE))
{
}
std::map<std::string, ftTransferModule *> mTransfers;
std::map<std::string, ftFileCreator *> mFileCreators;
/* add in new item for download */
std::string savepath = mDownloadPath + "/" + fname;
std::string chunker = "";
ftFileCreator *fc = new ftFileCreator(savepath, size, hash, chunker);
ftTransferModule = *tm = new ftTransferModule(fc, mClientModule);
/* add into maps */
ftFileControl ftfc(fname, size, hash, flags, fc, tm);
/* add to ClientModule */
mClientModule->addTransferModule(tm);
/* now add source peers (and their current state) */
tm->setFileSources(srcIds);
/* get current state for transfer module */
for(it = srcIds.begin(); it != srcIds.end(); it++)
{
if (mConnMgr->isOnline(*it))
{
tm->setPeer(*it, TRICKLE | ONLINE);
}
else
{
tm->setPeer(*it, OFFLINE);
}
}
/* only need to lock before to fiddle with own variables */
RsStackMutex stack(ctrlMutex); /******* LOCKED ********/
mDownloads[hash] = ftfc;
mSlowQueue.push_back(hash);
}
bool ftController::FileCancel(std::string hash);
bool ftController::FileControl(std::string hash, uint32_t flags);
bool ftController::FileClearCompleted();
/* get Details of File Transfers */
bool ftController::FileDownloads(std::list<std::string> &hashs)
{
RsStackMutex stack(ctrlMutex); /******* LOCKED ********/
std::map<std::string, ftFileControl>::iterator it;
for(it = mDownloads.begin(); it != mDownloads.end(); it++)
{
hashes.push_back(it->second.hash);
}
return true;
}
/* Directory Handling */
bool ftController::setDownloadDirectory(std::string path)
{
/* check if it exists */
if (RsDirUtil::checkCreateDirectory(path))
{
RsStackMutex stack(ctrlMutex); /******* LOCKED ********/
mDownloadPath = path;
return true;
}
return false;
}
bool ftController::setPartialsDirectory(std::string path);
{
/* check it is not a subdir of download / shared directories (BAD) - TODO */
/* check if it exists */
if (RsDirUtil::checkCreateDirectory(path))
{
RsStackMutex stack(ctrlMutex); /******* LOCKED ********/
mPartialPath = path;
/* move all existing files! */
std::map<std::string, ftFileControl>::iterator it;
for(it = mDownloads.begin(); it != mDownloads.end(); it++)
{
(it->second).mCreator->changePartialDirectory(mPartialPath);
}
return true;
}
return false;
}
std::string ftController::getDownloadDirectory()
{
RsStackMutex stack(ctrlMutex); /******* LOCKED ********/
return mDownloadPath;
}
std::string ftController::getPartialsDirectory()
{
RsStackMutex stack(ctrlMutex); /******* LOCKED ********/
return mPartialPath;
}
bool ftController::FileDetails(std::string hash, FileInfo &info)
{
RsStackMutex stack(ctrlMutex); /******* LOCKED ********/
std::map<std::string, ftFileControl>::iterator it;
it = mDownloads.find(hash);
if (it == mDownloads.end())
{
return false;
}
/* extract details */
return true;
}
/***************************************************************/
/********************** Controller Access **********************/
/***************************************************************/
/* pqiMonitor callback:
* Used to tell TransferModules new available peers
*/
void ftController::statusChange(const std::list<pqipeer> &plist)
{
RsStackMutex stack(ctrlMutex); /******* LOCKED ********/
/* add online to all downloads */
std::map<std::string, ftFileControl>::iterator it;
std::list<pqipeer>::const_iterator pit;
for(it = mDownloads.begin(); it != mDownloads.end(); it++)
{
for(pit = plist.begin(); pit != plist.end(); pit++)
{
if (pit->actions | RS_PEER_CONNECTED)
{
((it->second).tm)->setPeer(ONLINE | TRICKLE);
}
else if (pit->actions | RS_PEER_DISCONNECTED)
{
((it->second).tm)->setPeer(OFFLINE);
}
}
}
/* modify my list of peers */
for(pit = plist.begin(); pit != plist.end(); pit++)
{
if (pit->actions | RS_PEER_CONNECTED)
{
/* add in */
((it->second).tm)->setPeer(ONLINE | TRICKLE);
}
else if (pit->actions | RS_PEER_DISCONNECTED)
{
((it->second).tm)->setPeer(OFFLINE);
}
}
}
/* p3Config Interface */
protected:
virtual RsSerialiser *setupSerialiser();
virtual std::list<RsItem *> saveList(bool &cleanup);
virtual bool loadList(std::list<RsItem *> load);
private:
/* RunTime Functions */
/* pointers to other components */
ftSearch *mSearch;
RsMutex ctrlMutex;
std::list<FileDetails> incomingQueue;
std::map<std::string, FileDetails> mCompleted;
class ftFileControl
{
public:
ftFileControl(std::string fname, uint64_t size, std::string hash,
uint32_t flags, ftFileCreator *fc, ftTransferModule *tm);
std::string mName,
uint64_t mSize;
std::string mHash,
uint32_t mFlags;
ftFileCreator *mCreator;
ftTransferModule *mTransfer;
};
class ftPeerControl
{
std::string peerId;
std::map<std::string, uint32_t> priority;
uint32_t currentBandwidth;
uint32_t maxBandwidth;
};
std::map<std::string, ftFileControl> mDownloads;
/* A Bunch of Queues */
std::map<std::string, std::string> mStreamQueue;
std::map<std::string, std::string> mFastQueue;
std::list<std::string> mSlowQueue;
std::list<std::string> mTrickleQueue;
std::string mConfigPath;
std::string mDownloadPath;
std::string mPartialPath;
};
#endif

View File

@ -54,7 +54,8 @@ virtual void run();
/***************************************************************/
bool FileRequest(std::string fname, std::string hash,
uint32_t size, std::string dest, uint32_t flags);
uint64_t size, std::string dest, uint32_t flags,
std::list<std::string> sourceIds);
bool FileCancel(std::string hash);
bool FileControl(std::string hash, uint32_t flags);
@ -64,8 +65,8 @@ bool FileClearCompleted();
bool FileDownloads(std::list<std::string> &hashs);
/* Directory Handling */
void setDownloadDirectory(std::string path);
void setPartialsDirectory(std::string path);
bool setDownloadDirectory(std::string path);
bool setPartialsDirectory(std::string path);
std::string getDownloadDirectory();
std::string getPartialsDirectory();
bool FileDetails(std::string hash, FileInfo &info);

View File

@ -0,0 +1,79 @@
/*
* libretroshare/src/ft: ftdata.h
*
* File Transfer for RetroShare.
*
* 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".
*
*/
#ifndef FT_DATA_INTERFACE_HEADER
#define FT_DATA_INTERFACE_HEADER
/*
* ftData.
*
* Internal Interfaces for sending and receiving data.
* Most likely to be implemented by ftServer.
* Provided as an independent interface for testing purposes.
*
*/
#include <string>
#include <inttypes.h>
/*************** SEND INTERFACE *******************/
class ftDataSend
{
public:
virtual ~ftDataSend() { return; }
/* Client Send */
virtual bool sendDataRequest(std::string peerId, std::string hash,
uint64_t offset, uint32_t size) = 0;
/* Server Send */
virtual bool sendData(std::string peerId, std::string hash,
uint64_t offset, uint32_t size, void *data) = 0;
};
/*************** RECV INTERFACE *******************/
class ftDataRecv
{
public:
virtual ~ftDataRecv() { return; }
/* Client Recv */
virtual bool recvData(std::string peerId, std::string hash,
uint64_t offset, uint32_t size, void *data) = 0;
/* Server Recv */
virtual bool recvDataRequest(std::string peerId, std::string hash,
uint64_t offset, uint32_t size) = 0;
};
#endif

View File

@ -0,0 +1,247 @@
/*
* libretroshare/src/ft: ftdatamultiplex.h
*
* File Transfer for RetroShare.
*
* 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".
*
*/
/*
* ftDataMultiplexModule.
*
* This multiplexes the data from PQInterface to the ftTransferModules.
*/
#include "ft/ftdatamultiplex.h"
#include "ft/fttransfermodule.h"
#include "ft/ftfilecreator.h"
#include "ft/ftfileprovider.h"
#include "ft/ftsearch.h"
ftClient::ftClient(ftTransferModule *module, ftFileCreator *creator)
:mModule(module), mCreator(creator)
{
return;
}
const uint32_t FT_DATA = 0x0001;
const uint32_t FT_DATA_REQ = 0x0002;
ftRequest::ftRequest(uint32_t type, std::string peerId, std::string hash, uint64_t offset, uint32_t chunk, void *data)
:mType(type), mPeerId(peerId), mHash(hash),
mOffset(offset), mChunk(chunk), mData(data)
{
return;
}
ftDataMultiplex::ftDataMultiplex(ftDataSend *server, ftSearch *search)
:mDataSend(server), mSearch(search)
{
return;
}
bool ftDataMultiplex::addTransferModule(ftTransferModule *mod, ftFileCreator *f)
{
RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/
std::map<std::string, ftClient>::iterator it;
if (mClients.end() != (it = mClients.find(mod->hash())))
{
/* error */
return false;
}
mClients[mod->hash()] = ftClient(mod, f);
return true;
}
bool ftDataMultiplex::removeTransferModule(ftTransferModule *mod, ftFileCreator *f)
{
RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/
std::map<std::string, ftClient>::iterator it;
if (mClients.end() == (it = mClients.find(mod->hash())))
{
/* error */
return false;
}
mClients.erase(it);
return true;
}
/* data interface */
/*************** SEND INTERFACE (calls ftDataSend) *******************/
/* Client Send */
bool ftDataMultiplex::sendDataRequest(std::string peerId, std::string hash, uint64_t offset, uint32_t size)
{
return mDataSend->sendDataRequest(peerId, hash, offset, size);
}
/* Server Send */
bool ftDataMultiplex::sendData(std::string peerId, std::string hash, uint64_t offset, uint32_t size, void *data)
{
return mDataSend->sendData(peerId, hash, offset, size, data);
}
/*************** RECV INTERFACE (provides ftDataRecv) ****************/
/* Client Recv */
bool ftDataMultiplex::recvData(std::string peerId, std::string hash, uint64_t offset, uint32_t size, void *data)
{
/* Store in Queue */
RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/
mRequestQueue.push_back(
ftRequest(FT_DATA, peerId, hash, offset, size, data));
return true;
}
/* Server Recv */
bool ftDataMultiplex::recvDataRequest(std::string peerId, std::string hash, uint64_t offset, uint32_t size)
{
/* Store in Queue */
RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/
mRequestQueue.push_back(
ftRequest(FT_DATA_REQ, peerId, hash, offset, size, NULL));
return true;
}
/*********** BACKGROUND THREAD OPERATIONS ***********/
bool ftDataMultiplex::handleRecvData(std::string peerId,
std::string hash, uint64_t offset, uint32_t size, void *data)
{
RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/
std::map<std::string, ftClient>::iterator it;
if (mClients.end() == (it = mClients.find(hash)))
{
/* error */
return false;
}
(it->second).mModule->recvFileData(peerId, offset, size, data);
return true;
}
/* called by ftTransferModule */
bool ftDataMultiplex::handleRecvDataRequest(std::string peerId,
std::string hash, uint64_t offset, uint32_t size)
{
/**** Find Files *****/
RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/
std::map<std::string, ftClient>::iterator cit;
if (mClients.end() != (cit = mClients.find(hash)))
{
locked_handleServerRequest((cit->second).mCreator,
peerId, hash, offset, size);
return true;
}
std::map<std::string, ftFileProvider *>::iterator sit;
if (mServers.end() != (sit = mServers.find(hash)))
{
locked_handleServerRequest(sit->second,
peerId, hash, offset, size);
return true;
}
/* Add to Search Queue */
mSearchQueue.push_back(
ftRequest(FT_DATA_REQ, peerId, hash, offset, size, NULL));
return true;
}
bool ftDataMultiplex::locked_handleServerRequest(ftFileProvider *provider,
std::string peerId, std::string hash, uint64_t offset, uint32_t size)
{
void *data = malloc(size);
if (provider->getFileData(offset, size, data))
{
/* send data out */
sendData(peerId, hash, offset, size, data);
return true;
}
return false;
}
bool ftDataMultiplex::handleSearchRequest(std::string peerId,
std::string hash, uint64_t offset, uint32_t size)
{
{
RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/
/* Check for bad requests */
std::map<std::string, time_t>::iterator bit;
if (mUnknownHashs.end() != (bit = mUnknownHashs.find(hash)))
{
/* We've previously rejected this one, so ignore */
return false;
}
}
/*
* Do Actual search
* Could be Cache File, Local or Extra
* (anywhere but remote really)
*/
FileInfo info;
uint32_t hintflags = (RS_FILE_HINTS_CACHE |
RS_FILE_HINTS_EXTRA |
RS_FILE_HINTS_LOCAL |
RS_FILE_HINTS_SPEC_ONLY);
if (mSearch->search(hash, size, hintflags, info))
{
/* setup a new provider */
RsStackMutex stack(dataMtx); /******* LOCK MUTEX ******/
ftFileProvider *provider =
new ftFileProvider(info.path, size, hash);
mServers[hash] = provider;
/* handle request finally */
locked_handleServerRequest(provider,
peerId, hash, offset, size);
return true;
}
return false;
}

View File

@ -0,0 +1,136 @@
/*
* libretroshare/src/ft: ftdatamultiplex.h
*
* File Transfer for RetroShare.
*
* 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".
*
*/
#ifndef FT_DATA_MULTIPLEX_HEADER
#define FT_DATA_MULTIPLEX_HEADER
/*
* ftDataMultiplexModule.
*
* This multiplexes the data from PQInterface to the ftTransferModules.
*/
class ftTransferModule;
class ftFileProvider;
class ftFileCreator;
class ftSearch;
#include <string>
#include <list>
#include <map>
#include <inttypes.h>
#include "util/rsthreads.h"
#include "ft/ftdata.h"
class ftClient
{
public:
ftClient() :mModule(NULL), mCreator(NULL) { return; }
ftClient(ftTransferModule *module, ftFileCreator *creator);
ftTransferModule *mModule;
ftFileCreator *mCreator;
};
class ftRequest
{
public:
ftRequest(uint32_t type, std::string peerId, std::string hash, uint64_t offset, uint32_t chunk, void *data);
uint32_t mType;
std::string mPeerId;
std::string mHash;
uint64_t mOffset;
uint32_t mChunk;
void *mData;
};
class ftDataMultiplex: public ftDataRecv
{
public:
ftDataMultiplex(ftDataSend *server, ftSearch *search);
/* ftController Interface */
bool addTransferModule(ftTransferModule *mod, ftFileCreator *f);
bool removeTransferModule(ftTransferModule *mod, ftFileCreator *f);
/* data interface */
/*************** SEND INTERFACE (calls ftDataSend) *******************/
/* Client Send */
bool sendDataRequest(std::string peerId, std::string hash, uint64_t offset, uint32_t size);
/* Server Send */
bool sendData(std::string peerId, std::string hash, uint64_t offset, uint32_t size, void *data);
/*************** RECV INTERFACE (provides ftDataRecv) ****************/
/* Client Recv */
virtual bool recvData(std::string peerId, std::string hash, uint64_t offset, uint32_t size, void *data);
/* Server Recv */
virtual bool recvDataRequest(std::string peerId, std::string hash, uint64_t offset, uint32_t size);
private:
/* Handling Job Queues */
bool handleRecvData(std::string peerId,
std::string hash, uint64_t offset, uint32_t size, void *data);
bool handleRecvDataRequest(std::string peerId,
std::string hash, uint64_t offset, uint32_t size);
bool handleSearchRequest(std::string peerId,
std::string hash, uint64_t offset, uint32_t size);
/* We end up doing the actual server job here */
bool locked_handleServerRequest(ftFileProvider *provider,
std::string peerId, std::string hash, uint64_t offset, uint32_t size);
RsMutex dataMtx;
std::map<std::string, ftClient> mClients;
std::map<std::string, ftFileProvider *> mServers;
std::list<ftRequest> mRequestQueue;
std::list<ftRequest> mSearchQueue;
std::map<std::string, time_t> mUnknownHashs;
ftDataSend *mDataSend;
ftSearch *mSearch;
};
#endif

View File

@ -23,59 +23,8 @@
*
*/
#ifndef FT_FILE_EXTRA_LIST_HEADER
#define FT_FILE_EXTRA_LIST_HEADER
/*
* ftFileExtraList
*
* This maintains a list of 'Extra Files' to share with peers.
*
* Files are added via:
* 1) For Files which have been hashed already:
* addExtraFile(std::string path, std::string hash, uint64_t size, uint32_t period, uint32_t flags);
*
* 2) For Files to be hashed:
* hashExtraFile(std::string path, uint32_t period, uint32_t flags);
*
* Results of Hashing can be retrieved via:
* hashExtraFileDone(std::string path, std::string &hash, uint64_t &size);
*
* Files can be searched for via:
* searchExtraFiles(std::string hash, ftFileDetail file);
*
* This Class is Mutexed protected, and has a thread in it which checks the files periodically.
* If a file is found to have changed... It is discarded from the list - and not updated.
*
* this thread is also used to hash added files.
*
* The list of extra files is stored using the configuration system.
*
*/
class FileDetails
{
public:
std::list<std::string> sources;
std::string path;
std::string fname;
std::string hash;
uint64_t size;
uint32_t start;
uint32_t period;
uint32_t flags;
};
const uint32_t FT_DETAILS_CLEANUP = 0x0100; /* remove when it expires */
const uint32_t FT_DETAILS_LOCAL = 0x0001;
const uint32_t FT_DETAILS_REMOTE = 0x0002;
class ftExtraList: public p3Config
{
public:
#include "ft/ftextralist.h"
#include "util/rsdir.h"
ftExtraList::ftExtraList()
:p3Config(CONFIG_FT_EXTRA_LIST)
@ -128,26 +77,32 @@ void ftExtraList::run()
void ftExtraList::hashAFile()
{
/* extract entry from the queue */
std::string path;
FileDetails details;
{
RsStackMutex stack(extMutex);
path = mToHash.front();
details = mToHash.front();
mToHash.pop_front();
}
/* hash it! */
if (hashFile(path, details))
std::string name, hash;
uint64_t size;
if (RsDirUtil::hashFile(details.info.path, details.info.fname,
details.info.hash, details.info.size))
{
RsStackMutex stack(extMutex);
details.start = time(NULL);
/* stick it in the available queue */
addExtraFile(path, hash, size, period, flags);
mFiles[details.info.hash] = details;
/* add to the path->hash map */
addNewlyHashed(path, details);
mHashedList[details.info.path] = details.info.hash;
}
}
/***
* If the File is alreay Hashed, then just add it in.
**/
@ -157,6 +112,19 @@ bool ftExtraList::addExtraFile(std::string path, std::string hash,
{
RsStackMutex stack(extMutex);
FileDetails details;
details.info.path = path;
details.info.fname = RsDirUtil::getTopDir(path);
details.info.hash = hash;
details.info.size = size;
details.start = time(NULL);
details.flags = flags;
details.period = period;
/* stick it in the available queue */
mFiles[details.info.hash] = details;
}
@ -165,6 +133,8 @@ bool ftExtraList::cleanupOldFiles()
{
RsStackMutex stack(extMutex);
time_t now = time(NULL);
std::list<std::string> toRemove;
std::list<std::string>::iterator rit;
@ -172,7 +142,7 @@ bool ftExtraList::cleanupOldFiles()
for(it = mFiles.begin(); it != mFiles.end(); it++)
{
/* check timestamps */
if (it->
if (it->second.start + it->second.period < now)
{
toRemove.push_back(it->first);
}
@ -208,7 +178,7 @@ bool ftExtraList::hashExtraFile(std::string path, uint32_t period, uint32_t fla
return true;
}
bool ftExtraList::hashExtraFileDone(std::string path, FileDetails &details)
bool ftExtraList::hashExtraFileDone(std::string path, FileInfo &info)
{
std::string hash;
{
@ -222,14 +192,14 @@ bool ftExtraList::hashExtraFileDone(std::string path, FileDetails &details)
}
hash = it->second;
}
return searchExtraFiles(hash, details);
return searchExtraFiles(hash, info);
}
/***
* Search Function - used by File Transfer
*
**/
bool ftExtraList::searchExtraFiles(std::string hash, FileDetails &details)
bool ftExtraList::searchExtraFiles(std::string hash, FileInfo &info)
{
RsStackMutex stack(extMutex);
@ -240,7 +210,7 @@ bool ftExtraList::searchExtraFiles(std::string hash, FileDetails &details)
return false;
}
details = fit->second;
info = fit->second.info;
return true;
}

View File

@ -53,15 +53,45 @@
*
*/
#include <list>
#include <map>
#include <string>
#include "util/rsthreads.h"
#include "rsiface/rsfiles.h"
#include "pqi/p3cfgmgr.h"
class FileDetails
{
public:
FileDetails()
{
return;
}
FileDetails(std::string path, uint32_t p, uint32_t f)
{
info.path = path;
period = p;
flags = f;
}
FileDetails(FileInfo &i, uint32_t p, uint32_t f)
{
info = i;
period = p;
flags = f;
}
FileInfo info;
#if 0 /*** WHAT IS NEEDED ***/
std::list<std::string> sources;
std::string path;
std::string fname;
std::string hash;
uint64_t size;
#endif
uint32_t start;
uint32_t period;
@ -72,7 +102,13 @@ const uint32_t FT_DETAILS_CLEANUP = 0x0100; /* remove when it expires */
const uint32_t FT_DETAILS_LOCAL = 0x0001;
const uint32_t FT_DETAILS_REMOTE = 0x0002;
class ftExtraList: public p3Config
#warning CONFIG_FT_EXTRA_LIST Not defined in p3cfgmgr.h
const uint32_t CONFIG_FT_EXTRA_LIST = 1;
const uint32_t CLEANUP_PERIOD = 600; /* 10 minutes */
class ftExtraList: public RsThread, public p3Config
{
public:
@ -100,6 +136,11 @@ bool hashExtraFileDone(std::string path, FileInfo &info);
**/
bool searchExtraFiles(std::string hash, FileInfo &info);
/***
* Thread Main Loop
**/
virtual void run();
/***
* Configuration - store extra files.
*
@ -111,12 +152,19 @@ virtual bool loadList(std::list<RsItem *> load);
private:
/* Worker Functions */
void hashAFile();
bool cleanupOldFiles();
RsMutex extMutex;
std::map<std::string, std::string> hashedList; /* path -> hash ( not saved ) */
std::map<std::string, FileInfo> files;
std::list<FileDetails> mToHash;
std::map<std::string, std::string> mHashedList; /* path -> hash ( not saved ) */
std::map<std::string, FileDetails> mFiles;
};
#endif

View File

@ -0,0 +1,160 @@
/*
* libretroshare/src/ft: ftextralisttest.cc
*
* File Transfer for RetroShare.
*
* 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 "ft/ftextralist.h"
extern "C" void* runExtraList(void* p)
{
ftExtraList *eList = (ftExtraList *) p;
if (!eList)
{
pthread_exit(NULL);
}
while (1)
{
//eList->tick();
sleep(1);
}
delete eList;
pthread_exit(NULL);
return NULL;
}
void displayExtraListDetails(ftExtraList *eList, std::list<std::string> toHash, std::list<std::string> hashed);
void usage(char *name)
{
std::cerr << "Usage: " << name << " -h <path> -p <period> -d <dperiod>";
std::cerr << std::endl;
}
int main(int argc, char **argv)
{
int c;
uint32_t period = 1;
uint32_t dPeriod = 600; /* default 10 minutes */
std::list<std::string> hashList;
while(-1 != (c = getopt(argc, argv, "h:p:d:")))
{
switch (c)
{
case 'h':
hashList.push_back(std::string(optarg));
break;
case 'p':
period = atoi(optarg);
break;
case 'd':
dPeriod = atoi(optarg);
break;
default:
usage(argv[0]);
break;
}
}
ftExtraList *eList = new ftExtraList();
/* now startup background thread to keep it reunning */
eList->start();
/* now work the thread */
std::list<std::string> toHash;
std::list<std::string> hashed;
std::list<std::string>::iterator it;
uint32_t flags = 0;
for(it = hashList.begin(); it != hashList.end(); it++)
{
sleep(period);
/* load up file */
//eList->addExtraFile(*it);
eList->hashExtraFile(*it, dPeriod, flags);
toHash.push_back(*it);
displayExtraListDetails(eList, toHash, hashed);
}
while(1)
{
sleep(period);
displayExtraListDetails(eList, toHash, hashed);
}
}
void displayExtraListDetails(ftExtraList *eList, std::list<std::string> toHash, std::list<std::string> hashed)
{
std::cerr << "displayExtraListDetails()";
std::cerr << std::endl;
std::list<std::string>::iterator it;
for(it = toHash.begin(); it != toHash.end(); it++)
{
FileInfo info;
if (eList->hashExtraFileDone(*it, info))
{
std::cerr << "displayExtraListDetails() Hash Completed for: " << *it;
std::cerr << std::endl;
std::cerr << info << std::endl;
}
else
{
std::cerr << "displayExtraListDetails() Hash Not Done for: " << *it;
std::cerr << std::endl;
}
}
for(it = hashed.begin(); it != hashed.end(); it++)
{
FileInfo info;
if (eList->searchExtraFiles(*it, info))
{
std::cerr << "displayExtraListDetails() Found Hash: " << *it;
std::cerr << std::endl;
std::cerr << info << std::endl;
}
else
{
std::cerr << "displayExtraListDetails() Hash Not Found: " << *it;
std::cerr << std::endl;
}
}
}

View File

@ -34,7 +34,7 @@
*
*/
#include "rsiface/rstypes.h"
#include "rsiface/rsfiles.h" // includes rsiface/rstypes.h too!
class ftSearch
{
@ -42,10 +42,21 @@ class ftSearch
public:
ftSearch() { return; }
virtual bool search(std::string hash, uint64_t size, uint32_t hintflags, FileInfo &info);
virtual ~ftSearch() { return; }
virtual bool search(std::string hash, uint64_t size, uint32_t hintflags, FileInfo &info) = 0;
};
class ftSearchDummy
{
ftSearchDummy() { return; }
virtual ~ftSearchDummy() { return; }
virtual bool search(std::string hash, uint64_t size, uint32_t hintflags, FileInfo &info)
{
return false;
}
};
#endif

View File

@ -39,27 +39,25 @@
*
*/
#include "pqi/pqi.h"
#include "pqi/pqiindic.h"
#include "serialiser/rsconfigitems.h"
#include <map>
#include <deque>
#include <list>
#include <map>
#include <iostream>
#include "rsiface/rsiface.h"
#include "rsiface/rsfiles.h"
#include "dbase/cachestrapper.h"
#include "pqi/p3cfgmgr.h"
class p3ConnectMgr;
class p3AuthMgr;
class CacheStrapper;
class ftfiler;
class FileIndexStore;
class FileIndexMonitor;
class ftController;
class ftExtraList;
class ftServer: public RsFiles
{
@ -104,7 +102,7 @@ virtual bool FileDetails(std::string hash, uint32_t hintflags, FileInfo &info);
/* Access ftExtraList - Details */
virtual bool ExtraFileAdd(std::string fname, std::string hash, uint32_t size,
uint32_t period, uint32_t flags);
virtual bool ExtraFileRemove(std::string hash, uin32_t flags);
virtual bool ExtraFileRemove(std::string hash, uint32_t flags);
virtual bool ExtraFileHash(std::string localpath, uint32_t period, uint32_t flags);
virtual bool ExtraFileStatus(std::string localpath, FileInfo &info);
@ -131,23 +129,20 @@ virtual bool getSharedDirectories(std::list<std::string> &dirs);
virtual bool addSharedDirectory(std::string dir);
virtual bool removeSharedDirectory(std::string dir);
virtual int reScanDirs();
virtual int check_dBUpdate();
std::string getSaveDir();
void setSaveDir(std::string d);
void setEmergencySaveDir(std::string s);
void setConfigDir(std::string d) { config_dir = d; }
bool getSaveIncSearch();
void setSaveIncSearch(bool v);
/***************************************************************/
/*************** Control Interface *****************************/
/***************************************************************/
/***************************************************************/
/*************** Data Transfer Interface ***********************/
/***************************************************************/
bool requestData(std::string peerId, std::string hash,
uint64_t offset, uint32_t size);
/******************* p3 Config Overload ************************/
protected:
/* Key Functions to be overloaded for Full Configuration */

View File

@ -37,7 +37,7 @@
#include <map>
#include <list>
#include <ftFileCreator.h>
#include "ft/ftfilecreator.h"
class Request
{
@ -47,7 +47,7 @@ class Request
class peerInfo
{
std:string peerId;
std::string peerId;
uint16_t state;
uint32_t desiredRate;
Request lastRequest;
@ -71,21 +71,26 @@ public:
bool completeFileTransfer();
//interface to client module
bool recvFileData(uint64_t offset, uint32_t chunk_size, void *data);
void requestData(std::hash, uint64_t offset, uint32_t chunk_size);
bool recvFileData(std::string peerId, uint64_t offset,
uint32_t chunk_size, void *data);
void requestData(std::string hash, uint64_t offset, uint32_t chunk_size);
//interface to file creator
bool getChunk(uint64_t &offset, uint32_t &chunk_size);
bool storeData(uint64_t offset, uint32_t chunk_size);
void tick();
/* add by DrBob for interfaces */
std::string hash() { return mHash; }
uint64_t size() { return mSize; }
public:
ftFileCreator* fc;
private:
std::string hash;
uint64_t size;
std::string mHash;
uint64_t mSize;
uint32_t dataRate; //data transfer rate for current file
uint16_t state; //file transfer state
std::list<std::string> onlinePeerList;

View File

@ -105,6 +105,10 @@ class FileTransferInfo: public FileInfo
FileTransferInfo() { return; }
};
std::ostream &operator<<(std::ostream &out, const FileInfo &info);
/* matched to the uPnP states */
#define UPNP_STATE_UNINITIALISED 0
#define UPNP_STATE_UNAVAILABILE 1

View File

@ -19,9 +19,9 @@ RSOBJ = p3peers.o \
p3face-msgs.o \
rsiface.o \
p3files.o \
rstypes.o
# p3face-file.o \
# rstypes.o \
# pqistrings.o \
# p3face-people.o
# p3face-network.o \

View File

@ -45,3 +45,16 @@
*
**********************************************************************/
std::ostream &operator<<(std::ostream &out, const FileInfo &info)
{
out << "FileInfo: path: " << info.path;
out << std::endl;
out << "File: " << info.fname;
out << " Size: " << info.size;
out << std::endl;
out << "Hash: " << info.hash;
return out;
}

View File

@ -196,6 +196,31 @@ int RsDirUtil::breakupDirList(std::string path,
bool RsDirUtil::checkDirectory(std::string dir)
{
struct stat buf;
int val = stat(dir.c_str(), &buf);
if (val == -1)
{
#ifdef RSDIR_DEBUG
std::cerr << "RsDirUtil::checkDirectory() ";
std::cerr << dir << " doesn't exist" << std::endl;
#endif
return false;
}
else if (!S_ISDIR(buf.st_mode))
{
// Some other type - error.
#ifdef RSDIR_DEBUG
std::cerr << "RsDirUtil::checkDirectory() ";
std::cerr << dir << " is not Directory" << std::endl;
#endif
return false;
}
return true;
}
bool RsDirUtil::checkCreateDirectory(std::string dir)
{
struct stat buf;
@ -289,11 +314,24 @@ bool RsDirUtil::cleanupDirectory(std::string cleandir, std::list<std::string> k
return true;
}
/* slightly nicer helper function */
bool RsDirUtil::hashFile(std::string filepath,
std::string &name, std::string &hash, uint64_t &size)
{
if (getFileHash(filepath, hash, size))
{
/* extract file name */
name = RsDirUtil::getTopDir(filepath);
return true;
}
return false;
}
#include <openssl/sha.h>
#include <sstream>
#include <iomanip>
/* Function to hash, and get details of a file */
bool RsDirUtil::getFileHash(std::string filepath,
std::string &hash, uint64_t &size)

View File

@ -43,9 +43,13 @@ std::string removeRootDirs(std::string path, std::string root);
int breakupDirList(std::string path,
std::list<std::string> &subdirs);
bool checkDirectory(std::string dir);
bool checkCreateDirectory(std::string dir);
bool cleanupDirectory(std::string dir, std::list<std::string> keepFiles);
bool hashFile(std::string filepath,
std::string &name, std::string &hash, uint64_t &size);
bool getFileHash(std::string filepath,
std::string &hash, uint64_t &size);

View File

@ -26,6 +26,7 @@
#include "rsthreads.h"
#include <unistd.h> /* for usleep() */
extern "C" void* rsthread_init(void* p)
{
@ -56,4 +57,43 @@ pthread_t createThread(RsThread &thread)
}
RsQueueThread::RsQueueThread(uint32_t min, uint32_t max, double relaxFactor )
:mMinSleep(min), mMaxSleep(max), mRelaxFactor(relaxFactor)
{
}
void RsQueueThread::run()
{
while(1)
{
bool doneWork = false;
while(workQueued() && doWork())
{
doneWork = true;
}
time_t now = time(NULL);
if (doneWork)
{
mLastWork = now;
mLastSleep = (uint32_t)
(mMinSleep + (mLastSleep - mMinSleep) / 2.0);
}
else
{
uint32_t deltaT = now - mLastWork;
double frac = deltaT / mRelaxFactor;
mLastSleep += (uint32_t)
((mMaxSleep-mMinSleep) * (frac + 0.05));
if (mLastSleep > mMaxSleep)
{
mLastSleep = mMaxSleep;
}
}
usleep(1000 * mLastSleep);
}
}

View File

@ -28,6 +28,7 @@
#include <pthread.h>
#include <inttypes.h>
/* RsIface Thread Wrappers */
@ -75,4 +76,23 @@ virtual void run() = 0; /* called once the thread is started */
};
class RsQueueThread
{
RsQueueThread(uint32_t min, uint32_t max, double relaxFactor );
virtual ~RsQueueThread() { return; }
virtual void run();
virtual bool workQueued() = 0;
virtual bool doWork() = 0;
private:
uint32_t mMinSleep; /* ms */
uint32_t mMaxSleep; /* ms */
uint32_t mLastSleep; /* ms */
time_t mLastWork; /* secs */
float mRelaxFactor;
};
#endif