AREXPORT void ArServerClient::processAuthPacket(ArNetPacket *packet, struct sockaddr_in *sin) { ArNetPacket retPacket; long authKey; // check the auth key again, just in case authKey = packet->bufToUByte4(); if (authKey != myAuthKey) { ArLog::log(ArLog::Terse, "ArServerClient: authKey given does not match actual authKey, horrible error."); return; } if (mySin.sin_port != sin->sin_port) { ArLog::log(myVerboseLogLevel, "Client says it is using port %u but is using port %u\n", ArSocket::netToHostOrder(mySin.sin_port), ArSocket::netToHostOrder(sin->sin_port)); } myUdpConfirmedFrom = true; mySin.sin_port = sin->sin_port; mySin.sin_addr = sin->sin_addr; ArLog::log(myVerboseLogLevel, "Client connected to server on udp port %u", ArSocket::netToHostOrder(mySin.sin_port)); // TODO put some state info here to note that its fully udp connected retPacket.empty(); retPacket.setCommand(ArServerCommands::UDP_INTRODUCTION); retPacket.byte4ToBuf(myIntroKey); sendPacketUdp(&retPacket); retPacket.empty(); retPacket.setCommand(ArServerCommands::UDP_CONFIRMATION); sendPacketTcp(&retPacket); }
AREXPORT void ArServerHandlerPopup::netPopupList(ArServerClient *client, ArNetPacket *packet) { ArLog::log(ArLog::Normal, "Sending popup list"); std::map<ArTypes::Byte4, PopupData *>::iterator it; ArNetPacket sendingPacket; PopupData *popupData; myDataMutex.lock(); for (it = myMap.begin(); it != myMap.end(); it++) { popupData = (*it).second; sendingPacket.empty(); ArLog::log(ArLog::Normal, "Sending popup %d", popupData->myID); buildPacket(&sendingPacket, popupData); sendingPacket.setCommand(myServer->findCommandFromName("popupCreate")); client->sendPacketTcp(&sendingPacket); } sendingPacket.empty(); client->sendPacketTcp(&sendingPacket); ArLog::log(ArLog::Normal, "Sent popups"); myDataMutex.unlock(); }
AREXPORT void ArServerClient::shutdown(void) { ArNetPacket packet; packet.setCommand(ArServerCommands::SHUTDOWN); sendPacketTcp(&packet); myTcpSender.sendData(); }
AREXPORT bool ArServerClient::tcpCallback(void) { if (myState == STATE_REJECTED) { myTcpSender.sendData(); ArUtil::sleep(10); return false; } if (myState == STATE_DISCONNECTED && (myHaveSlowPackets || myHaveIdlePackets)) return true; if (myState == STATE_DISCONNECTED) return false; if (myState == STATE_SENT_INTRO && myStateStart.secSince() >= 60) { ArLog::log(myVerboseLogLevel, "%sTook too long for %s to connect", myLogPrefix.c_str(), getIPString()); return false; } if (myTcpOnly && !mySentTcpOnly) { mySentTcpOnly = true; ArNetPacket sending; sending.setCommand(ArServerCommands::TCP_ONLY); sendPacketTcp(&sending); } if (!myTcpReceiver.readData()) { ArLog::log(myVerboseLogLevel, "%sTrouble receiving tcp data from %s", myLogPrefix.c_str(), getIPString()); internalSwitchState(STATE_DISCONNECTED); return tcpCallback(); //return false; } if (!myTcpSender.sendData()) { ArLog::log(myVerboseLogLevel, "%sTrouble sending tcp data to %s", myLogPrefix.c_str(), getIPString()); internalSwitchState(STATE_DISCONNECTED); return tcpCallback(); //return false; } return true; }
AREXPORT bool ArCentralForwarder::requestOnceUdp(const char *name, ArNetPacket *packet, bool quiet) { if (myClient != NULL) { unsigned int commandNum = myClient->findCommandFromName(name); if (commandNum == 0) { if (!quiet) ArLog::log(ArLog::Normal, "ArCentralForwarder::%s::requestOnce: Can't find commandNum for %s", getRobotName(), name); return false; } //return myClient->requestOnceUdp(name, packet, quiet); if (packet != NULL) { packet->setCommand(commandNum); packet->finalizePacket(); return internalRequestOnce(NULL, packet, false); } else { ArNetPacket tempPacket; tempPacket.setCommand(commandNum); tempPacket.finalizePacket(); return internalRequestOnce(NULL, &tempPacket, false); } } else { if (!quiet) ArLog::log(ArLog::Normal, "ArCentralForwarder::%s::requestOnce: Tried to call (for %s) while client was still NULL", getRobotName(), name); return false; } }
AREXPORT ArServerClient::ArServerClient( ArSocket *tcpSocket, unsigned int udpPort, long authKey, long introKey, ArRetFunctor2<bool, ArNetPacket *, struct sockaddr_in *> *sendUdpCallback, std::map<unsigned int, ArServerData *> *dataMap, const char *passwordKey, const char *serverKey, const ArServerUserInfo *userInfo, int rejecting, const char *rejectingString, bool debugLogging, const char *serverClientName, bool logPasswordFailureVerbosely, bool allowSlowPackets, bool allowIdlePackets) : myProcessPacketCB(this, &ArServerClient::processPacket, NULL, true) { ArNetPacket packet; // set our default to no command pushCommand(0); myAuthKey = authKey; myIntroKey = introKey; myTcpSocket.transfer(tcpSocket); myTcpSocket.setCloseCallback(tcpSocket->getCloseCallback()); myTcpSocket.setNonBlock(); myTcpReceiver.setSocket(&myTcpSocket); myTcpReceiver.setProcessPacketCB(&myProcessPacketCB); myTcpSender.setSocket(&myTcpSocket); mySendUdpCB = sendUdpCallback; myDataMap = dataMap; if (udpPort == 0) myTcpOnly = true; else myTcpOnly = false; mySentTcpOnly = myTcpOnly; myUserInfo = userInfo; myPasswordKey = passwordKey; myServerKey = serverKey; myRejecting = rejecting; if (rejectingString != NULL) myRejectingString = rejectingString; myDebugLogging = debugLogging; if (myDebugLogging) myVerboseLogLevel = ArLog::Normal; else myVerboseLogLevel = ArLog::Verbose; myTcpSender.setDebugLogging(myDebugLogging); myLogPrefix = serverClientName; myLogPrefix += ": "; myTcpSender.setLoggingPrefix(myLogPrefix.c_str()); myTcpReceiver.setLoggingPrefix(myLogPrefix.c_str()); myLogPasswordFailureVerbosely = logPasswordFailureVerbosely; mySlowPacketsMutex.setLogName("ArServerClient::mySlowPacketsMutex"); myIdlePacketsMutex.setLogName("ArServerClient::myIdlePacketsMutex"); myAllowSlowPackets = allowSlowPackets; myAllowIdlePackets = allowIdlePackets; setIdentifier(ArServerClientIdentifier()); internalSwitchState(STATE_SENT_INTRO); packet.empty(); packet.setCommand(ArServerCommands::INTRODUCTION); packet.strToBuf("alpha"); packet.uByte2ToBuf(udpPort); packet.uByte4ToBuf(myAuthKey); packet.uByte4ToBuf(myIntroKey); packet.strToBuf(myPasswordKey.c_str()); sendPacketTcp(&packet); mySlowIdleThread = NULL; myHaveSlowPackets = false; myHaveIdlePackets = false; myCreationTime.setToNow(); resetTracking(); }
AREXPORT void ArServerClient::processPacket(ArNetPacket *packet, bool tcp) { std::string str; struct sockaddr_in sin; unsigned int clientUdpPort; ArNetPacket retPacket; //printf("Command number %d\n", packet->getCommand()); // if we're in intro mode and received back the intro if (myState == STATE_SENT_INTRO && packet->getCommand() == ArClientCommands::INTRODUCTION) { char user[512]; unsigned char password[16]; clientUdpPort = packet->bufToUByte2(); packet->bufToStr(user, sizeof(user)); packet->bufToData((char *)password, 16); if (myRejecting != 0) { retPacket.empty(); retPacket.setCommand(ArServerCommands::REJECTED); retPacket.byte2ToBuf(myRejecting); retPacket.strToBuf(myRejectingString.c_str()); sendPacketTcp(&retPacket); if (myRejecting == 2) ArLog::log(ArLog::Normal, "%sRejected connection from %s since we're using a central server at %s", myLogPrefix.c_str(), getIPString(), myRejectingString.c_str()); internalSwitchState(STATE_REJECTED); return; } // if user info is NULL we're not checking passwords if (myUserInfo != NULL && !myUserInfo->matchUserPassword(user, password, myPasswordKey.c_str(), myServerKey.c_str(), myLogPasswordFailureVerbosely)) { retPacket.empty(); retPacket.setCommand(ArServerCommands::REJECTED); retPacket.byte2ToBuf(1); retPacket.strToBuf(""); sendPacketTcp(&retPacket); ArLog::log(ArLog::Normal, "%sRejected user '%s' or password from %s", myLogPrefix.c_str(), user, getIPString()); internalSwitchState(STATE_REJECTED); return; } if (myUserInfo != NULL) myGroups = myUserInfo->getUsersGroups(user); else myGroups.clear(); sin.sin_family = AF_INET; sin.sin_addr = *myTcpSocket.inAddr(); sin.sin_port = ArSocket::hostToNetOrder(clientUdpPort); if (myUserInfo != NULL) ArLog::log(ArLog::Normal, "%sClient connected from %s with user %s", myLogPrefix.c_str(), getIPString(), user); else ArLog::log(ArLog::Normal, "%sClient connected from %s", myLogPrefix.c_str(), getIPString()); setUdpAddress(&sin); // send that we've connected retPacket.empty(); retPacket.setCommand(ArServerCommands::CONNECTED); sendPacketTcp(&retPacket); // note that we're connected internalSwitchState(STATE_CONNECTED); // send them the list sendListPacket(); // send the udp introduction if we're using udp if (!myTcpOnly) { retPacket.empty(); retPacket.setCommand(ArServerCommands::UDP_INTRODUCTION); retPacket.byte4ToBuf(myIntroKey); sendPacketUdp(&retPacket); } } // if we aren't in intro mode and got an intro somethings wrong else if (packet->getCommand() == ArClientCommands::INTRODUCTION) { ArLog::log(ArLog::Terse, "%sReceived introduction when not in intro mode", myLogPrefix.c_str()); return; } // if we got this over tcp then they only want tcp else if (packet->getCommand() == ArClientCommands::UDP_INTRODUCTION) { if (!myTcpOnly) { ArLog::log(ArLog::Normal, "%sGot UDP introduction over tcp, assuming client only wants tcp data.", myLogPrefix.c_str()); myTcpOnly = true; } return; } // if we're connected and got a udp confirmation else if ((myState == STATE_CONNECTED || myState == STATE_SENT_INTRO) && packet->getCommand() == ArClientCommands::UDP_CONFIRMATION) { myUdpConfirmedTo = true; ArLog::log(myVerboseLogLevel, "%s: udp connection to client confirmed.", myLogPrefix.c_str()); return; } // if we're not connected (or close) and got a confirmation else if (packet->getCommand() == ArClientCommands::UDP_CONFIRMATION) { ArLog::log(ArLog::Normal, "%sReceived udp confirmation when not connected.", myLogPrefix.c_str()); return; } else if (packet->getCommand() == ArClientCommands::TCP_ONLY) { ArLog::log(myVerboseLogLevel, "%sClient only wants tcp data.", myLogPrefix.c_str()); myTcpOnly = true; return; } else if (packet->getCommand() == ArClientCommands::SHUTDOWN) { ArLog::log(ArLog::Normal, "%sClient from %s has disconnected.", myLogPrefix.c_str(), getIPString()); internalSwitchState(STATE_DISCONNECTED); return; } // if we're connected its a request, then set all that up else if (myState == STATE_CONNECTED && packet->getCommand() == ArClientCommands::REQUEST) { std::list<ArServerClientData *>::iterator it; ArServerClientData *data; ArServerData *serverData; unsigned int command; long mSec; // see which one they requested command = packet->bufToUByte2(); mSec = packet->bufToByte4(); // first we see if we already have this one for (it = myRequested.begin(); it != myRequested.end(); ++it) { data = (*it); serverData = data->getServerData(); if (serverData->getCommand() == command) { trackPacketReceived(packet, command); data->setMSec(mSec); data->setPacket(packet); data->getPacket()->setCommand(command); serverData->callRequestChangedFunctor(); ArLog::log(myVerboseLogLevel, "%sRevised request for command %s to %d mSec with new argument", myLogPrefix.c_str(), findCommandName(serverData->getCommand()), mSec); return; } } // we didn't have it, so make a new one std::map<unsigned int, ArServerData *>::iterator sdit; if ((sdit = myDataMap->find(command)) == myDataMap->end()) { ArLog::log(ArLog::Terse, "%sGot request for command %d which doesn't exist", myLogPrefix.c_str(), command); return; } serverData = (*sdit).second; if (serverData == NULL) { ArLog::log(ArLog::Terse, "%sprocessPackets request handler has NULL serverData", myLogPrefix.c_str()); } if (myUserInfo != NULL && serverData->getCommandGroup() != NULL && serverData->getCommandGroup()[0] != '\0' && myGroups.count(serverData->getCommandGroup()) == 0 && myGroups.count("all") == 0) { ArLog::log(ArLog::Normal, "%s%s tried to request command '%s' but it doesn't have access to that command", myLogPrefix.c_str(), getIPString(), serverData->getName()); return; } trackPacketReceived(packet, command); data = new ArServerClientData(serverData, mSec, packet); data->getPacket()->setCommand(command); ArLog::log(myVerboseLogLevel, "%sadded request for command %s every %d mSec", myLogPrefix.c_str(), serverData->getName(), mSec); if (mSec == 0) ArLog::log(ArLog::Normal, "%sClient from %s requested command %s every at 0 msec", myLogPrefix.c_str(), getIPString(), serverData->getName()); myRequested.push_front(data); serverData->callRequestChangedFunctor(); pushCommand(command); pushForceTcpFlag(false); if (serverData->getFunctor() != NULL) serverData->getFunctor()->invoke(this, data->getPacket()); popCommand(); popForceTcpFlag(); return; } // if we got a request when we're not connected else if (packet->getCommand() == ArClientCommands::REQUEST) { ArLog::log(ArLog::Normal, "Got a request while not connected.", myLogPrefix.c_str()); return; } // if we're connected its a requestStop, then set all that up else if (myState == STATE_CONNECTED && packet->getCommand() == ArClientCommands::REQUESTSTOP) { std::list<ArServerClientData *>::iterator it; ArServerClientData *data; ArServerData *serverData; unsigned int command; // see which one they requested command = packet->bufToUByte2(); // first we see if we have this one for (it = myRequested.begin(); it != myRequested.end(); ++it) { data = (*it); serverData = data->getServerData(); // we have a match, so set the new params then return if (data->getServerData()->getCommand() == command) { trackPacketReceived(packet, command); myRequested.erase(it); ArLog::log(myVerboseLogLevel, "%sStopped request for command %s", myLogPrefix.c_str(), findCommandName(serverData->getCommand())); delete data; serverData->callRequestChangedFunctor(); return; } } // if we don't have it... that means that it wasn't here // find out what to call it std::map<unsigned int, ArServerData *>::iterator sdit; if ((sdit = myDataMap->find(command)) == myDataMap->end()) { ArLog::log(ArLog::Terse, "%sGot a requeststop for command %d which doesn't exist", myLogPrefix.c_str(), command); return; } trackPacketReceived(packet, command); serverData = (*sdit).second; if (serverData == NULL) ArLog::log(ArLog::Terse, "%srequeststop handler has NULL serverData on back command %d", myLogPrefix.c_str(), command); else ArLog::log(ArLog::Normal, "%s: Got a stop request for command %s that isn't requested", myLogPrefix.c_str(), serverData->getName()); return; } // if we got a requestStop when we're not connected else if (packet->getCommand() == ArClientCommands::REQUESTSTOP) { ArLog::log(ArLog::Normal, "%sGot a requeststop while not connected.", myLogPrefix.c_str()); return; } // if we're connected and its a command to execute just once else if (myState == STATE_CONNECTED) { unsigned int command; std::map<unsigned int, ArServerData *>::iterator it; ArServerData *serverData; command = packet->getCommand(); if ((it = myDataMap->find(command)) == myDataMap->end()) { ArLog::log(ArLog::Terse, "%sArServerClient got request for command %d which doesn't exist", myLogPrefix.c_str(), command); return; } serverData = (*it).second; if (myUserInfo != NULL && serverData->getCommandGroup() != NULL && serverData->getCommandGroup()[0] != '\0' && myGroups.count(serverData->getCommandGroup()) == 0 && myGroups.count("all") == 0) { ArLog::log(ArLog::Normal, "%s%s tried to request command '%s' once but it doesn't have access to that command", myLogPrefix.c_str(), getIPString(), serverData->getName()); return; } trackPacketReceived(packet, command); // copy it out and return if its an idle packet if (myAllowIdlePackets && serverData->isIdlePacket()) { myHaveIdlePackets = true; if (command <= 255) ArLog::log(myVerboseLogLevel, "%sStoring idle command %d", myLogPrefix.c_str(), command); else ArLog::log(myVerboseLogLevel, "%sStoring idle command %s", myLogPrefix.c_str(), serverData->getName()); myIdlePacketsMutex.lock(); ArNetPacket *idlePacket = new ArNetPacket(packet->getLength() + 5); idlePacket->duplicatePacket(packet); myIdlePackets.push_back(idlePacket); myIdlePacketsMutex.unlock(); return; } // If its a slow or an idle packet (and we're not allowing the // idle behavior) and we allow slow packets then copy it else if (myAllowSlowPackets && (serverData->isSlowPacket() || serverData->isIdlePacket())) { myHaveSlowPackets = true; if (command <= 255) ArLog::log(myVerboseLogLevel, "%sStoring slow command %d", myLogPrefix.c_str(), command); else ArLog::log(myVerboseLogLevel, "%sStoring slow command %s", myLogPrefix.c_str(), serverData->getName()); mySlowPacketsMutex.lock(); ArNetPacket *slowPacket = new ArNetPacket(packet->getLength() + 5); slowPacket->duplicatePacket(packet); mySlowPackets.push_back(slowPacket); mySlowPacketsMutex.unlock(); return; } if (command <= 255) ArLog::log(myVerboseLogLevel, "%sGot command %s", myLogPrefix.c_str(), serverData->getName()); else ArLog::log(ArLog::Verbose, "%sGot command %s", myLogPrefix.c_str(), serverData->getName()); pushCommand(command); pushForceTcpFlag(tcp); if (serverData->getFunctor() != NULL) serverData->getFunctor()->invoke(this, packet); if (serverData->getRequestOnceFunctor() != NULL) serverData->getRequestOnceFunctor()->invoke(this, packet); popCommand(); popForceTcpFlag(); return; } else { ArLog::log(ArLog::Terse, "%sRogue packet command %s in state %d", myLogPrefix.c_str(), findCommandName(packet->getCommand()), myState); } }
void ArServerClient::sendListPacket(void) { ArNetPacket packet; std::map<unsigned int, ArServerData *>::iterator it; unsigned int count; unsigned int shortLen; unsigned int longLen; ArServerData *serverData; // First we send a list of numbers, names and descriptions packet.setCommand(ArServerCommands::LIST); // number of entries (we'll overwrite it later with the right number) shortLen = packet.getLength(); packet.uByte2ToBuf(0); // loop through the data to build the packet for (it = myDataMap->begin(), count = 0; it != myDataMap->end(); it++) { serverData = (*it).second; if (myUserInfo == NULL || serverData->getCommandGroup() == NULL || serverData->getCommandGroup()[0] == '\0' || myGroups.count(serverData->getCommandGroup()) != 0 || myGroups.count("all") != 0) { count++; packet.uByte2ToBuf(serverData->getCommand()); packet.strToBuf(serverData->getName()); packet.strToBuf(serverData->getDescription()); } } // put the real number of entries in the right spot longLen = packet.getLength(); packet.setLength(shortLen); packet.uByte2ToBuf(count); packet.setLength(longLen); sendPacketTcp(&packet); // then we send a list of the arguments and returns... they aren't // combined so that the packet structure doesn't need to change packet.empty(); packet.setCommand(ArServerCommands::LISTARGRET); // number of entries (we'll overwrite it later with the right number) shortLen = packet.getLength(); packet.uByte2ToBuf(0); // loop through the data to build the packet for (it = myDataMap->begin(), count = 0; it != myDataMap->end(); it++) { serverData = (*it).second; if (myUserInfo == NULL || serverData->getCommandGroup() == NULL || serverData->getCommandGroup()[0] == '\0' || myGroups.count(serverData->getCommandGroup()) != 0 || myGroups.count("all") != 0) { count++; packet.uByte2ToBuf(serverData->getCommand()); packet.strToBuf(serverData->getArgumentDescription()); packet.strToBuf(serverData->getReturnDescription()); } } // put the real number of entries in the right spot longLen = packet.getLength(); packet.setLength(shortLen); packet.uByte2ToBuf(count); packet.setLength(longLen); sendPacketTcp(&packet); // then we send a list of command groups... they aren't // combined so that the packet structure doesn't need to change packet.empty(); packet.setCommand(ArServerCommands::LISTGROUPANDFLAGS); // number of entries (we'll overwrite it later with the right number) shortLen = packet.getLength(); packet.uByte2ToBuf(0); // loop through the data to build the packet for (it = myDataMap->begin(), count = 0; it != myDataMap->end(); it++) { serverData = (*it).second; if (myUserInfo == NULL || serverData->getCommandGroup() == NULL || serverData->getCommandGroup()[0] == '\0' || myGroups.count(serverData->getCommandGroup()) != 0 || myGroups.count("all") != 0) { count++; packet.uByte2ToBuf(serverData->getCommand()); packet.strToBuf(serverData->getCommandGroup()); packet.strToBuf(serverData->getDataFlagsString()); } } // put the real number of entries in the right spot longLen = packet.getLength(); packet.setLength(shortLen); packet.uByte2ToBuf(count); packet.setLength(longLen); sendPacketTcp(&packet); }