RetroShare/libretroshare/src/zeroconf/p3zeroconf.cc

1432 lines
34 KiB
C++
Raw Normal View History

/*
* libretroshare/src/zeroconf: p3zeroconf.cc
*
* ZeroConf interface for RetroShare.
*
* Copyright 2011-2011 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 "zeroconf/p3zeroconf.h"
#include <openssl/sha.h>
#include <iostream>
#include "pqi/authgpg.h"
/* TODO
*
* - Get Local Port when it changes.... (need second interface?)
* - Get GpgId, SslId for all peers.
* - Able to install new sslIds for friends.
* - Hold data for all peers.
* - parse TxtRecord.
*
*/
//#define DEBUG_ZEROCONF 1
#define ZC_MAX_QUERY_TIME 30
#define ZC_MAX_RESOLVE_TIME 30
p3ZeroConf::p3ZeroConf(std::string gpgid, std::string sslid, pqiConnectCb *cb, p3NetMgr *nm, p3PeerMgr *pm)
:pqiNetAssistConnect(sslid, cb), mNetMgr(nm), mPeerMgr(pm), mZcMtx("p3ZeroConf")
{
mRegistered = false;
mTextOkay = false;
mPortOkay = false;
mOwnGpgId = gpgid;
mOwnSslId = sslid;
#ifdef DEBUG_ZEROCONF
std::cerr << "p3ZeroConf::p3ZeroConf()" << std::endl;
std::cerr << "Using Id: " << sslid;
std::cerr << std::endl;
#endif
mRegisterStatus = ZC_SERVICE_STOPPED;
mRegisterStatusTS = time(NULL);
mBrowseStatus = ZC_SERVICE_STOPPED;
mBrowseStatusTS = time(NULL);
mResolveStatus = ZC_SERVICE_STOPPED;
mResolveStatusTS = time(NULL);
mQueryStatus = ZC_SERVICE_STOPPED;
mQueryStatusTS = time(NULL);
createTxtRecord();
}
p3ZeroConf::~p3ZeroConf()
{
}
void p3ZeroConf::start()
{
#ifdef DEBUG_ZEROCONF
std::cerr << "p3ZeroConf::start()";
std::cerr << std::endl;
#endif
}
/* pqiNetAssist - external interface functions */
void p3ZeroConf::enable(bool on)
{
#ifdef DEBUG_ZEROCONF
std::cerr << "p3ZeroConf::enable(" << on << ")";
std::cerr << std::endl;
#endif
}
void p3ZeroConf::shutdown() /* blocking call */
{
}
void p3ZeroConf::restart()
{
}
bool p3ZeroConf::getEnabled()
{
return true;
}
bool p3ZeroConf::getActive()
{
return true;
}
bool p3ZeroConf::getNetworkStats(uint32_t &netsize, uint32_t &localnetsize)
{
return false; // Cannot provide Network Stats.
}
void p3ZeroConf::createTxtRecord()
{
RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/
std::string gpgid = "gpgid=" + mOwnGpgId;
std::string sslid = "sslid=" + mOwnSslId;
mTextRecord += (char) gpgid.length();
mTextRecord += gpgid;
mTextRecord += (char) sslid.length();
mTextRecord += sslid;
std::cerr << "p3ZeroConf::createTxtRecord() Record: " << std::endl;
std::cerr << "------------------------------------" << std::endl;
std::cerr << mTextRecord;
std::cerr << std::endl;
std::cerr << "------------------------------------" << std::endl;
mTextOkay = true;
}
int procPeerTxtRecord(int txtLen, const unsigned char *txtRecord, std::string &peerGpgId, std::string &peerSslId)
{
int txtRemaining = txtLen;
int idx = 0;
bool setGpg = false;
bool setSsl = false;
std::cerr << "procPeerTxtRecord() processing";
std::cerr << std::endl;
while(txtRemaining > 0)
{
uint8_t len = txtRecord[idx];
idx++;
txtRemaining -= 1;
std::string record((const char *) txtRecord, idx, len);
std::cerr << "procPeerTxtRecord() record: " << record;
std::cerr << std::endl;
if (0 == strncmp(record.c_str(), "gpgid=", 6))
{
peerGpgId = record.substr(6, -1);
setGpg = true;
std::cerr << "procPeerTxtRecord() found peerGpgId: " << peerGpgId;
std::cerr << std::endl;
}
else if (0 == strncmp(record.c_str(), "sslid=", 6))
{
peerSslId = record.substr(6, -1);
setSsl = true;
std::cerr << "procPeerTxtRecord() found peerSslId: " << peerSslId;
std::cerr << std::endl;
}
else
{
std::cerr << "Unknown Record";
}
idx += len;
txtRemaining -= len;
}
return (setGpg && setSsl);
}
/*** OVERLOADED from pqiNetListener ***/
bool p3ZeroConf::resetListener(struct sockaddr_in &local)
{
RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/
mLocalPort = ntohs(local.sin_port);
mPortOkay = true;
if (mRegisterStatus == ZC_SERVICE_ACTIVE)
{
locked_stopRegister();
}
return true;
}
/*****************************************************************************
********* pqiNetAssistConnect - external interface functions ***************
*****************************************************************************/
/**** DUMMY FOR THE MOMENT *****/
bool p3ZeroConf::findPeer(std::string pid)
{
#ifdef DEBUG_ZEROCONF
std::cerr << "p3ZeroConf::findPeer(" << pid << ")";
std::cerr << std::endl;
#endif
return true;
}
bool p3ZeroConf::dropPeer(std::string pid)
{
#ifdef DEBUG_ZEROCONF
std::cerr << "p3ZeroConf::dropPeer(" << pid << ")";
std::cerr << std::endl;
#endif
return true;
}
/* extract current peer status */
bool p3ZeroConf::getPeerStatus(std::string id,
struct sockaddr_storage &/*laddr*/, struct sockaddr_storage &/*raddr*/,
uint32_t &/*type*/, uint32_t &/*mode*/)
{
/* remove unused parameter warnings */
(void) id;
#ifdef DEBUG_ZEROCONF
std::cerr << "p3ZeroConf::getPeerStatus(" << id << ")";
std::cerr << std::endl;
#endif
return false;
}
#if 0
bool p3ZeroConf::getExternalInterface(struct sockaddr_storage &/*raddr*/,
uint32_t &/*mode*/)
{
#ifdef DEBUG_ZEROCONF
std::cerr << "p3ZeroConf::getExternalInterface()";
std::cerr << std::endl;
#endif
return false;
}
#endif
bool p3ZeroConf::setAttachMode(bool on)
{
#ifdef DEBUG_ZEROCONF
std::cerr << "p3ZeroConf::setAttachMode(" << on << ")";
std::cerr << std::endl;
#endif
return true;
}
int p3ZeroConf::addBadPeer(const struct sockaddr_storage &addr, uint32_t reason, uint32_t flags, uint32_t age)
{
return 1;
}
int p3ZeroConf::addKnownPeer(const std::string &pid, const struct sockaddr_storage &addr, uint32_t flags)
{
return 1;
}
void p3ZeroConf::ConnectionFeedback(std::string pid, int state)
{
return;
}
/***********************************************************************************/
/*
*
*
* ZeroConf Interface for Retroshare.
* This will use the pqiNetAssistConnect Interface (like the DHT).
*
* we will advertise ourselves using GPGID & SSLID on the zeroconf interface.
*
* Will search local network for any peers.
* If they are our friends... callback to p3NetMgr to initiate connection.
*
*
* This should be very easy to implement under OSX.... so we start with that.
* For Windows, we will use Apple's libraries... so that should be similar too.
* Linux - won't bother with zeroconf for the moment - If someone feels like implementing that.. ok.
*
* Most important is that Windows and OSX can interact.
*
* We keep a simple system here....
* 1) Register.
* 2) Enable Browsing.
* 3) Resolve Browse results one at a time.
* 4) Callback Resolve results.
*
*
*/
int p3ZeroConf::tick()
{
{
RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/
locked_startRegister();
locked_startBrowse();
}
checkServiceFDs(); // will cause callbacks - if data is ready.
checkResolveAction();
checkLocationResults();
checkQueryAction();
checkQueryResults();
return 0;
}
void p3ZeroConf::checkServiceFDs()
{
RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/
//std::cerr << "p3ZeroConf::checkServiceFDs()";
//std::cerr << std::endl;
if (mRegisterStatus == ZC_SERVICE_ACTIVE)
{
locked_checkFD(mRegisterRef);
}
if (mBrowseStatus == ZC_SERVICE_ACTIVE)
{
locked_checkFD(mBrowseRef);
}
if (mResolveStatus == ZC_SERVICE_ACTIVE)
{
locked_checkFD(mResolveRef);
time_t age = time(NULL) - mResolveStatusTS;
if (age > ZC_MAX_RESOLVE_TIME)
{
std::cerr << "p3ZeroConf::checkServiceFDs() Killing very old Resolve request";
std::cerr << std::endl;
locked_stopResolve();
}
}
if (mQueryStatus == ZC_SERVICE_ACTIVE)
{
locked_checkFD(mQueryRef);
time_t age = time(NULL) - mQueryStatusTS;
if (age > ZC_MAX_QUERY_TIME)
{
std::cerr << "p3ZeroConf::checkServiceFDs() Killing very old Query request";
std::cerr << std::endl;
locked_stopQueryIp();
}
}
}
void p3ZeroConf::locked_checkFD(DNSServiceRef ref)
{
//std::cerr << "p3ZeroConf::locked_checkFD() Start";
//std::cerr << std::endl;
int sockfd = DNSServiceRefSockFD(ref);
fd_set ReadFDs, WriteFDs, ExceptFDs;
FD_ZERO(&ReadFDs);
FD_ZERO(&WriteFDs);
FD_ZERO(&ExceptFDs);
FD_SET(sockfd, &ReadFDs);
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
if (select(sockfd + 1, &ReadFDs, &WriteFDs, &ExceptFDs, &timeout) < 0)
{
std::cerr << "p3zeroconf::checkFD() Select ERROR";
std::cerr << std::endl;
return;
}
if (FD_ISSET(sockfd, &ReadFDs))
{
DNSServiceErrorType err = DNSServiceProcessResult(ref);
switch(err)
{
case 0:
/* ok */
break;
default:
std::cerr << "DNSServiceProcessResult() ERROR: ";
std::cerr << displayDNSServiceError(err);
std::cerr << std::endl;
break;
}
}
//std::cerr << "p3ZeroConf::locked_checkFD() End";
//std::cerr << std::endl;
return;
}
int p3ZeroConf::checkResolveAction()
{
RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/
if (mResolveStatus == ZC_SERVICE_ACTIVE)
{
/* Do nothing - if we are already resolving */
return 0;
}
/* iterate through the Browse Results... look for unresolved one - and do it! */
/* check the new results Queue first */
if (mBrowseResults.size() > 0)
{
std::cerr << "p3ZeroConf::checkResolveAction() Getting Item from BrowseResults";
std::cerr << std::endl;
zcBrowseResult br = mBrowseResults.front();
mBrowseResults.pop_front();
locked_startResolve(br.interfaceIndex, br.serviceName, br.regtype, br.replyDomain);
}
return 1;
}
int p3ZeroConf::checkLocationResults()
{
zcLocationResult lr;
{
RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/
/* check the results Queue */
if (mLocationResults.empty())
{
return 0;
}
std::cerr << "p3ZeroConf::checkLocationResults() Getting Item from LocationResults";
std::cerr << std::endl;
lr = mLocationResults.front();
mLocationResults.pop_front();
}
/* now callback to mPeerMgr to add new location... This will eventually get back here
* via some magic!
*/
std::cerr << "p3ZeroConf::checkLocationResults() adding new location.";
std::cerr << std::endl;
std::cerr << "gpgid = " << lr.gpgId;
std::cerr << std::endl;
std::cerr << "sslid = " << lr.sslId;
std::cerr << std::endl;
time_t now = time(NULL);
mPeerMgr->addFriend(lr.sslId, lr.gpgId, RS_NET_MODE_UDP, RS_VS_DISC_FULL, RS_VS_DHT_FULL, now);
return 1;
}
int p3ZeroConf::checkQueryAction()
{
RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/
if (mQueryStatus == ZC_SERVICE_ACTIVE)
{
/* Do nothing - if we are already resolving */
return 0;
}
/* check the new results Queue first */
if (mResolveResults.size() > 0)
{
std::cerr << "p3ZeroConf::checkQueryAction() Getting Item from ResolveResults";
std::cerr << std::endl;
zcResolveResult rr = mResolveResults.front();
mResolveResults.pop_front();
locked_startQueryIp(rr.interfaceIndex, rr.hosttarget, rr.gpgId, rr.sslId);
}
return 1;
}
int p3ZeroConf::checkQueryResults()
{
zcQueryResult qr;
{
RsStackMutex stack(mZcMtx); /****** STACK LOCK MUTEX *******/
/* check the results Queue */
if (mQueryResults.empty())
{
return 0;
}
std::cerr << "p3ZeroConf::checkQueryResults() Getting Item from QueryResults";
std::cerr << std::endl;
qr = mQueryResults.front();
mQueryResults.pop_front();
}
/* now callback to mLinkMgr to say we can connect */
std::cerr << "p3ZeroConf::checkQueryResults() linkMgr->peerConnectRequest() to start link";
std::cerr << std::endl;
std::cerr << "to gpgid = " << qr.gpgId;
std::cerr << std::endl;
std::cerr << "sslid = " << qr.sslId;
std::cerr << std::endl;
time_t now = time(NULL);
uint32_t flags = RS_CB_FLAG_MODE_TCP;
uint32_t source = RS_CB_DHT; // SHOULD ADD NEW SOURCE ZC???
struct sockaddr_storage dummyProxyAddr, dummySrcAddr;
sockaddr_storage_clear(dummyProxyAddr);
sockaddr_storage_clear(dummySrcAddr);
mConnCb->peerConnectRequest(qr.sslId, qr.addr, dummyProxyAddr, dummySrcAddr,
source, flags, 0, 0);
return 1;
}
/* First Step is to register the DNSService */
void p3ZeroConf_CallbackRegister( DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode,
const char *name, const char *regtype, const char *domain, void *context )
{
p3ZeroConf *zc = (p3ZeroConf *) context;
zc->callbackRegister(sdRef, flags, errorCode, name, regtype, domain);
}
int p3ZeroConf::locked_startRegister()
{
if (mRegistered)
{
return 0;
}
/* need, port & txtRecord setup already */
if (!mTextOkay)
{
std::cerr << "p3ZeroConf::locked_startRegister()";
std::cerr << "Text Not Setup";
std::cerr << std::endl;
return 0;
}
if (!mPortOkay)
{
std::cerr << "p3ZeroConf::locked_startRegister()";
std::cerr << "Port Not Set";
std::cerr << std::endl;
return 0;
}
if (mRegisterStatus == ZC_SERVICE_ACTIVE)
{
return 0;
}
std::cerr << "p3ZeroConf::locked_startRegister() Registering!";
std::cerr << std::endl;
std::cerr << "p3ZeroConf::locked_startRegister() Text: " << mTextRecord;
std::cerr << std::endl;
std::cerr << "p3ZeroConf::locked_startRegister() Port: " << mLocalPort;
std::cerr << std::endl;
DNSServiceRef *sdRef = &mRegisterRef;
DNSServiceFlags flags = 0; /* no flags */
uint32_t interfaceIndex = 0; /* all interfaces */
char *name = NULL; /* may be NULL */
std::string regtype = "_librs._tcp";
char *domain = NULL; /* may be NULL for all domains. */
char *host = NULL; /* may be NULL for default hostname */
uint16_t port = htons(mLocalPort);
uint16_t txtLen = mTextRecord.length();
const void *txtRecord = (void *) mTextRecord.c_str();
DNSServiceRegisterReply callBack = p3ZeroConf_CallbackRegister;
void *context = this;
DNSServiceErrorType errcode = DNSServiceRegister (sdRef, flags, interfaceIndex,
name, regtype.c_str(), domain, host, port,
txtLen, txtRecord, callBack, context);
if (errcode != kDNSServiceErr_NoError)
{
std::cerr << "p3ZeroConf::locked_startRegister() ERROR: ";
std::cerr << displayDNSServiceError(errcode);
std::cerr << std::endl;
}
else
{
mRegisterStatus = ZC_SERVICE_ACTIVE;
mRegisterStatusTS = time(NULL);
mRegistered = true;
}
return 1;
}
void p3ZeroConf::callbackRegister( DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode,
const char *name, const char *regtype, const char *domain)
{
std::cerr << "p3ZeroConf::callbackRegister()";
std::cerr << std::endl;
/* handle queryIp */
if (errorCode != kDNSServiceErr_NoError)
{
std::cerr << "p3ZeroConf::callbackRegister() FAILED ERROR: ";
std::cerr << displayDNSServiceError(errorCode);
std::cerr << std::endl;
return;
}
std::cerr << "p3ZeroConf::callbackRegister() Success";
std::cerr << std::endl;
}
void p3ZeroConf::locked_stopRegister()
{
std::cerr << "p3ZeroConf::locked_stopRegister()";
std::cerr << std::endl;
if (mRegisterStatus != ZC_SERVICE_ACTIVE)
{
return;
}
DNSServiceRefDeallocate(mRegisterRef);
mRegisterStatus = ZC_SERVICE_STOPPED;
mRegisterStatusTS = time(NULL);
mRegistered = false;
}
void p3ZeroConf_CallbackBrowse( DNSServiceRef sdRef, DNSServiceFlags flags,
uint32_t interfaceIndex, DNSServiceErrorType errorCode,
const char *serviceName, const char *regtype, const char *replyDomain, void *context )
{
p3ZeroConf *zc = (p3ZeroConf *) context;
zc->callbackBrowse(sdRef, flags, interfaceIndex, errorCode, serviceName, regtype, replyDomain);
}
int p3ZeroConf::locked_startBrowse()
{
if (mBrowseStatus == ZC_SERVICE_ACTIVE)
{
return 0;
}
std::cerr << "p3ZeroConf::locked_startBrowse()";
std::cerr << std::endl;
DNSServiceRef *sdRef = &mBrowseRef;
DNSServiceFlags flags = 0;
uint32_t interfaceIndex = 0;
const char *regtype = "_librs._tcp";
const char *domain = NULL;
DNSServiceBrowseReply callBack = p3ZeroConf_CallbackBrowse;
void *context = this;
DNSServiceErrorType errcode = DNSServiceBrowse(sdRef, flags, interfaceIndex,
regtype, domain, callBack, context);
if (errcode != kDNSServiceErr_NoError)
{
std::cerr << "p3ZeroConf::locked_startBrowse() ERROR: ";
std::cerr << displayDNSServiceError(errcode);
std::cerr << std::endl;
}
else
{
mBrowseStatus = ZC_SERVICE_ACTIVE;
mBrowseStatusTS = time(NULL);
}
return 1;
}
void p3ZeroConf::callbackBrowse(DNSServiceRef /* sdRef */, DNSServiceFlags flags,
uint32_t interfaceIndex, DNSServiceErrorType errorCode,
const char *serviceName, const char *regtype, const char *replyDomain)
{
std::cerr << "p3ZeroConf::callbackBrowse()";
std::cerr << std::endl;
/* handle queryIp */
if (errorCode != kDNSServiceErr_NoError)
{
std::cerr << "p3ZeroConf::callbackBrowse() FAILED ERROR: ";
std::cerr << displayDNSServiceError(errorCode);
std::cerr << std::endl;
return;
}
zcBrowseResult br;
br.flags = flags;
br.interfaceIndex = interfaceIndex;
br.serviceName = serviceName;
br.regtype = regtype;
br.replyDomain = replyDomain;
std::cerr << "p3ZeroConf::callbackBrowse() ";
std::cerr << " flags: " << flags;
std::cerr << " interfaceIndex: " << interfaceIndex;
std::cerr << " serviceName: " << serviceName;
std::cerr << " regtype: " << regtype;
std::cerr << " replyDomain: " << replyDomain;
std::cerr << std::endl;
if (flags & kDNSServiceFlagsAdd)
{
std::cerr << "p3ZeroConf::callbackBrowse() Add Flags => so newly found Service => BrowseResults";
std::cerr << std::endl;
mBrowseResults.push_back(br);
}
else
{
std::cerr << "p3ZeroConf::callbackBrowse() Missing Add Flag => so Service now dropped, Ignoring";
std::cerr << std::endl;
}
}
int p3ZeroConf::locked_stopBrowse()
{
std::cerr << "p3ZeroConf::locked_stopBrowse()";
std::cerr << std::endl;
if (mBrowseStatus != ZC_SERVICE_ACTIVE)
{
return 0;
}
DNSServiceRefDeallocate(mBrowseRef);
mBrowseStatus = ZC_SERVICE_STOPPED;
mBrowseStatusTS = time(NULL);
return 1;
}
void p3ZeroConf_CallbackResolve( DNSServiceRef sdRef, DNSServiceFlags flags,
uint32_t interfaceIndex, DNSServiceErrorType errorCode,
const char *fullname, const char *hosttarget, uint16_t port,
uint16_t txtLen, const unsigned char *txtRecord, void *context )
{
p3ZeroConf *zc = (p3ZeroConf *) context;
zc->callbackResolve(sdRef, flags, interfaceIndex, errorCode, fullname, hosttarget, port, txtLen, txtRecord);
}
void p3ZeroConf::locked_startResolve(uint32_t idx, std::string name,
std::string regtype, std::string domain)
{
if (mResolveStatus == ZC_SERVICE_ACTIVE)
{
return;
}
std::cerr << "p3ZeroConf::locked_startResolve()";
std::cerr << std::endl;
DNSServiceRef *sdRef = &mResolveRef;
DNSServiceFlags flags = 0;
DNSServiceResolveReply callBack = p3ZeroConf_CallbackResolve;
void *context = (void *) this;
DNSServiceErrorType errcode = DNSServiceResolve(sdRef, flags, idx,
name.c_str(), regtype.c_str(), domain.c_str(), callBack, context);
if (errcode != kDNSServiceErr_NoError)
{
std::cerr << "p3ZeroConf::locked_startResolve() ERROR: ";
std::cerr << displayDNSServiceError(errcode);
std::cerr << std::endl;
}
else
{
mResolveStatus = ZC_SERVICE_ACTIVE;
mResolveStatusTS = time(NULL);
}
}
void p3ZeroConf::callbackResolve( DNSServiceRef /* sdRef */, DNSServiceFlags flags,
uint32_t interfaceIndex, DNSServiceErrorType errorCode,
const char *fullname, const char *hosttarget, uint16_t port,
uint16_t txtLen, const unsigned char *txtRecord)
{
std::cerr << "p3ZeroConf::callbackResolve()";
std::cerr << std::endl;
if (errorCode != kDNSServiceErr_NoError)
{
std::cerr << "p3ZeroConf::callbackResolve() FAILED ERROR: ";
std::cerr << displayDNSServiceError(errorCode);
std::cerr << std::endl;
return;
}
/* handle resolve */
zcResolveResult rr;
rr.flags = flags;
rr.interfaceIndex = interfaceIndex;
rr.fullname = fullname;
rr.hosttarget = hosttarget;
rr.port = ntohs(port);
rr.txtLen = txtLen;
//rr.txtRecord = NULL; //malloc(rr.txtLen);
//memcpy(rr.txtRecord, txtRecord, txtLen);
// We must consume the txtRecord and translate into strings...
std::cerr << "p3ZeroConf::callbackResolve() ";
std::cerr << " flags: " << flags;
std::cerr << " interfaceIndex: " << interfaceIndex;
std::cerr << " fullname: " << fullname;
std::cerr << " hosttarget: " << hosttarget;
std::cerr << " port: " << ntohs(port);
std::cerr << " txtLen: " << txtLen;
std::cerr << std::endl;
std::string peerGpgId;
std::string peerSslId;
if (procPeerTxtRecord(txtLen, txtRecord, peerGpgId, peerSslId))
{
rr.gpgId = peerGpgId;
rr.sslId = peerSslId;
/* check if we care - install ssl record */
int resolve = locked_checkResolvedPeer(rr);
if (resolve)
{
mResolveResults.push_back(rr);
}
}
if (flags & kDNSServiceFlagsMoreComing)
{
std::cerr << "p3ZeroConf::callbackResolve() Expecting More Results.. keeping Ref";
std::cerr << std::endl;
}
else
{
std::cerr << "p3ZeroConf::callbackResolve() Result done.. closing Ref";
std::cerr << std::endl;
locked_stopResolve();
}
}
/* returns if we are interested in the peer */
int p3ZeroConf::locked_checkResolvedPeer(const zcResolveResult &rr)
{
/* if self - drop it */
if ((rr.gpgId == mOwnGpgId) && (rr.sslId == mOwnSslId))
{
std::cerr << "p3ZeroConf::locked_checkpeer() Found Self on LAN:";
std::cerr << std::endl;
std::cerr << "gpgid = " << rr.gpgId;
std::cerr << std::endl;
std::cerr << "sslid = " << rr.sslId;
std::cerr << std::endl;
return 0;
}
/* check if peerGpgId is in structure already */
std::map<std::string, zcPeerDetails>::iterator it;
it = mPeerDetails.find(rr.gpgId);
if (it == mPeerDetails.end())
{
/* possibility we don't have any SSL ID's for this person
* check against AuthGPG()
*/
if ((AuthGPG::getAuthGPG()->isGPGAccepted(rr.gpgId)) || (rr.gpgId == mOwnGpgId))
{
zcPeerDetails newFriend;
newFriend.gpgId = rr.gpgId;
mPeerDetails[rr.gpgId] = newFriend;
it = mPeerDetails.find(rr.gpgId);
}
else
{
std::cerr << "p3ZeroConf::locked_checkpeer() Found Unknown peer on LAN:";
std::cerr << std::endl;
std::cerr << "gpgid = " << rr.gpgId;
std::cerr << std::endl;
std::cerr << "sslid = " << rr.sslId;
std::cerr << std::endl;
return 0;
}
}
/* now see if we have an sslId */
std::map<std::string, zcLocationDetails>::iterator lit;
lit = it->second.mLocations.find(rr.sslId);
if (lit == it->second.mLocations.end())
{
/* install a new location -> flag it as this */
zcLocationDetails loc;
loc.mSslId = rr.sslId;
loc.mStatus = ZC_STATUS_FOUND | ZC_STATUS_NEW_LOCATION;
loc.mPort = rr.port;
loc.mFullName = rr.fullname;
loc.mHostTarget = rr.hosttarget;
loc.mFoundTs = time(NULL);
it->second.mLocations[rr.sslId] = loc;
std::cerr << "p3ZeroConf::locked_checkpeer() Adding New Location for:";
std::cerr << std::endl;
std::cerr << "gpgid = " << rr.gpgId;
std::cerr << std::endl;
std::cerr << "sslid = " << rr.sslId;
std::cerr << std::endl;
std::cerr << "port = " << rr.port;
std::cerr << std::endl;
/* install item in ADD Queue */
zcLocationResult locResult(rr.gpgId, rr.sslId);
mLocationResults.push_back(locResult);
/* return 1, to resolve fully */
return 1;
}
std::cerr << "p3ZeroConf::locked_checkpeer() Updating Location for:";
std::cerr << std::endl;
std::cerr << "gpgid = " << rr.gpgId;
std::cerr << std::endl;
std::cerr << "sslid = " << rr.sslId;
std::cerr << std::endl;
std::cerr << "port = " << rr.port;
std::cerr << std::endl;
lit->second.mStatus |= ZC_STATUS_FOUND;
lit->second.mPort = rr.port;
lit->second.mFullName = rr.fullname;
lit->second.mHostTarget = rr.hosttarget;
lit->second.mFoundTs = time(NULL);
/* otherwise we get here - and we see if we are already connected */
if (lit->second.mStatus & ZC_STATUS_CONNECTED)
{
return 0;
}
return 1;
}
int p3ZeroConf::locked_stopResolve()
{
std::cerr << "p3ZeroConf::locked_stopResolve()";
std::cerr << std::endl;
if (mResolveStatus != ZC_SERVICE_ACTIVE)
{
return 0;
}
DNSServiceRefDeallocate(mResolveRef);
mResolveStatus = ZC_SERVICE_STOPPED;
mResolveStatusTS = time(NULL);
return 1;
}
void p3ZeroConf_CallbackQueryIp( DNSServiceRef sdRef, DNSServiceFlags flags,
uint32_t interfaceIndex, DNSServiceErrorType errorCode,
const char *fullname, uint16_t rrtype, uint16_t rrclass,
uint16_t rdlen, const void *rdata, uint32_t ttl, void *context )
{
p3ZeroConf *zc = (p3ZeroConf *) context;
zc->callbackQueryIp(sdRef, flags, interfaceIndex, errorCode, fullname, rrtype, rrclass, rdlen, rdata, ttl);
}
void p3ZeroConf::locked_startQueryIp(uint32_t idx, std::string hosttarget, std::string gpgId, std::string sslId)
{
if (mQueryStatus == ZC_SERVICE_ACTIVE)
{
return;
}
std::cerr << "p3ZeroConf::locked_startQueryIp()";
std::cerr << std::endl;
std::cerr << "\thosttarget: " << hosttarget;
std::cerr << std::endl;
std::cerr << "\tgpgId: " << gpgId;
std::cerr << std::endl;
std::cerr << "\tsslId: " << sslId;
std::cerr << std::endl;
DNSServiceRef *sdRef = &mQueryRef;
DNSServiceFlags flags = 0;
uint16_t rrtype = kDNSServiceType_A;
uint16_t rrclass = kDNSServiceClass_IN;
DNSServiceQueryRecordReply callBack = p3ZeroConf_CallbackQueryIp;
void *context = (void *) this;
DNSServiceErrorType errcode = DNSServiceQueryRecord(sdRef, flags, idx,
hosttarget.c_str(), rrtype, rrclass, callBack, context);
if (errcode != kDNSServiceErr_NoError)
{
std::cerr << "p3ZeroConf::locked_startQueryIp() ERROR: ";
std::cerr << displayDNSServiceError(errcode);
std::cerr << std::endl;
}
else
{
std::cerr << "p3ZeroConf::locked_startQueryIp() Query Active";
std::cerr << std::endl;
mQueryStatus = ZC_SERVICE_ACTIVE;
mQueryStatusTS = time(NULL);
mQueryGpgId = gpgId;
mQuerySslId = sslId;
}
}
void p3ZeroConf::callbackQueryIp( DNSServiceRef /* sdRef */, DNSServiceFlags flags,
uint32_t interfaceIndex, DNSServiceErrorType errorCode,
const char *fullname, uint16_t rrtype, uint16_t rrclass,
uint16_t rdlen, const void *rdata, uint32_t ttl)
{
std::cerr << "p3ZeroConf::callbackQueryIp()";
std::cerr << std::endl;
/* handle queryIp */
if (errorCode != kDNSServiceErr_NoError)
{
std::cerr << "p3ZeroConf::callbackQueryIp() FAILED ERROR: ";
std::cerr << displayDNSServiceError(errorCode);
std::cerr << std::endl;
return;
}
/* handle resolve */
zcQueryResult qr;
qr.flags = flags;
qr.interfaceIndex = interfaceIndex;
qr.fullname = fullname;
qr.rrtype = rrtype;
qr.rrclass = rrclass;
qr.rdlen = rdlen;
//qr.rdata = NULL; //malloc(rr.rdlen);
//memcpy(rr.rdata, rdata, rdlen);
qr.ttl = ttl;
std::cerr << "p3ZeroConf::callbackQuery() ";
std::cerr << " flags: " << flags;
std::cerr << " interfaceIndex: " << interfaceIndex;
std::cerr << " fullname: " << fullname;
std::cerr << " rrtype: " << rrtype;
std::cerr << " rrclass: " << rrclass;
std::cerr << " rdlen: " << rdlen;
std::cerr << " ttl: " << ttl;
std::cerr << std::endl;
/* add in the query Ids, that we saved... */
qr.sslId = mQuerySslId;
qr.gpgId = mQueryGpgId;
if ((rrtype == kDNSServiceType_A) && (rdlen == 4))
{
// IPV4 type.
sockaddr_storage_clear(qr.addr);
struct sockaddr_in *addr = (struct sockaddr_in *) &(qr.addr);
addr->sin_family = AF_INET;
addr->sin_addr.s_addr = *((uint32_t *) rdata);
addr->sin_port = htons(0);
if (locked_completeQueryResult(qr)) // Saves Query Results, and fills in Port details.
{
mQueryResults.push_back(qr);
}
}
else
{
std::cerr << "p3ZeroConf::callbackQuery() Unknown rrtype";
std::cerr << std::endl;
}
if (flags & kDNSServiceFlagsMoreComing)
{
std::cerr << "p3ZeroConf::callbackQuery() Expecting More Results.. keeping Ref";
std::cerr << std::endl;
}
else
{
std::cerr << "p3ZeroConf::callbackQuery() Result done.. closing Ref";
std::cerr << std::endl;
locked_stopQueryIp();
}
}
/* returns 1 if all is good */
int p3ZeroConf::locked_completeQueryResult(zcQueryResult &qr)
{
/* check if peerGpgId is in structure already */
std::map<std::string, zcPeerDetails>::iterator it;
it = mPeerDetails.find(qr.gpgId);
if (it == mPeerDetails.end())
{
/* Should not be possible to get here! */
std::cerr << "p3ZeroConf::locked_completeQueryResults() Missing GPGID";
std::cerr << std::endl;
return 0;
}
/* now see if we have an sslId */
std::map<std::string, zcLocationDetails>::iterator lit;
lit = it->second.mLocations.find(qr.sslId);
if (lit == it->second.mLocations.end())
{
/* Should not be possible to get here! */
std::cerr << "p3ZeroConf::locked_completeQueryResults() Missing SSLID";
std::cerr << std::endl;
return 0;
}
/*** NOW HAVE FOUND ENTRY, exchange info ****/
std::cerr << "p3ZeroConf::locked_completeQueryResults() Filling in Peer IpAddress";
std::cerr << std::endl;
sockaddr_storage_setport(qr.addr, lit->second.mPort);
lit->second.mAddress = qr.addr;
lit->second.mStatus |= ZC_STATUS_IPADDRESS;
lit->second.mAddrTs = time(NULL);
/* if we have connected? */
if (lit->second.mStatus & ZC_STATUS_CONNECTED)
{
std::cerr << "p3ZeroConf::locked_completeQueryResults() Warning Already Connected";
std::cerr << std::endl;
}
return 1;
}
int p3ZeroConf::locked_stopQueryIp()
{
std::cerr << "p3ZeroConf::locked_stopQueryIp()";
std::cerr << std::endl;
if (mQueryStatus != ZC_SERVICE_ACTIVE)
{
return 0;
}
DNSServiceRefDeallocate(mQueryRef);
mQueryStatus = ZC_SERVICE_STOPPED;
mQueryStatusTS = time(NULL);
return 1;
}
std::string displayDNSServiceError(DNSServiceErrorType errcode)
{
std::string str;
switch(errcode)
{
default:
str = "kDNSServiceErr_??? UNKNOWN-CODE";
break;
case kDNSServiceErr_NoError:
str = "kDNSServiceErr_NoError";
break;
case kDNSServiceErr_Unknown:
str = "kDNSServiceErr_Unknown";
break;
case kDNSServiceErr_NoSuchName:
str = "kDNSServiceErr_NoSuchName";
break;
case kDNSServiceErr_NoMemory:
str = "kDNSServiceErr_NoMemory";
break;
case kDNSServiceErr_BadParam:
str = "kDNSServiceErr_BadParam";
break;
case kDNSServiceErr_BadReference:
str = "kDNSServiceErr_BadReference";
break;
case kDNSServiceErr_BadState:
str = "kDNSServiceErr_BadState";
break;
case kDNSServiceErr_BadFlags:
str = "kDNSServiceErr_BadFlags";
break;
case kDNSServiceErr_Unsupported:
str = "kDNSServiceErr_Unsupported";
break;
case kDNSServiceErr_NotInitialized:
str = "kDNSServiceErr_NotInitialized";
break;
case kDNSServiceErr_AlreadyRegistered:
str = "kDNSServiceErr_AlreadyRegistered";
break;
case kDNSServiceErr_NameConflict:
str = "kDNSServiceErr_NameConflict";
break;
case kDNSServiceErr_Invalid:
str = "kDNSServiceErr_Invalid";
break;
case kDNSServiceErr_Firewall:
str = "kDNSServiceErr_Firewall";
break;
case kDNSServiceErr_Incompatible:
str = "kDNSServiceErr_Incompatible";
break;
case kDNSServiceErr_BadInterfaceIndex:
str = "kDNSServiceErr_BadInterfaceIndex";
break;
case kDNSServiceErr_Refused:
str = "kDNSServiceErr_Refused";
break;
case kDNSServiceErr_NoSuchRecord:
str = "kDNSServiceErr_NoSuchRecord";
break;
case kDNSServiceErr_NoAuth:
str = "kDNSServiceErr_NoAuth";
break;
case kDNSServiceErr_NoSuchKey:
str = "kDNSServiceErr_NoSuchKey";
break;
case kDNSServiceErr_NATTraversal:
str = "kDNSServiceErr_NATTraversal";
break;
case kDNSServiceErr_DoubleNAT:
str = "kDNSServiceErr_DoubleNAT";
break;
case kDNSServiceErr_BadTime:
str = "kDNSServiceErr_BadTime";
break;
case kDNSServiceErr_BadSig:
str = "kDNSServiceErr_BadSig";
break;
case kDNSServiceErr_BadKey:
str = "kDNSServiceErr_BadKey";
break;
case kDNSServiceErr_Transient:
str = "kDNSServiceErr_Transient";
break;
case kDNSServiceErr_ServiceNotRunning:
str = "kDNSServiceErr_ServiceNotRunning";
break;
case kDNSServiceErr_NATPortMappingUnsupported:
str = "kDNSServiceErr_NATPortMappingUnsupported";
break;
case kDNSServiceErr_NATPortMappingDisabled:
str = "kDNSServiceErr_NATPortMappingDisabled";
break;
#if 0
case kDNSServiceErr_NoRouter:
str = "kDNSServiceErr_NoRouter";
break;
case kDNSServiceErr_PollingMode:
str = "kDNSServiceErr_PollingMode";
break;
#endif
}
return str;
}
/***********************************************************************************
* Handle Peer Data, list of friends etc.
*
* We need data structures to handle the Info from libretroshare,
* and the info from ZeroConf too.
*
****/
/* This needs to be a separate class - as we don't know which peer it is
* associated with until we have Resolved the details.
*/
class RsZCBrowseDetails
{
public:
RsZCBrowseDetails();
uint32_t mBrowseState;
time_t mBrowseUpdate;
uint32_t mBrowseInterfaceIndex;
std::string mBrowserServiceName;
std::string mBrowserRegType;
std::string mBrowserReplyDomain;
uint32_t mResolveInterfaceIndex;
std::string mResolveFullname;
std::string mResolveHostTarget;
uint32_t mResolvePort;
std::string mResolveTxtRecord;
};
class RsZCPeerDetails
{
/* passed from libretroshare */
std::string mGpgId;
std::string mSslId;
uint32_t mPeerStatus; /* FRIEND, FOF, ONLINE, OFFLINE */
/* Browse Info */
uint32_t mBrowseState;
time_t mBrowseUpdate;
uint32_t mBrowseInterfaceIndex;
std::string mBrowserServiceName;
std::string mBrowserRegType;
std::string mBrowserReplyDomain;
/* Resolve Info */
uint32_t mResolveInterfaceIndex;
std::string mResolveFullname;
std::string mResolveHostTarget;
uint32_t mResolvePort;
std::string mResolveTxtRecord;
};