RetroShare/libretroshare/src/services/p3serviceinfo.cc

265 lines
5.8 KiB
C++

/*
* libretroshare/src/services p3serviceinfo.cc
*
* ServiceInfo Service for RetroShare.
*
* Copyright 2014 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.1 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 "pqi/p3linkmgr.h"
#include "pqi/p3netmgr.h"
#include "util/rsnet.h"
#include "services/p3serviceinfo.h"
#include "rsitems/rsbanlistitems.h"
#include <sys/time.h>
/****
* #define DEBUG_INFO 1
****/
/************ IMPLEMENTATION NOTES *********************************
*
* Send Info to peers about services we are providing.
*/
p3ServiceInfo::p3ServiceInfo(p3ServiceControl *serviceControl)
:p3Service(), mInfoMtx("p3ServiceInfo"),
mServiceControl(serviceControl)
{
addSerialType(new RsServiceInfoSerialiser());
}
const std::string SERVICE_INFO_APP_NAME = "serviceinfo";
const uint16_t SERVICE_INFO_APP_MAJOR_VERSION = 1;
const uint16_t SERVICE_INFO_APP_MINOR_VERSION = 0;
const uint16_t SERVICE_INFO_MIN_MAJOR_VERSION = 1;
const uint16_t SERVICE_INFO_MIN_MINOR_VERSION = 0;
RsServiceInfo p3ServiceInfo::getServiceInfo()
{
return RsServiceInfo(RS_SERVICE_TYPE_SERVICEINFO,
SERVICE_INFO_APP_NAME,
SERVICE_INFO_APP_MAJOR_VERSION,
SERVICE_INFO_APP_MINOR_VERSION,
SERVICE_INFO_MIN_MAJOR_VERSION,
SERVICE_INFO_MIN_MINOR_VERSION);
}
int p3ServiceInfo::tick()
{
processIncoming();
sendPackets();
return 0;
}
int p3ServiceInfo::status()
{
return 1;
}
/***** Implementation ******/
bool p3ServiceInfo::processIncoming()
{
/* for each packet - pass to specific handler */
RsItem *item = NULL;
while(NULL != (item = recvItem()))
{
#ifdef DEBUG_INFO
std::cerr << "p3ServiceInfo::processingIncoming() Received Item:";
std::cerr << std::endl;
item->print(std::cerr);
std::cerr << std::endl;
#endif
switch(item->PacketSubType())
{
default:
break;
case RS_PKT_SUBTYPE_SERVICELIST_ITEM:
{
// Order is important!.
RsServiceInfoListItem *listItem = dynamic_cast<RsServiceInfoListItem *>(item);
if (listItem)
{
recvServiceInfoList(listItem);
}
else
{
// error.
std::cerr << "p3ServiceInfo::processingIncoming() Error with Received Item:";
std::cerr << std::endl;
item->print(std::cerr);
std::cerr << std::endl;
}
}
break;
}
/* clean up */
delete item;
}
return true ;
}
bool convertServiceInfoToItem(
const RsPeerServiceInfo &info,
RsServiceInfoListItem *item)
{
item->mServiceInfo = info.mServiceList;
item->PeerId(info.mPeerId);
return true;
}
bool convertServiceItemToInfo(
const RsServiceInfoListItem *item,
RsPeerServiceInfo &info)
{
info.mServiceList = item->mServiceInfo;
info.mPeerId = item->PeerId();
return true;
}
bool p3ServiceInfo::recvServiceInfoList(RsServiceInfoListItem *item)
{
RsPeerId peerId = item->PeerId();
#ifdef DEBUG_INFO
std::cerr << "p3ServiceInfo::recvServiceInfoList() from: " << peerId.toStdString();
std::cerr << std::endl;
#endif
RsPeerServiceInfo info;
if (convertServiceItemToInfo(item, info))
{
#ifdef DEBUG_INFO
std::cerr << "p3ServiceInfo::recvServiceInfoList() Info: ";
std::cerr << std::endl;
std::cerr << info;
std::cerr << std::endl;
#endif
/* update service control */
mServiceControl->updateServicesProvided(peerId, info);
return true;
}
return false;
}
bool p3ServiceInfo::sendPackets()
{
std::set<RsPeerId> updateSet;
{
RsStackMutex stack(mInfoMtx); /****** LOCKED MUTEX *******/
updateSet = mPeersToUpdate;
mPeersToUpdate.clear();
}
mServiceControl->getServiceChanges(updateSet);
RsStackMutex stack(mInfoMtx); /****** LOCKED MUTEX *******/
std::set<RsPeerId>::iterator it;
for(it = updateSet.begin(); it != updateSet.end(); ++it)
{
sendServiceInfoList(*it);
}
return (!updateSet.empty());
}
int p3ServiceInfo::sendServiceInfoList(const RsPeerId &peerId)
{
#ifdef DEBUG_INFO
std::cerr << "p3ServiceInfo::sendServiceInfoList() to " << peerId.toStdString();
std::cerr << std::endl;
#endif
RsServiceInfoListItem *item = new RsServiceInfoListItem();
RsPeerServiceInfo info;
bool sent = false;
if (mServiceControl->getServicesAllowed(peerId, info))
{
#ifdef DEBUG_INFO
std::cerr << "p3ServiceInfo::sendServiceInfoList() Info: ";
std::cerr << std::endl;
std::cerr << info;
std::cerr << std::endl;
#endif
if (convertServiceInfoToItem(info, item))
{
item->PeerId(peerId);
sent = true;
sendItem(item);
}
}
if (!sent)
{
delete item;
}
return sent;
}
void p3ServiceInfo::statusChange(const std::list<pqipeer> &plist)
{
#ifdef DEBUG_INFO
std::cerr << "p3ServiceInfo::statusChange()";
std::cerr << std::endl;
#endif
std::list<pqipeer>::const_iterator it;
for (it = plist.begin(); it != plist.end(); ++it)
{
if (it->state & RS_PEER_S_FRIEND)
{
if (it->actions & RS_PEER_CONNECTED)
{
#ifdef DEBUG_INFO
std::cerr << "p3ServiceInfo::statusChange()";
std::cerr << "Peer: " << it->id;
std::cerr << " Connected";
std::cerr << std::endl;
#endif
RsStackMutex stack(mInfoMtx); /****** LOCKED MUTEX *******/
mPeersToUpdate.insert(it->id);
}
}
}
}