/* * libretroshare/src/pqi pqiperson.cc * * 3P/PQI network interface for RetroShare. * * Copyright 2004-2006 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 "pqi/pqi.h" #include "pqi/pqiperson.h" #include "pqi/pqipersongrp.h" const int pqipersonzone = 82371; #include "pqi/pqidebug.h" #include pqiperson::pqiperson(std::string id, pqipersongrp *pg) :PQInterface(id), active(false), activepqi(NULL), inConnectAttempt(false), waittimes(0), pqipg(pg) { /* must check id! */ return; } pqiperson::~pqiperson() { // clean up the children. std::map::iterator it; for(it = kids.begin(); it != kids.end(); it++) { pqiconnect *pc = (it->second); delete pc; } kids.clear(); } // The PQInterface interface. int pqiperson::SendItem(RsItem *i) { std::ostringstream out; out << "pqiperson::SendItem()"; if (active) { out << " Active: Sending On"; return activepqi -> SendItem(i); } else { out << " Not Active: Used to put in ToGo Store"; out << std::endl; out << " Now deleting..."; delete i; } pqioutput(PQL_DEBUG_BASIC, pqipersonzone, out.str()); return 0; // queued. } RsItem *pqiperson::GetItem() { if (active) return activepqi -> GetItem(); // else not possible. return NULL; } int pqiperson::status() { if (active) return activepqi -> status(); return -1; } // tick...... int pqiperson::tick() { int activeTick = 0; { std::ostringstream out; out << "pqiperson::tick() Id: " << PeerId() << " "; if (active) out << "***Active***"; else out << ">>InActive<<"; out << std::endl; out << "Activepqi: " << activepqi << " inConnectAttempt: "; if (inConnectAttempt) out << "In Connection Attempt"; else out << " Not Connecting "; out << std::endl; // tick the children. std::map::iterator it; for(it = kids.begin(); it != kids.end(); it++) { if (0 < (it->second) -> tick()) { activeTick = 1; } out << "\tTicking Child: " << (it->first) << std::endl; } pqioutput(PQL_DEBUG_ALL, pqipersonzone, out.str()); } // end of pqioutput. return activeTick; } // callback function for the child - notify of a change. // This is only used for out-of-band info.... // otherwise could get dangerous loops. int pqiperson::notifyEvent(NetInterface *ni, int newState) { { std::ostringstream out; out << "pqiperson::notifyEvent() Id: " << PeerId(); out << std::endl; out << "Message: " << newState << " from: " << ni << std::endl; pqioutput(PQL_DEBUG_BASIC, pqipersonzone, out.str()); } /* find the pqi, */ pqiconnect *pqi = NULL; std::map::iterator it; /* start again */ int i = 0; for(it = kids.begin(); it != kids.end(); it++) { std::ostringstream out; out << "pqiperson::connectattempt() Kid# "; out << i << " of " << kids.size(); out << std::endl; out << " type: " << (it->first); out << " ni: " << (it->second)->ni; out << " in_ni: " << ni; pqioutput(PQL_DEBUG_BASIC, pqipersonzone, out.str()); i++; if ((it->second)->thisNetInterface(ni)) { pqi = (it->second); } } if (!pqi) { pqioutput(PQL_WARNING, pqipersonzone, "Unknown notfyEvent Source!"); return -1; } switch(newState) { case CONNECT_RECEIVED: case CONNECT_SUCCESS: /* notify */ if (pqipg) pqipg->notifyConnect(PeerId(), true); if ((active) && (activepqi != pqi)) // already connected - trouble { pqioutput(PQL_WARNING, pqipersonzone, "CONNECT_SUCCESS+active->trouble: shutdown EXISTING->switch to new one!"); // This is the RESET that's killing the connections..... activepqi -> reset(); // this causes a recursive call back into this fn. // which cleans up state. // we only do this if its not going to mess with new conn. } /* now install a new one. */ { pqioutput(PQL_WARNING, pqipersonzone, "CONNECT_SUCCESS->marking so!"); // mark as active. active = true; activepqi = pqi; inConnectAttempt = false; return 1; } break; case CONNECT_UNREACHABLE: case CONNECT_FIREWALLED: case CONNECT_FAILED: if (active) { if (activepqi == pqi) { pqioutput(PQL_WARNING, pqipersonzone, "CONNECT_FAILED->marking so!"); active = false; activepqi = NULL; } else { pqioutput(PQL_WARNING, pqipersonzone, "CONNECT_FAIL+not activepqi->strange!"); // probably UDP connect has failed, // TCP connection has been made since attempt started. return -1; } } else { pqioutput(PQL_WARNING, pqipersonzone, "CONNECT_FAILED+NOT active -> try connect again"); } /* notify up (But not if we are actually active: rtn -1 case above) */ if (pqipg) pqipg->notifyConnect(PeerId(), false); return 1; break; default: break; } return -1; } /***************** Not PQInterface Fns ***********************/ int pqiperson::reset() { { std::ostringstream out; out << "pqiperson::reset() Id: " << PeerId(); out << std::endl; pqioutput(PQL_DEBUG_BASIC, pqipersonzone, out.str()); } std::map::iterator it; for(it = kids.begin(); it != kids.end(); it++) { (it->second) -> reset(); } activepqi = NULL; active = false; return 1; } int pqiperson::addChildInterface(uint32_t type, pqiconnect *pqi) { { std::ostringstream out; out << "pqiperson::addChildInterface() : Id " << PeerId() << " " << type; out << std::endl; pqioutput(PQL_DEBUG_BASIC, pqipersonzone, out.str()); } kids[type] = pqi; return 1; } /***************** PRIVATE FUNCTIONS ***********************/ // functions to iterate over the connects and change state. int pqiperson::listen() { { std::ostringstream out; out << "pqiperson::listen() Id: " << PeerId(); out << std::endl; pqioutput(PQL_DEBUG_BASIC, pqipersonzone, out.str()); } if (!active) { std::map::iterator it; for(it = kids.begin(); it != kids.end(); it++) { // set them all listening. (it->second) -> listen(); } } return 1; } int pqiperson::stoplistening() { { std::ostringstream out; out << "pqiperson::stoplistening() Id: " << PeerId(); out << std::endl; pqioutput(PQL_DEBUG_BASIC, pqipersonzone, out.str()); } std::map::iterator it; for(it = kids.begin(); it != kids.end(); it++) { // set them all listening. (it->second) -> stoplistening(); } return 1; } int pqiperson::connect(uint32_t type, struct sockaddr_in raddr, uint32_t delay, uint32_t period) { { std::ostringstream out; out << "pqiperson::connect() Id: " << PeerId(); out << " type: " << type; out << " addr: " << inet_ntoa(raddr.sin_addr); out << ":" << ntohs(raddr.sin_port); out << std::endl; std::cerr << out.str(); //pqioutput(PQL_DEBUG_BASIC, pqipersonzone, out.str()); } std::map::iterator it; it = kids.find(type); if (it == kids.end()) { std::ostringstream out; out << "pqiperson::connect()"; out << " missing pqiconnect"; out << std::endl; std::cerr << out.str(); //pqioutput(PQL_DEBUG_BASIC, pqipersonzone, out.str()); return 0; } /* set the parameters */ (it->second)->reset(); (it->second)->connect_parameter(NET_PARAM_CONNECT_DELAY, delay); (it->second)->connect_parameter(NET_PARAM_CONNECT_PERIOD, period); (it->second)->connect(raddr); // flag if we started a new connectionAttempt. inConnectAttempt = true; return 1; } float pqiperson::getRate(bool in) { // get the rate from the active one. if ((!active) || (activepqi == NULL)) return 0; return activepqi -> getRate(in); } void pqiperson::setMaxRate(bool in, float val) { // set to all of them. (and us) PQInterface::setMaxRate(in, val); // clean up the children. std::map::iterator it; for(it = kids.begin(); it != kids.end(); it++) { (it->second) -> setMaxRate(in, val); } }