/* * libretroshare/src/services: p3disc.cc * * Services 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/p3disc.h" #include "pqi/p3authmgr.h" #include "pqi/p3connmgr.h" #include #include #include const uint32_t AUTODISC_LDI_SUBTYPE_PING = 0x01; const uint32_t AUTODISC_LDI_SUBTYPE_RPLY = 0x02; #include #include "pqi/pqidebug.h" const int pqidisczone = 2482; static int updateAutoServer(autoserver *as, RsDiscItem *di); static int convertTDeltaToTRange(double tdelta); static int convertTRangeToTDelta(int trange); static int updateCertAvailabilityFlags(cert *c, unsigned long discFlags); static unsigned long determineCertAvailabilityFlags(cert *c); // Operating System specific includes. #include "pqi/pqinetwork.h" p3disc::p3disc(p3AuthMgr *am, p3ConnectMgr *cm) :p3Service(RS_SERVICE_TYPE_DISC), mAuthMgr(am), mConnMgr(cm) { addSerialType(new RsDiscSerialiser()); ldata = NULL; ldlenmax = 1024; local_disc = false; //true; remote_disc = true; // set last check to current time, this prevents queued. // messages at the start! (actually shouldn't matter - as they aren't connected). ts_lastcheck = time(NULL); // 0; // configure... load_configuration(); localSetup(); return; } p3disc::~p3disc() { return; } int p3disc::tick() { pqioutput(PQL_DEBUG_ALL, pqidisczone, "p3disc::tick()"); if (local_disc) { if (ts_nextlp == 0) { pqioutput(PQL_DEBUG_ALL, pqidisczone, "Local Discovery On!"); localPing(baddr); localListen(); } } else { pqioutput(PQL_DEBUG_ALL, pqidisczone, "Local Discovery Off!"); } // ten minute counter. if (--ts_nextlp < 0) { ts_nextlp = 600; } if (ts_nextlp % 300 == 0) idServers(); /* remote discovery can run infrequently.... * this is a good idea, as it ensures that * multiple Pings aren't sent to neighbours.... * * only run every 5 seconds. */ if (ts_nextlp % 5 != 0) { return 1; } // important bit int nr = handleReplies(); // discards packets if not running. if (remote_disc) { pqioutput(PQL_DEBUG_ALL, pqidisczone, "Remote Discovery On!"); newRequests(); if ((sroot -> collectedCerts()) || (nr > 0)) { distillData(); } } else { pqioutput(PQL_DEBUG_ALL, pqidisczone, "Remote Discovery Off!"); } return 1; } static int local_disc_def_port = 7770; static int local_disc_secondary_port = 7870; int p3disc::setLocalAddress(struct sockaddr_in srvaddr) { saddr = srvaddr; return 1; } int p3disc::determineLocalNetAddr() { // laddr filled in by load_configuration. laddr.sin_port = htons(local_disc_def_port); /********************************** WINDOWS/UNIX SPECIFIC PART ******************/ #ifndef WINDOWS_SYS // ie UNIX // broadcast address. baddr.sin_family = AF_INET; inet_aton("0.0.0.0", &(baddr.sin_addr)); baddr.sin_port = htons(local_disc_def_port); #else // WIN baddr. sin_family = AF_INET; // So as recommended on this site.. will use |+& to calc it. unsigned long netmask = inet_addr("255.255.255.0"); unsigned long netaddr = saddr.sin_addr.s_addr & netmask; baddr.sin_addr.s_addr = netaddr | (~netmask); // direct works! //baddr.sin_addr.s_addr = inet_addr("10.0.0.59"); //baddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // broadcast! baddr.sin_addr.s_addr = INADDR_BROADCAST; baddr.sin_port = htons(local_disc_def_port); #endif /********************************** WINDOWS/UNIX SPECIFIC PART ******************/ { std::ostringstream out; out << "p3disc::determineLocalNetAddr() baddr: "; out << inet_ntoa(baddr.sin_addr) << std::endl; pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); } return 1; } int p3disc::setupLocalPacket(int type, struct sockaddr_in *home, struct sockaddr_in *server) { if (ldata == NULL) { ldata = malloc(ldlenmax); } // setup packet. // 8 bytes - tag ((char *) ldata)[0] = 'P'; ((char *) ldata)[1] = 'Q'; ((char *) ldata)[2] = 'I'; ((char *) ldata)[3] = 'L'; if (type == AUTODISC_LDI_SUBTYPE_PING) { ((char *) ldata)[4] = 'D'; ((char *) ldata)[5] = 'I'; ((char *) ldata)[6] = 'S'; ((char *) ldata)[7] = 'C'; } else { ((char *) ldata)[4] = 'R'; ((char *) ldata)[5] = 'P'; ((char *) ldata)[6] = 'L'; ((char *) ldata)[7] = 'Y'; } // sockaddr copy. ldlen = 8; for(unsigned int i = 0; i < sizeof(*home); i++) { ((char *) ldata)[ldlen + i] = ((char *) home)[i]; } ldlen += sizeof(*home); for(unsigned int i = 0; i < sizeof(*server); i++) { ((char *) ldata)[ldlen + i] = ((char *) server)[i]; } ldlen += sizeof(*server); return 1; } int p3disc::localSetup() { if (!local_disc) { pqioutput(PQL_DEBUG_BASIC, pqidisczone, "p3disc::localSetup() Warning local_disc OFF!"); return -1; } //First we must attempt to open the default socket determineLocalNetAddr(); int err = 0; lsock = socket(PF_INET, SOCK_DGRAM, 0); /********************************** WINDOWS/UNIX SPECIFIC PART ******************/ #ifndef WINDOWS_SYS // ie UNIX if (lsock < 0) { pqioutput(PQL_DEBUG_BASIC, pqidisczone, "p3disc::localSetup() Cannot open UDP socket!"); local_disc = false; return -1; } err = fcntl(lsock, F_SETFL, O_NONBLOCK); if (err < 0) { pqioutput(PQL_DEBUG_BASIC, pqidisczone, "p3disc::localSetup() Error: Cannot make socket NON-Blocking: "); local_disc = false; return -1; } int on = 1; if(0 != (err =setsockopt(lsock, SOL_SOCKET, SO_BROADCAST,(void *) &on, sizeof(on)))) { pqioutput(PQL_DEBUG_BASIC, pqidisczone, "p3disc::localSetup() Error: Cannot make socket Broadcast: "); local_disc = false; return -1; } else { pqioutput(PQL_DEBUG_BASIC, pqidisczone, "p3disc::localSetup() Broadcast Flag Set!"); } /********************************** WINDOWS/UNIX SPECIFIC PART ******************/ #else //WINDOWS_SYS if (lsock == INVALID_SOCKET) { pqioutput(PQL_DEBUG_BASIC, pqidisczone, "p3disc::localSetup() Cannot open UDP socket!"); local_disc = false; return -1; } unsigned long int on = 1; if (0 != (err = ioctlsocket(lsock, FIONBIO, &on))) { pqioutput(PQL_DEBUG_BASIC, pqidisczone, "p3disc::localSetup() Error: Cannot make socket NON-Blocking: "); local_disc = false; return -1; } on = 1; if(0 != (err=setsockopt(lsock, SOL_SOCKET, SO_BROADCAST,(char *) &on, sizeof(on)))) { pqioutput(PQL_DEBUG_BASIC, pqidisczone, "p3disc::localSetup() Error: Cannot make socket Broadcast: "); local_disc = false; return -1; } else { pqioutput(PQL_DEBUG_BASIC, pqidisczone, "p3disc::localSetup() Broadcast Flag Set!"); } #endif /********************************** WINDOWS/UNIX SPECIFIC PART ******************/ { std::ostringstream out; out << "p3disc::localSetup()" << std::endl; out << "\tSetup Family: " << laddr.sin_family; out << std::endl; out << "\tSetup Address: " << inet_ntoa(laddr.sin_addr); out << std::endl; out << "\tSetup Port: " << ntohs(laddr.sin_port) << std::endl; pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); } if (0 != (err = bind(lsock, (struct sockaddr *) &laddr, sizeof(laddr)))) { std::ostringstream out; out << "p3disc::localSetup()"; out << " Cannot Bind to Default Address!" << std::endl; showSocketError(out); out << std::endl; out << " Trying Secondary Address." << std::endl; pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); } else { // ifsucessful then call localPing // set ts to -1 and don't worry about outgoing until // we receive a packet std::ostringstream out; out << "p3disc::localSetup()" << std::endl; out << " Bound to Address." << std::endl; out << "\tSetup Address: " << inet_ntoa(laddr.sin_addr); out << std::endl; out << "\tSetup Port: " << ntohs(laddr.sin_port) << std::endl; pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); ts_nextlp = -1; ts_nextlp = 10; localPing(baddr); return 1; } laddr.sin_port = htons(local_disc_secondary_port); if (0 != (err = bind(lsock, (struct sockaddr *) &laddr, sizeof(laddr)))) { std::ostringstream out; out << "p3disc::localSetup()"; out << " Cannot Bind to Secondary Address!" << std::endl; showSocketError(out); out << std::endl; out << " Giving Up!" << std::endl; pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); local_disc = false; return -1; } else { std::ostringstream out; out << "p3disc::localSetup()" << std::endl; out << " Bound to Secondary Address." << std::endl; out << "\tSetup Address: " << inet_ntoa(laddr.sin_addr); out << std::endl; out << "\tSetup Port: " << ntohs(laddr.sin_port) << std::endl; pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); ts_nextlp = 10; localPing(baddr); return 1; } // else we open a random port and set the timer // ie - don't bind to a port..... ts_nextlp = 10; // ping every 10 minutes. localPing(baddr); return 1; } int p3disc::localPing(struct sockaddr_in reply_to) { //This function sends a meessage out containing both cert // and server address, as well as the ping address (if not standard) // so we send a packet out to that address // (most likely broadcast address). // setup up the data for connection. setupLocalPacket(AUTODISC_LDI_SUBTYPE_PING,&laddr, &saddr); // Cast to char for windows benefit. int len = sendto(lsock, (char *) ldata, ldlen, 0, (struct sockaddr *) &reply_to, sizeof(reply_to)); if (len != ldlen) { std::ostringstream out; out << "p3disc::localPing()"; out << " Failed to send Packet." << std::endl; out << "Sent (" << len << "/" << ldlen; out << std::endl; out << "Addr:" << inet_ntoa(reply_to.sin_addr) << std::endl; out << "Port:" << ntohs(reply_to.sin_port) << std::endl; out << std::endl; pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); } else { std::ostringstream out; out << "p3disc::localPing() Success!" << std::endl; out << "Sent To Addr:" << inet_ntoa(reply_to.sin_addr) << std::endl; out << "Sent To Port:" << ntohs(reply_to.sin_port) << std::endl; out << "Message Size: " << len << std::endl; pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); } return 1; } int p3disc::localReply(struct sockaddr_in reply_to) { //This function sends a meessage out containing both cert // and server address, as well as the ping address (if not standard) // so we send a packet out to that address // (most likely broadcast address). // setup up the data for connection. setupLocalPacket(AUTODISC_LDI_SUBTYPE_RPLY,&laddr, &saddr); // Cast to char for windows benefit. int len = sendto(lsock, (char *) ldata, ldlen, 0, (struct sockaddr *) &reply_to, sizeof(reply_to)); if (len != ldlen) { std::ostringstream out; out << "p3disc::localPing()"; out << " Failed to send Packet." << std::endl; pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); } return 1; } int p3disc::localListen() { //This function listens to the ping address. //For each reply, store the result in the structure and mark as local struct sockaddr_in addr; struct sockaddr_in neighbour; struct sockaddr_in server; socklen_t alen = sizeof(addr); int nlen = sizeof(neighbour); int len; int size = 0; while(0 < (size = recvfrom(lsock, (char *) ldata, ldlen, 0, (struct sockaddr *) &addr, &alen))) { std::ostringstream out; out << "Recved Message" << std::endl; out << "From Addr:" << inet_ntoa(addr.sin_addr) << std::endl; out << "From Port:" << ntohs(addr.sin_port) << std::endl; out << "Message Size: " << size << std::endl; for(int i = 0; i < 8; i++) { out << ((char *) ldata)[i]; } out << std::endl; len = 8; // sockaddr copy. for(int i = 0; i < nlen; i++) { ((char *) &neighbour)[i] = ((char *) ldata)[len + i]; } len += nlen; for(int i = 0; i < nlen; i++) { ((char *) &server)[i] = ((char *) ldata)[len + i]; } len += nlen; out << "Neighbour Addr:" << inet_ntoa(neighbour.sin_addr) << std::endl; out << "Neighbour Port:" << ntohs(neighbour.sin_port) << std::endl; out << "Server Addr:" << inet_ntoa(server.sin_addr) << std::endl; out << "Server Port:" << ntohs(server.sin_port) << std::endl; if ((laddr.sin_addr.s_addr == neighbour.sin_addr.s_addr) && (laddr.sin_port == neighbour.sin_port)) { // Then We Sent it!!!! // ignore.. out << "Found Self! Addr - " << inet_ntoa(neighbour.sin_addr); out << ":" << ntohs(neighbour.sin_port) << std::endl; } else { if ('D' == (((char *) ldata)[4])) // Then Ping. { // reply. localReply(neighbour); } addLocalNeighbour(&neighbour, &server); } pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); } /********************************** WINDOWS/UNIX SPECIFIC PART ******************/ #ifndef WINDOWS_SYS // ie UNIX if ((size < 0) && (errno != EAGAIN)) { std::ostringstream out; out << "Error Recieving Message" << std::endl; out << "Errno: " << errno << std::endl; out << socket_errorType(errno) << std::endl; pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); } /********************************** WINDOWS/UNIX SPECIFIC PART ******************/ #else // WINDOWS_SYS if (size == SOCKET_ERROR) { int err = WSAGetLastError(); if (err != WSAEWOULDBLOCK) { std::ostringstream out; out << "Error Recieving Message" << std::endl; out << "WSE: " << err << std::endl; pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); } } #endif /********************************** WINDOWS/UNIX SPECIFIC PART ******************/ return 1; } // This needs to be fixed up.... // Local dicsovery disabled for the moment.... int p3disc::addLocalNeighbour(struct sockaddr_in *n, struct sockaddr_in *s) { std::list::iterator it; for(it = neighbours.begin(); it != neighbours.end(); it++) { // if the server address matches one already! // make sure its flags as local and return. if (0 == memcmp((char *) &((*it) -> server_addr), (char *) s, sizeof(*s))) { (*it) -> local = true; return 1; } } // else add it in! autoneighbour *ln = new autoneighbour(); ln -> server_addr = (*s); ln -> local = true; ln -> id = NULL; // null cert std::string nname = "Local Neighbour ("; nname += inet_ntoa(ln -> server_addr.sin_addr); nname += ")"; //ln -> id -> Name(nname); // now we call the dummy connect... // this will only be done once per local neighbour. // connectForExchange(ln -> server_addr); neighbours.push_back(ln); // update dicovered. distillData(); return 1; } // Code Fragment that might be useful when local is patched up.... /**************************************************** int p3disc::distillLocalData() { // This transforms the autoneighbour tree into // a list of certificates with the best guess settings. discovered.clear(); pqioutput(PQL_DEBUG_BASIC, pqidisczone, "p3disc::distillData()"); std::list::iterator it; std::list::iterator it2; // Now check for local -> remote duplicates.... for(it = neighbours.begin(); it != neighbours.end();) { cert *c = (cert *) ((*it) -> id); if (((*it) -> local) && (c == NULL)) { // potentially a duplicate. bool found = false; for(it2 = neighbours.begin(); it2 != neighbours.end(); it2++) { // if address is the same -> remove first version. if ((it != it2) && (0 == memcmp((char *) &((*it) -> addr), (char *) &((*it2) -> addr), sizeof(struct sockaddr)))) { (*it2) -> local = true; found = true; } } if (found == true) { // remove the certless local. it = neighbours.erase(it); } else { it++; } } else { it++; } } ******************************************/ int p3disc::idServers() { std::list::iterator it; std::list::iterator nit; int cts = time(NULL); std::ostringstream out; out << "::::AutoDiscovery Neighbours::::" << std::endl; for(it = neighbours.begin(); it != neighbours.end(); it++) { if ((*it) -> local) { out << "Local Neighbour: "; } else { out << "Friend of a friend: "; } cert *c = (cert *) ((*it) -> id); if (c != NULL) { if (c -> certificate != NULL) { out << c -> certificate -> name; } else { out << c -> Name(); } } else { out << "UnIdentified"; } out << std::endl; out << "BG LocalAddr: "; out << inet_ntoa((*it) -> local_addr.sin_addr); out << ":" << ntohs((*it) -> local_addr.sin_port) << std::endl; out << "BG Server: "; out << inet_ntoa((*it) -> server_addr.sin_addr); out << ":" << ntohs((*it) -> server_addr.sin_port) << std::endl; out << " Listen TR: "; if (((*it) -> listen) && ((*it) -> l_ts)) { out << cts - (*it) -> l_ts << " sec ago"; } else { out << "Never"; } out << " "; out << "Connect TR: "; if (((*it) -> connect) && ((*it) -> c_ts)) { out << cts - (*it) -> c_ts << " sec ago"; } else { out << "Never"; } if ((*it) -> active) { out << " Active!!!"; } out << std::endl; out << " -->DiscFlags: 0x" << std::hex << (*it)->discFlags; out << std::dec << std::endl; for(nit = ((*it) -> neighbour_of).begin(); nit != ((*it) -> neighbour_of).end(); nit++) { out << "\tConnected via: "; if ((*nit) -> id != NULL) { out << ((*nit) ->id) -> Name() << "("; out << inet_ntoa(((*nit) -> id) -> lastaddr.sin_addr); out << ":" << ntohs(((*nit) -> id) -> lastaddr.sin_port); out << ")"; } out << std::endl; out << "\t\tServer: "; out << inet_ntoa((*nit) -> server_addr.sin_addr); out <<":"<< ntohs((*nit) -> server_addr.sin_port); out << std::endl; out << "\t\tLocalAddr: "; out << inet_ntoa((*nit) -> local_addr.sin_addr); out <<":"<< ntohs((*nit) -> local_addr.sin_port); out << std::endl; if ((*nit) -> listen) { out << "\t\tListen TR:"; out << cts - (*nit) -> l_ts << " sec ago"; } else { out << "\t\tNever Received!"; } out << std::endl; if ((*nit) -> connect) { out << "\t\tConnect TR:"; out << cts - (*nit) -> c_ts << " sec ago"; } else { out << "\t\tNever Connected!"; } out << std::endl; out << "\t\tDiscFlags: 0x" << std::hex << (*nit)->discFlags; out << std::dec << std::endl; } } pqioutput(PQL_WARNING, pqidisczone, out.str()); return 1; } int p3disc::newRequests() { // Check the timestamp against the list of certs. // If any are newer and currently active, then // send out Discovery Request. // This initiates the p3disc procedure. if (!remote_disc) { pqioutput(PQL_DEBUG_ALL, pqidisczone, "p3disc::newRequests() Remote Discovery is turned off"); return -1; } pqioutput(PQL_DEBUG_ALL, pqidisczone, "p3disc::newRequests() checkin for new neighbours"); // Perform operation on the cert list. std::list::iterator it; // Temp variable std::list &certlist = sroot -> getCertList(); { std::ostringstream out; out << "Checking CertList!" << std::endl; out << "last_check: " << ts_lastcheck; out << " time(): " << time(NULL); pqioutput(PQL_DEBUG_ALL, pqidisczone, out.str()); } for(it = certlist.begin(); it != certlist.end(); it++) { { std::ostringstream out; out << "Cert: " << (*it) -> Name(); out << " lc_ts: " << (*it) -> lc_timestamp; out << " lr_ts: " << (*it) -> lr_timestamp; pqioutput(PQL_DEBUG_ALL, pqidisczone, out.str()); } // This should be Connected(), rather than Accepted(). // should reply with all Accepted(), but only send to all connected(). // if (((*it) -> Accepted()) && // // need >= to ensure that it will happen, // about 1 in 5 chance of multiple newRequests if called every 5 secs. // can live with this. (else switch to fractional seconds). if (((*it) -> Connected()) && (((*it) -> lc_timestamp >= ts_lastcheck) || ((*it) -> lr_timestamp >= ts_lastcheck))) { // also must not have already sent message. // (unless reconnection?) // actually - this should occur, even if last // exchange not complete. // reconnect /***************************************************************************** * No more need for ad_init silliness.... * //if (ad_init.end() == // find(ad_init.begin(),ad_init.end(),*it)) // infact - we need the opposite behaviour. // remove if in the init list. std::list::iterator it2; if (ad_init.end() != (it2 = find(ad_init.begin(),ad_init.end(),*it))) { ad_init.erase(it2); } * * * ****************************************************************************/ { // Then send message. { std::ostringstream out; out << "p3disc::newRequests()"; out << "Constructing a Message!" << std::endl; out << "Sending to: " << (*it) -> Name(); out << " lc_ts: " << (*it) -> lc_timestamp; out << " lr_ts: " << (*it) -> lr_timestamp; pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); } // Construct a message RsDiscItem *di = new RsDiscItem(); // get our details..... cert *own = sroot -> getOwnCert(); // Fill the message di -> PeerId((*it) -> PeerId()); di -> laddr = own -> localaddr; di -> saddr = own -> serveraddr; // if we are firewalled..... (and no forwarding...) // set received as impossible. if (own -> Firewalled() && (!(own -> Forwarded()))) di -> receive_tr = 0; /* invalid */ else di -> receive_tr = 1; /* zero time */ di -> connect_tr = 1; /* zero time */ di -> discFlags = determineCertAvailabilityFlags(own); // Send off message sendItem(di); /***************************************************************************** * No more need for ad_init silliness.... // push onto init list. ad_init.push_back(*it); * ****************************************************************************/ // Finally we should also advertise the // new connection to our neighbours???? // SHOULD DO - NOT YET. } } } ts_lastcheck = time(NULL); return 1; } int p3disc::handleReplies() { RsItem *item = NULL; pqioutput(PQL_DEBUG_ALL, pqidisczone, "p3disc::handleReplies()"); // if off discard item. if (!remote_disc) { while(NULL != (item = recvItem())) { std::ostringstream out; out << "p3disc::handleReplies()"; out << " Deleting - Cos RemoteDisc Off!" << std::endl; item -> print(out); pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); delete item; } return 0; } int nhandled = 0; // While messages read while(NULL != (item = recvItem())) { RsDiscItem *di = NULL; RsDiscReply *dri = NULL; if (NULL == (di = dynamic_cast (item))) { std::ostringstream out; out << "p3disc::handleReplies()"; out << "Deleting Non RsDiscItem Msg" << std::endl; item -> print(out); pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); // delete and continue to next loop. delete item; continue; } nhandled++; { std::ostringstream out; out << "p3disc::handleReplies()"; out << " Received Message!" << std::endl; di -> print(out); pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); } // if discovery reply then respondif haven't already. if (NULL != (dri = dynamic_cast (di))) { // add to data tree. handleDiscoveryData(dri); } else /* Ping */ { handleDiscoveryPing(di); /* find the certificate */ certsign sign; convert_to_certsign(di->PeerId(), sign); cert *peer = getSSLRoot() -> findcertsign(sign); if (peer) { sendDiscoveryReply(peer); pqioutput(PQL_DEBUG_BASIC, pqidisczone, "After Reply to Ping"); } else { pqioutput(PQL_ALERT, pqidisczone, "Failed to Match disc Ping ID"); } } delete di; } return nhandled; } int p3disc::sendDiscoveryReply(cert *p) { if (!remote_disc) return -1; // So to send a discovery reply .... we need to.... // 1) generate a list of our neighbours..... pqioutput(PQL_DEBUG_BASIC, pqidisczone, "p3disc::sendDiscoveryReply() Generating Messages!"); std::list::iterator it; // Temp variable std::list &certlist = sroot -> getCertList(); int good_certs = 0; int cts = time(NULL); for(it = certlist.begin(); it != certlist.end(); it++) { // if accepted and has connected (soon) if ((*it) -> Accepted()) { good_certs++; { std::ostringstream out; out << "p3disc::sendDiscoveryReply()"; out << " Found Neighbour Cert!" << std::endl; out << "Encoding: "<<(*it)->Name() << std::endl; out << "Encoding(2): "<<(*it)->certificate->name << std::endl; pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); } // Construct a message RsDiscReply *di = new RsDiscReply(); // Fill the message // Set Target as input cert. di -> PeerId(p -> PeerId()); // set the server address. di -> laddr = (*it) -> localaddr; di -> saddr = (*it) -> serveraddr; // set the timeframe since last connection. if ((*it) -> lr_timestamp <= 0) { di -> receive_tr = 0; } else { di -> receive_tr = convertTDeltaToTRange(cts - (*it) -> lr_timestamp); } if ((*it) -> lc_timestamp <= 0) { di -> connect_tr = 0; } else { di -> connect_tr = convertTDeltaToTRange(cts - (*it) -> lc_timestamp); } di -> discFlags = determineCertAvailabilityFlags(*it); // actually ned to copy certificate to array // for proper cert stuff. /**************** PQI_USE_XPGP ******************/ #if defined(PQI_USE_XPGP) int len = i2d_XPGP((*it) -> certificate, (unsigned char **) &(di -> certDER.bin_data)); #else /* X509 Certificates */ /**************** PQI_USE_XPGP ******************/ int len = i2d_X509((*it) -> certificate, (unsigned char **) &(di -> certDER.bin_data)); #endif /* X509 Certificates */ /**************** PQI_USE_XPGP ******************/ if (len > 0) { di -> certDER.bin_len = len; std::ostringstream out; out << "Cert Encoded(" << len << ")" << std::endl; pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); } else { pqioutput(PQL_DEBUG_BASIC, pqidisczone, "Failed to Encode Cert"); di -> certDER.bin_len = 0; } // Send off message sendItem(di); pqioutput(PQL_DEBUG_BASIC, pqidisczone, "Sent DI Message"); } else { std::ostringstream out; out << "p3disc::sendDiscoveryReply()"; out << "Not Sending Cert: " << std::endl; out << (*it) -> Name() << std::endl; pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); } } { std::ostringstream out; out << "p3disc::sendDiscoveryReply()"; out << "Found " << good_certs << " Certs" << std::endl; pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); } return 1; } int p3disc::handleDiscoveryPing(RsDiscItem *di) { std::list::iterator it; // as already connected.... certificate available. certsign sign; convert_to_certsign(di->PeerId(), sign); cert *c = getSSLRoot() -> findcertsign(sign); if (c == NULL) return -1; { std::ostringstream out; out << "p3disc::handleDiscoveryPing()" << std::endl; di -> print(out); out << "RECEIVED Self Describing RsDiscItem!"; out << std::endl; pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); } // The first check is whether this packet came from // the cert in the reply. // Local address is always right! // No User control anyway! c -> localaddr = di -> laddr; // The Rest of this should only be set // if we are in autoconnect mode..... // else should be done manually. // ----> Think we should do this always (is disc from then) /**************************** if (!(c -> Manual())) ****************************/ { // if the connect addr isn't valid. if (!isValidNet(&(c -> lastaddr.sin_addr))) { // set it all c -> serveraddr = di -> saddr; pqioutput(PQL_WARNING, pqidisczone, "lastaddr !Valid -> serveraddr=di->saddr"); } // if the connect addr == dispkt.local else if (0 == inaddr_cmp(c -> lastaddr, di -> laddr)) { // set it all c -> serveraddr = di -> saddr; c -> Local(true); pqioutput(PQL_WARNING, pqidisczone, "lastaddr=di->laddr -> Local & serveraddr=di->saddr"); } else if (0 == inaddr_cmp(c -> lastaddr, di -> saddr)) { pqioutput(PQL_WARNING, pqidisczone, "lastaddr=di->saddr -> !Local & serveraddr=di->saddr"); c -> serveraddr = di -> saddr; c -> Local(false); } else { pqioutput(PQL_WARNING, pqidisczone, "lastaddr!=(di->laddr|di->saddr) -> !Local,serveraddr left"); c -> Local(false); } updateCertAvailabilityFlags(c, di->discFlags); } /**************************** else { pqioutput(PQL_WARNING, pqidisczone, "peer is Manual -> leaving server settings"); if (0 == inaddr_cmp(c -> lastaddr, di -> laddr)) { pqioutput(PQL_WARNING, pqidisczone, "c->lastaddr=di->laddr -> local"); c -> Local(true); } else { pqioutput(PQL_WARNING, pqidisczone, "c->lastaddr!=di->laddr -> !local"); c -> Local(false); } } ****************************/ // Now add it into the system. // check if it exists already...... for(it = neighbours.begin(); it != neighbours.end(); it++) { cert *c2 = (cert *) (*it) -> id; /**************** PQI_USE_XPGP ******************/ #if defined(PQI_USE_XPGP) if ((c2 != NULL) && (0 == XPGP_cmp( c -> certificate, c2 -> certificate))) #else /* X509 Certificates */ /**************** PQI_USE_XPGP ******************/ if ((c2 != NULL) && (0 == X509_cmp( c -> certificate, c2 -> certificate))) #endif /* X509 Certificates */ /**************** PQI_USE_XPGP ******************/ { // matching.... // update it....; pqioutput(PQL_DEBUG_BASIC, pqidisczone, "Updating Certificate (AN)!"); (*it)-> local = c -> Local(); updateAutoServer((*it), di); /* now look through the neighbours_of */ std::list::iterator nit; for(nit = ((*it) -> neighbour_of).begin(); nit != ((*it) -> neighbour_of).end(); nit++) { /* check if we already have a autoserver.... */ if ((*it)->id == (*nit)->id) { /* we already have one */ // update it....; pqioutput(PQL_DEBUG_BASIC, pqidisczone, "Updating Certificate (AS)!"); updateAutoServer(*nit, di); return 0; } } pqioutput(PQL_DEBUG_BASIC, pqidisczone, "Adding Certificate (AS)!"); /* if we get here, we need to add an autoserver */ autoserver *as = new autoserver(); as -> id = c; updateAutoServer(as, di); (*it) -> neighbour_of.push_back(as); return 1; } } // if get here must add a autoneighbour + an autoserver. autoneighbour *an = new autoneighbour(); an -> id = c; an -> local = c -> Local(); updateAutoServer(an, di); // add autoserver to an. autoserver *as = new autoserver(); as -> id = c; updateAutoServer(as, di); an -> neighbour_of.push_back(as); neighbours.push_back(an); return 1; } int p3disc::handleDiscoveryData(RsDiscReply *di) { std::list::iterator it; { std::ostringstream out; out << "p3disc::handleDiscoveryData()" << std::endl; di -> print(out); pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); } certsign sign; convert_to_certsign(di->PeerId(), sign); cert *di_peer = getSSLRoot() -> findcertsign(sign); if (!di_peer) { std::ostringstream out; out << "p3disc::handleDiscoveryData() BAD Id" << std::endl; di -> print(out); pqioutput(PQL_ALERT, pqidisczone, out.str()); delete di; return 0; } /* WIN/LINUX Difference. */ /********************************** WINDOWS/UNIX SPECIFIC PART ******************/ #ifndef WINDOWS_SYS // ie UNIX const unsigned char *certptr = (const unsigned char *) di -> certDER.bin_data; #else unsigned char *certptr = (unsigned char *) di -> certDER.bin_data; #endif /********************************** WINDOWS/UNIX SPECIFIC PART ******************/ // load up the certificate..... /**************** PQI_USE_XPGP ******************/ #if defined(PQI_USE_XPGP) XPGP *tmp = NULL; XPGP *xpgp = d2i_XPGP(&tmp, (unsigned char **) &certptr, di -> certDER.bin_len); if (xpgp == NULL) return -1; { std::ostringstream out; out << "p3disc::handleDiscoveryData()" << std::endl; out << "certificate name: " << xpgp -> name << std::endl; pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); } // if a duplicate with ad/or sslroot; cert *c = sroot -> makeCertificateXPGP(xpgp); if (c == NULL) { pqioutput(PQL_DEBUG_BASIC, pqidisczone, "Failed to Create Certificate"); // delete the cert. XPGP_free(xpgp); return -1; } #else /* X509 Certificates */ /**************** PQI_USE_XPGP ******************/ X509 *tmp = NULL; X509 *x509 = d2i_X509(&tmp, &certptr, di -> certLen); if (x509 == NULL) return -1; { std::ostringstream out; out << "p3disc::handleDiscoveryData()" << std::endl; out << "certificate name: " << x509 -> name << std::endl; pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); } // if a duplicate with ad/or sslroot; cert *c = sroot -> makeCertificate(x509); if (c == NULL) { pqioutput(PQL_DEBUG_BASIC, pqidisczone, "Failed to Create Certificate"); // delete the cert. X509_free(x509); return -1; } #endif /* X509 Certificates */ /**************** PQI_USE_XPGP ******************/ // So have new/existing cert; // check if it exists already...... for(it = neighbours.begin(); it != neighbours.end(); it++) { cert *c2 = (cert *) (*it) -> id; /**************** PQI_USE_XPGP ******************/ #if defined(PQI_USE_XPGP) if ((c2 != NULL) && (0 == XPGP_cmp( c -> certificate, c2 -> certificate))) #else /* X509 Certificates */ /**************** PQI_USE_XPGP ******************/ if ((c2 != NULL) && (0 == X509_cmp( c -> certificate, c2 -> certificate))) #endif /* X509 Certificates */ /**************** PQI_USE_XPGP ******************/ { // matching.... check neighbours of.... // for the source of the message. std::list::iterator nit; for(nit = ((*it) -> neighbour_of).begin(); nit != ((*it) -> neighbour_of).end(); nit++) { /**************** PQI_USE_XPGP ******************/ #if defined(PQI_USE_XPGP) if (0 == XPGP_cmp( #else /* X509 Certificates */ /**************** PQI_USE_XPGP ******************/ if (0 == X509_cmp( #endif /* X509 Certificates */ /**************** PQI_USE_XPGP ******************/ ((cert *) (*nit) -> id) -> certificate, di_peer -> certificate)) { // update it....; pqioutput(PQL_DEBUG_BASIC, pqidisczone, "Updating Certificate!"); updateAutoServer(*nit, di); return 0; } } // if we get to here - add neighbour of info. autoserver *as = new autoserver(); as -> id = di_peer; // add in some more ....as -> addr = (di -> ); updateAutoServer(as, di); (*it) -> neighbour_of.push_back(as); return 1; } } // if get here must add a autoneighbour + autoserver. { std::ostringstream out; out << "p3disc::handleDiscoveryData()" << std::endl; out << "Adding New AutoNeighbour:" << c -> Name() << std::endl; pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); } autoneighbour *an = new autoneighbour(); an -> id = c; // initial guess. an -> local_addr = di -> laddr; an -> server_addr = di -> saddr; an -> local = false; autoserver *as = new autoserver(); as -> id = di_peer; updateAutoServer(as, di); an -> neighbour_of.push_back(as); neighbours.push_back(an); return 1; } int p3disc::collectCerts() { // First get any extras from the CollectedCerts Queue. // if the cert matches an existing one.... update + discard // else add in.... std::list::iterator it; std::list::iterator it2; cert *nc; while(NULL != (nc = sroot -> getCollectedCert())) { // check for matching certs. bool found = false; { std::ostringstream out; out << "p3disc::collectCert: " << std::endl; out << "Name: " << nc -> Name() << std::endl; out << "CN: " << nc -> certificate -> name << std::endl; out << " From: "; out << inet_ntoa(nc -> lastaddr.sin_addr); out << ":" << ntohs(nc -> lastaddr.sin_port) << std::endl; out << " Local: "; out << inet_ntoa(nc -> localaddr.sin_addr); out << ":" << ntohs(nc -> localaddr.sin_port) << std::endl; out << " Server: "; out << inet_ntoa(nc -> serveraddr.sin_addr); out << ":" << ntohs(nc -> serveraddr.sin_port) << std::endl; out << " Listen TS:"; out << nc -> lr_timestamp << " "; out << "Connect TR:"; out << nc -> lc_timestamp << std::endl; out << std::endl; pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); } for(it = neighbours.begin(); (!found) && (it != neighbours.end()); it++) { cert *c = (cert *) ((*it) -> id); /**************** PQI_USE_XPGP ******************/ #if defined(PQI_USE_XPGP) if ((c != NULL) && (0 == XPGP_cmp(c -> certificate, nc -> certificate))) #else /* X509 Certificates */ /**************** PQI_USE_XPGP ******************/ if ((c != NULL) && (0 == X509_cmp(c -> certificate, nc -> certificate))) #endif /* X509 Certificates */ /**************** PQI_USE_XPGP ******************/ { /* addresses handled already .... * by sslroot. (more intelligent decisions). * update timestamps so we don't overwrite * the uptodate cert data. */ found = true; if ((nc -> lc_timestamp > 0) && ((unsigned) nc -> lc_timestamp > (*it) -> c_ts)) { // connect.... timestamp (*it) -> connect = true; (*it) -> c_ts = nc -> lc_timestamp; // don't make this decision here. //(*it) -> server_addr = nc -> lastaddr; } if ((nc -> lr_timestamp > 0) && ((unsigned) nc -> lr_timestamp > (*it) -> l_ts)) { // received.... timestamp (*it) -> listen = true; (*it) -> l_ts = nc -> lr_timestamp; } if ((c != nc) || (c -> certificate != nc -> certificate)) { std::ostringstream out; out << "Warning Dup/Diff Mem "; out << " Found in p3Disc!"; out << std::endl; pqioutput(PQL_ALERT, pqidisczone, out.str()); exit(1); } } } if (!found) { // add into the list..... autoneighbour *an = new autoneighbour(); an -> id = nc; // initial guess. an -> local_addr = nc -> localaddr; an -> server_addr = nc -> serveraddr; an -> local = false; if (nc -> lc_timestamp > 0) { an -> c_ts = nc -> lc_timestamp; an -> connect = true; } else { an -> c_ts = 0; an -> connect = false; } if (nc -> lr_timestamp > 0) { an -> l_ts = nc -> lr_timestamp; an -> listen = true; } else { an -> l_ts = 0; an -> listen = false; } neighbours.push_back(an); } } return 1; } int p3disc::distillData() { // This transforms the autoneighbour tree into // a list of certificates with the best guess settings. // get any extra. from sslroot. collectCerts(); discovered.clear(); std::ostringstream out; out << "p3disc::distillData()" << std::endl; std::list::iterator it; std::list::iterator it2; std::list::iterator nit; cert *own = sroot -> getOwnCert(); for(it = neighbours.begin(); it != neighbours.end(); it++) { /* for the moment this is going to be a simplistic * (and non-fault tolerent design).... * we will take the most up-to-date values.... from the friends of neighbours. * * if these are more up-to-date than both the * (1) neighbour (*it) and * (2) the actual certificate and * (3) we are not connected... then * * (a) we update the addresses and timestamps on the neighbour. * (b) addresses on the certificate. * * Therefore * cert has (1) our connect times, (2) best guess server. * neighbour has uptodate times/servers from last distill. * * NOTE this requires a better algorithm. * */ unsigned int mr_connect = 0; unsigned int mr_listen = 0; unsigned int mr_both = 0; /* connect or receive */ /* three fields below match most recent (of either) */ struct sockaddr_in mr_server; struct sockaddr_in mr_local; unsigned int mr_flags = 0; /* if we find a neighbour_of, which is the same cert. * then we have the definitive answer already * (and it has been installed) */ bool haveDefinitive = false; cert *c = (cert *) (*it) -> id; for(nit = ((*it) -> neighbour_of).begin(); nit != ((*it) -> neighbour_of).end(); nit++) { out << "\tDistill Connected via: "; if ((*nit) -> id != NULL) { out << ((*nit) ->id) -> Name(); } out << std::endl; out << "\t\tServer: "; out << inet_ntoa((*nit)->server_addr.sin_addr); out << ":" << ntohs((*nit)->server_addr.sin_port); out << std::endl; if ((*nit)->id == (*it)->id) { haveDefinitive = true; out << "\t\tIs Definitive Answer!"; out << std::endl; } if ((*nit) -> listen) { if ((*nit)->l_ts > mr_listen) { mr_listen = (*nit)->l_ts; if (mr_listen > mr_both) { mr_both = mr_listen; mr_server = (*nit) -> server_addr; mr_local = (*nit) -> local_addr; mr_flags = (*nit) -> discFlags; } } } if ((*nit) -> connect) { if ((*nit) -> c_ts > mr_connect) { mr_connect = (*nit)->c_ts; if (mr_connect > mr_both) { mr_both = mr_connect; mr_server = (*nit) -> server_addr; mr_local = (*nit) -> local_addr; mr_flags = (*nit) -> discFlags; } } } } if ((c == own) || (haveDefinitive)) { out << c -> Name(); out << ": Is Own or Definitive: no Update..."; out << std::endl; discovered.push_back(c); continue; } if ((mr_both > (*it)-> c_ts) && (mr_both > (*it)-> l_ts)) { (*it) -> server_addr = mr_server; (*it) -> local_addr = mr_local; (*it) -> discFlags = mr_flags; } /* now we can check against (*it) */ if ((!(*it)->listen) || ((*it)-> l_ts < mr_listen)) { (*it) -> listen = true; (*it)-> l_ts = mr_listen; } if ((!(*it)->connect) || ((*it)-> c_ts < mr_connect)) { (*it) -> connect = true; (*it)-> c_ts = mr_connect; } /* XXX fixme ***/ // Finally we can update the certificate, if auto // is selected.... or not in use. if (!(c -> Connected())) { out << "Checking: " << c -> Name() << std::endl; // if empty local if (0 == inaddr_cmp(c -> localaddr, INADDR_ANY)) { out << "\tUpdating NULL Local Addr:" << std::endl; out << "\t\tOld: "; out << inet_ntoa(c->localaddr.sin_addr); out << ":" << ntohs(c->localaddr.sin_port); c -> localaddr = (*it) -> local_addr; out << "\t\tNew: "; out << inet_ntoa(c->localaddr.sin_addr); out << ":" << ntohs(c->localaddr.sin_port); } // if empty server ..... if (0 == inaddr_cmp(c -> serveraddr, INADDR_ANY)) { out << "\tUpdating NULL Serv Addr:" << std::endl; out << "\t\tOld: "; out << inet_ntoa(c->serveraddr.sin_addr); out << ":" << ntohs(c->serveraddr.sin_port); c -> serveraddr = (*it) -> server_addr; out << "\t\tNew: "; out << inet_ntoa(c->serveraddr.sin_addr); out << ":" << ntohs(c->serveraddr.sin_port); } // if local (second as should catch empty) else if ((0 == inaddr_cmp((*it) -> server_addr, c -> localaddr))) //&& (inaddr_local(c -> localaddr)) { out << "\tMaking Local..." << std::endl; c -> Local(true); } // Finally the key update .... // check only against the latest data.... if (mr_both) { // unsigned int cert_both = c -> lc_timestamp; if (cert_both < (unsigned) c -> lr_timestamp) { cert_both = c -> lr_timestamp; } int log_delta = -1; /* invalid log */ if (mr_both > cert_both) { log_delta = (int) log10((double) (mr_both - cert_both)); } /* if a peer has connected more recently than us */ if (log_delta > 3) // or > 10000 (secs), or ~3 hours. { out << "\tUpdating OLD Addresses:" << std::endl; out << "\t\tOld Local: "; out << inet_ntoa(c->serveraddr.sin_addr); out << ":" << ntohs(c->serveraddr.sin_port); out << std::endl; out << "\t\tOld Server: "; out << inet_ntoa(c->serveraddr.sin_addr); out << ":" << ntohs(c->serveraddr.sin_port); out << std::endl; if (c->Firewalled()) { out << "\t\tFireWalled/"; } else { out << "\t\tNot FireWalled/"; } if (c->Forwarded()) { out << "Forwarded"; } else { out << "Not Forwarded"; } out << std::endl; if (0!=inaddr_cmp(mr_server, INADDR_ANY)) { c -> serveraddr = mr_server; } if (0!=inaddr_cmp(mr_local, INADDR_ANY)) { c -> localaddr = mr_local; } updateCertAvailabilityFlags(c, mr_flags); out << "\t\tNew: "; out << inet_ntoa(c->serveraddr.sin_addr); out << ":" << ntohs(c->serveraddr.sin_port); out << "\t\tNew Local: "; out << inet_ntoa(c->serveraddr.sin_addr); out << ":" << ntohs(c->serveraddr.sin_port); out << std::endl; out << "\t\tNew Server: "; out << inet_ntoa(c->serveraddr.sin_addr); out << ":" << ntohs(c->serveraddr.sin_port); out << std::endl; if (c->Firewalled()) { out << "\t\tFireWalled/"; } else { out << "\t\tNot FireWalled/"; } if (c->Forwarded()) { out << "Forwarded"; } else { out << "Not Forwarded"; } out << std::endl; } } } discovered.push_back(c); } pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); idServers(); return 1; } std::list &p3disc::getDiscovered() { return discovered; } static const std::string pqi_adflags("PQI_ADFLAGS"); int p3disc::save_configuration() { if (sroot == NULL) return -1; std::string localflags; if (local_disc) localflags += "L"; if (remote_disc) localflags += "R"; sroot -> setSetting(pqi_adflags, localflags); return 1; } // load configuration from sslcert -> owncert() // instead of from the configuration files. int p3disc::load_configuration() { unsigned int i = 0; if (sroot == NULL) return -1; Person *p = sroot -> getOwnCert(); if (p == NULL) return -1; laddr = p -> localaddr; //laddr.sin_family = AF_INET; saddr = p -> serveraddr; local_firewalled = p -> Firewalled(); local_forwarded = p -> Forwarded(); std::string localflags = sroot -> getSetting(pqi_adflags); // initially drop out gracefully. if (localflags.length() == 0) return 1; if (i < localflags.length()) if (local_disc = ('L' == localflags[i])) i++; if (i < localflags.length()) if (remote_disc = ('R' == localflags[i])) i++; // temp turn on! local_disc = false; // true; remote_disc = true; return 1; } std::list p3disc::potentialproxy(cert *target) { std::list certs; // search the discovery tree for proxies for target. std::list::iterator it; std::list::iterator nit; pqioutput(PQL_DEBUG_BASIC, pqidisczone, "p3disc::potentialproxy()"); for(it = neighbours.begin(); it != neighbours.end(); it++) { cert *c = (cert *) (*it) -> id; if (c == target) { // found target. for(nit = ((*it) -> neighbour_of).begin(); nit != ((*it) -> neighbour_of).end(); nit++) { /* can't use target as proxy */ cert *pp = (cert *) (*nit)->id; if ((pp -> Connected()) && (target != pp)) { std::ostringstream out; out << "Potential Proxy: "; out << pp -> Name(); certs.push_back(pp); pqioutput(PQL_DEBUG_BASIC, pqidisczone, out.str()); } } return certs; } } pqioutput(PQL_DEBUG_BASIC, pqidisczone, "p3disc::potentialproxy() No proxies found"); // empty list. return certs; } std::list p3disc::requestStunServers() { /* loop through all the possibilities * * find the ones which aren't firewalled. * * get their addresses. */ cert *own = sroot -> getOwnCert(); std::list stunList; std::list::iterator it; for(it = neighbours.begin(); it != neighbours.end(); it++) { cert *c = (cert *) (*it) -> id; /* if flags are correct, and the address looks * valid. */ /* switch on Local Stun for testing */ /* * #define STUN_ALLOW_LOCAL_NET 1 */ #ifdef STUN_ALLOW_LOCAL_NET bool isExtern = true; #else bool isExtern = (!c->Firewalled()) || (c->Firewalled() && c->Forwarded()); #endif if (isExtern) { // second level of checks. // if we will connect, and haven't -> they are probably // offline. if (c->Accepted() && (!c->Connected())) { std::ostringstream out; out << "Offline Friend: "; out << c -> Name(); out << " not available for Stun"; pqioutput(PQL_DEBUG_ALERT, pqidisczone, out.str()); isExtern = false; } // and address looks good. // // and not in our subnet (external to us) } if (isExtern) { std::ostringstream out; out << "Potential Stun Server: "; out << c -> Name(); out << std::endl; out << " ServerAddr: " << inet_ntoa(c->serveraddr.sin_addr); out << " : " << ntohs(c->serveraddr.sin_port); out << std::endl; out << " LocalAddr: " << inet_ntoa(c->localaddr.sin_addr); out << " : " << ntohs(c->localaddr.sin_port); out << std::endl; #ifdef STUN_ALLOW_LOCAL_NET if (isValidNet(&(c->serveraddr.sin_addr)) && (!sameNet(&(own->serveraddr.sin_addr), &(c->serveraddr.sin_addr)))) #else if ((isValidNet(&(c->serveraddr.sin_addr))) && (!isPrivateNet(&(c->serveraddr.sin_addr))) && (!sameNet(&(own->localaddr.sin_addr), &(c->serveraddr.sin_addr))) && (!sameNet(&(own->serveraddr.sin_addr), &(c->serveraddr.sin_addr)))) #endif { out << " -- Chose Server Address"; out << std::endl; stunList.push_back(c->serveraddr); } #ifdef STUN_ALLOW_LOCAL_NET else if (isValidNet(&(c->localaddr.sin_addr))) #else else if ((!c->Firewalled()) && (isValidNet(&(c->localaddr.sin_addr))) && (!isPrivateNet(&(c->localaddr.sin_addr))) && (!sameNet(&(own->localaddr.sin_addr), &(c->localaddr.sin_addr)))) #endif { out << " -- Chose Local Address"; out << std::endl; stunList.push_back(c->localaddr); } else { out << "<=> Invalid / Private Addresses"; out << std::endl; } pqioutput(PQL_DEBUG_ALERT, pqidisczone, out.str()); } else { std::ostringstream out; out << "Non-Stun Neighbour: "; out << c -> Name(); pqioutput(PQL_DEBUG_ALERT, pqidisczone, out.str()); } } return stunList; } // tdelta -> trange. // -inf...<0 0 (invalid) // 0.. <9 1 // 9...<99 2 // 99...<999 3 // 999...<9999 4 // etc... int convertTDeltaToTRange(double tdelta) { if (tdelta < 0) return 0; int trange = 1 + (int) log10(tdelta + 1.0); return trange; } // trange -> tdelta // -inf...0 -1 (invalid) // 1 8 // 2 98 // 3 998 // 4 9998 // etc... int convertTRangeToTDelta(int trange) { if (trange <= 0) return -1; return (int) (pow(10.0, trange) - 1.5); // (int) xxx98.5 -> xxx98 } // fn which updates: connect, c_ts, // listen, l_ts, // local_addr, server_addr, // and discFlags. int updateAutoServer(autoserver *as, RsDiscItem *di) { int cts = time(NULL); as->listen = (di->receive_tr != 0); as->connect= (di->connect_tr != 0); /* convert [r|c]_tf to timestamps.... * * Conversion to a _tf.... * * * */ if (as->listen) { as->l_ts = cts - convertTRangeToTDelta(di->receive_tr); } if (as->connect) { as->c_ts = cts - convertTRangeToTDelta(di->connect_tr); } as->local_addr = di->laddr; as->server_addr = di->saddr; as->discFlags = di->discFlags; return 1; } static const int PQI_DISC_FLAGS_FIREWALLED = 0x0001; static const int PQI_DISC_FLAGS_FORWARDED = 0x0002; static const int PQI_DISC_FLAGS_LOCAL = 0x0004; int updateCertAvailabilityFlags(cert *c, unsigned long discFlags) { if (c) { c->Firewalled(discFlags & PQI_DISC_FLAGS_FIREWALLED); c->Forwarded(discFlags & PQI_DISC_FLAGS_FORWARDED); if (discFlags & PQI_DISC_FLAGS_FIREWALLED) { pqioutput(PQL_WARNING, pqidisczone, "updateCertAvailabilityFlags() Setting Firewalled Flag = true"); } else { pqioutput(PQL_WARNING, pqidisczone, "updateCertAvailabilityFlags() Setting Firewalled Flag = false"); } if (discFlags & PQI_DISC_FLAGS_FORWARDED) { pqioutput(PQL_WARNING, pqidisczone, "updateCertAvailabilityFlags() Setting Forwarded Flag = true"); } else { pqioutput(PQL_WARNING, pqidisczone, "updateCertAvailabilityFlags() Setting Forwarded Flag = false"); } return 1; } return 0; } unsigned long determineCertAvailabilityFlags(cert *c) { unsigned long flags = 0; if (c->Firewalled()) { flags |= PQI_DISC_FLAGS_FIREWALLED; } if (c->Forwarded()) { flags |= PQI_DISC_FLAGS_FORWARDED; } if (c->Local()) { flags |= PQI_DISC_FLAGS_LOCAL; } return flags; }