AREXPORT void ArNetServer::runOnce(void) { ArSocket acceptingSocket; ArSocket *socket; char *str; std::list<ArSocket *> removeList; std::list<ArSocket *>::iterator it; ArArgumentBuilder *args = NULL; std::string command; if (!myOpened) { return; } lock(); // get any new sockets that want to connect while (myServerSocket.accept(&acceptingSocket) && acceptingSocket.getFD() >= 0) { acceptingSocket.setNonBlock(); // see if we want more sockets if (!myMultipleClients && (myConns.size() > 0 || myConnectingConns.size() > 0)) { // we didn't want it, so politely tell it to go away acceptingSocket.writeString("Conn refused."); acceptingSocket.writeString( "Only client allowed and it is already connected."); acceptingSocket.close(); ArLog::log(ArLog::Terse, "ArNetServer not taking multiple clients and another client tried to connect from %s.", acceptingSocket.getIPString()); } else { // we want the client so we put it in our list of connecting // sockets, which means that it is waiting to give its password socket = new ArSocket; socket->setLogWriteStrings(myLoggingDataSent); socket->transfer(&acceptingSocket); socket->writeString("Enter password:"******"Client connecting from %s.", socket->getIPString()); } } // now we read in data from our connecting sockets and see if // they've given us the password for (it = myConnectingConns.begin(); it != myConnectingConns.end(); ++it) { socket = (*it); // read in what the client has to say if ((str = socket->readString()) != NULL) { if (str[0] == '\0') continue; // now see if the word matchs the password if (myPassword == str) { ArLog::log(ArLog::Normal, "Client from %s gave password and connected.", socket->getIPString()); myConns.push_front(socket); removeList.push_front(socket); internalGreeting(socket); } else { socket->close(); myDeleteList.push_front(socket); ArLog::log(ArLog::Terse, "Client from %s gave wrong password and is being disconnected.", socket->getIPString()); } } // if we couldn't read a string it means we lost a connection else { ArLog::log(ArLog::Normal, "Connection to %s lost.", socket->getIPString()); socket->close(); myDeleteList.push_front(socket); } } // now we clear out the ones we want to remove from our connecting // clients list while ((it = removeList.begin()) != removeList.end()) { socket = (*it); myConnectingConns.remove(socket); removeList.pop_front(); } // now we read in data from our connecting sockets and see if // they've given us the password for (it = myConns.begin(); it != myConns.end() && myOpened; ++it) { socket = (*it); // read in what the client has to say while ((str = socket->readString()) != NULL) { // if this is null then there wasn't anything said if (str[0] == '\0') break; // make sure we read something // set up the arguments and then call the function for the // argument args = new ArArgumentBuilder; args->addPlain(str); //args->log(); parseCommandOnSocket(args, socket); delete args; args = NULL; } // if str was NULL we lost connection if (str == NULL) { ArLog::log(ArLog::Normal, "Connection to %s lost.", socket->getIPString()); socket->close(); myDeleteList.push_front(socket); } } // now we delete the ones we want to delete (we could do this above // but then it wouldn't be symetrical with above) while ((it = myDeleteList.begin()) != myDeleteList.end()) { socket = (*it); myConnectingConns.remove(socket); myConns.remove(socket); socket->close(); delete socket; myDeleteList.pop_front(); } if (myWantToClose) { close(); } unlock(); }
/// This should be its own thread here void *ArCentralManager::runThread(void *arg) { std::list<ArSocket *>::iterator sIt; std::list<std::string>::iterator nIt; std::list<ArCentralForwarder *>::iterator fIt; ArSocket *socket; std::string robotName; ArCentralForwarder *forwarder; ArNetPacket *packet; std::list<ArNetPacket *> addPackets; std::list<ArNetPacket *> remPackets; threadStarted(); while (getRunning()) { int numForwarders = 0; int numClients = 0; myDataMutex.lock(); // this is where the original code to add forwarders was before we // changed the unique behavior to drop old ones... std::list<ArCentralForwarder *> connectedRemoveList; std::list<ArCentralForwarder *> unconnectedRemoveList; for (fIt = myForwarders.begin(); fIt != myForwarders.end(); fIt++) { forwarder = (*fIt); numForwarders++; if (forwarder->getServer() != NULL) numClients += forwarder->getServer()->getNumClients(); bool connected = forwarder->isConnected(); bool removed = false; if (!forwarder->callOnce(myHeartbeatTimeout, myUdpHeartbeatTimeout, myRobotBackupTimeout, myClientBackupTimeout)) { if (connected) { ArLog::log(ArLog::Normal, "Will remove forwarder from %s", forwarder->getRobotName()); connectedRemoveList.push_back(forwarder); removed = true; } else { ArLog::log(ArLog::Normal, "Failed to connect to forwarder from %s", forwarder->getRobotName()); unconnectedRemoveList.push_back(forwarder); removed = true; } } if (!connected && !removed && forwarder->isConnected()) { ArLog::log(ArLog::Normal, "Adding forwarder %s", forwarder->getRobotName()); ArTime *newTime = new ArTime; newTime->setSec(0); myUsedPorts[forwarder->getPort()] = newTime; std::multimap<int, ArFunctor1<ArCentralForwarder *> *>::iterator it; for (it = myForwarderAddedCBList.begin(); it != myForwarderAddedCBList.end(); it++) { if ((*it).second->getName() == NULL || (*it).second->getName()[0] == '\0') ArLog::log(ArLog::Normal, "Calling unnamed add functor at %d", -(*it).first); else ArLog::log(ArLog::Normal, "Calling %s add functor at %d", (*it).second->getName(), -(*it).first); (*it).second->invoke(forwarder); } ArLog::log(ArLog::Normal, "Added forwarder %s", forwarder->getRobotName()); ArNetPacket *sendPacket = new ArNetPacket; sendPacket->strToBuf(""); sendPacket->uByte2ToBuf(forwarder->getPort()); sendPacket->strToBuf(forwarder->getRobotName()); sendPacket->strToBuf(""); sendPacket->strToBuf( forwarder->getClient()->getTcpSocket()->getIPString()); addPackets.push_back(sendPacket); // MPL added this at the same time as the changes for the deadlock that happened down below //myClientServer->broadcastPacketTcp(&sendPacket, "clientAdded"); } } while ((fIt = connectedRemoveList.begin()) != connectedRemoveList.end()) { forwarder = (*fIt); ArLog::log(ArLog::Normal, "Removing forwarder %s", forwarder->getRobotName()); std::multimap<int, ArFunctor1<ArCentralForwarder *> *>::iterator it; for (it = myForwarderRemovedCBList.begin(); it != myForwarderRemovedCBList.end(); it++) { if ((*it).second->getName() == NULL || (*it).second->getName()[0] == '\0') ArLog::log(ArLog::Normal, "Calling unnamed remove functor at %d", -(*it).first); else ArLog::log(ArLog::Normal, "Calling %s remove functor at %d", (*it).second->getName(), -(*it).first); (*it).second->invoke(forwarder); } ArLog::log(ArLog::Normal, "Called forwarder removed for %s", forwarder->getRobotName()); ArNetPacket *sendPacket = new ArNetPacket; sendPacket->strToBuf(""); sendPacket->uByte2ToBuf(forwarder->getPort()); sendPacket->strToBuf(forwarder->getRobotName()); sendPacket->strToBuf(""); sendPacket->strToBuf( forwarder->getClient()->getTcpSocket()->getIPString()); // MPL making this just push packets into a list to broadcast at the end since this was deadlocking //myClientServer->broadcastPacketTcp(&sendPacket, "clientRemoved"); remPackets.push_back(sendPacket); if (myUsedPorts.find(forwarder->getPort()) != myUsedPorts.end() && myUsedPorts[forwarder->getPort()] != NULL) myUsedPorts[forwarder->getPort()]->setToNow(); myForwarders.remove(forwarder); delete forwarder; connectedRemoveList.pop_front(); ArLog::log(ArLog::Normal, "Removed forwarder"); } while ((fIt = unconnectedRemoveList.begin()) != unconnectedRemoveList.end()) { forwarder = (*fIt); ArLog::log(ArLog::Normal, "Removing unconnected forwarder %s", forwarder->getRobotName()); if (myUsedPorts.find(forwarder->getPort()) != myUsedPorts.end() && myUsedPorts[forwarder->getPort()] != NULL) myUsedPorts[forwarder->getPort()]->setToNow(); myForwarders.remove(forwarder); delete forwarder; unconnectedRemoveList.pop_front(); ArLog::log(ArLog::Normal, "Removed unconnected forwarder"); } // this code was up above just after the lock before we changed // the behavior for unique names while ((sIt = myClientSockets.begin()) != myClientSockets.end() && (nIt = myClientNames.begin()) != myClientNames.end()) { socket = (*sIt); robotName = (*nIt); myClientSockets.pop_front(); myClientNames.pop_front(); ArLog::log(ArLog::Normal, "New forwarder for socket from %s with name %s", socket->getIPString(), robotName.c_str()); forwarder = new ArCentralForwarder(myClientServer, socket, robotName.c_str(), myClientServer->getTcpPort() + 1, &myUsedPorts, &myForwarderServerClientRemovedCB, myEnforceProtocolVersion.c_str(), myEnforceType); myForwarders.push_back(forwarder); } numClients += myRobotServer->getNumClients(); if (myRobotServer != myClientServer) numClients += myClientServer->getNumClients(); // end of code moved for change in unique behavior if (numClients > myMostClients) { ArLog::log(ArLog::Normal, "CentralManager: New most clients: %d", numClients); myMostClients = numClients; } if (numForwarders > myMostForwarders) myMostForwarders = numForwarders; if (numClients > myMostClients) { ArLog::log(ArLog::Normal, "CentralManager: New most forwarders: %d", numForwarders); myMostForwarders = numForwarders; } myRobotServer->internalSetNumClients(numForwarders + myClientSockets.size()); myDataMutex.unlock(); while (addPackets.begin() != addPackets.end()) { packet = addPackets.front(); myClientServer->broadcastPacketTcp(packet, "clientAdded"); addPackets.pop_front(); delete packet; } while (remPackets.begin() != remPackets.end()) { packet = remPackets.front(); myClientServer->broadcastPacketTcp(packet, "clientRemoved"); remPackets.pop_front(); delete packet; } ArUtil::sleep(1); //make this a REALLY long sleep to test the duplicate pending //connection code //ArUtil::sleep(20000); } threadFinished(); return NULL; }