void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeType, bool shouldSendStats) { // change the logging target name while the assignment is running LogHandler::getInstance().setTargetName(targetName); NodeList* nodeList = NodeList::getInstance(); nodeList->setOwnerType(nodeType); // this is a temp fix for Qt 5.3 - rebinding the node socket gives us readyRead for the socket on this thread nodeList->rebindNodeSocket(); QTimer* domainServerTimer = new QTimer(this); connect(domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit())); domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS); QTimer* silentNodeRemovalTimer = new QTimer(this); connect(silentNodeRemovalTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); silentNodeRemovalTimer->start(NODE_SILENCE_THRESHOLD_MSECS); if (shouldSendStats) { // send a stats packet every 1 second QTimer* statsTimer = new QTimer(this); connect(statsTimer, &QTimer::timeout, this, &ThreadedAssignment::sendStatsPacket); statsTimer->start(1000); } }
void Agent::run() { NodeList* nodeList = NodeList::getInstance(); nodeList->setOwnerType(NodeType::Agent); nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer); // figure out the URL for the script for this agent assignment QString scriptURLString("http://%1:8080/assignment/%2"); scriptURLString = scriptURLString.arg(NodeList::getInstance()->getDomainIP().toString(), uuidStringWithoutCurlyBraces(_uuid)); QNetworkAccessManager *networkManager = new QNetworkAccessManager(this); QNetworkReply *reply = networkManager->get(QNetworkRequest(QUrl(scriptURLString))); qDebug() << "Downloading script at" << scriptURLString; QEventLoop loop; QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); loop.exec(); QString scriptContents(reply->readAll()); qDebug() << "Downloaded script:" << scriptContents; timeval startTime; gettimeofday(&startTime, NULL); QTimer* domainServerTimer = new QTimer(this); connect(domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit())); domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_USECS / 1000); QTimer* silentNodeTimer = new QTimer(this); connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000); QTimer* pingNodesTimer = new QTimer(this); connect(pingNodesTimer, SIGNAL(timeout()), nodeList, SLOT(pingInactiveNodes())); pingNodesTimer->start(PING_INACTIVE_NODE_INTERVAL_USECS / 1000); // tell our script engine about our local particle tree _scriptEngine.getParticlesScriptingInterface()->setParticleTree(&_particleTree); // setup an Avatar for the script to use AvatarData scriptedAvatar; // give this AvatarData object to the script engine _scriptEngine.setAvatarData(&scriptedAvatar, "Avatar"); // register ourselves to the script engine _scriptEngine.registerGlobalObject("Agent", this); _scriptEngine.setScriptContents(scriptContents); _scriptEngine.run(); }
void AssignmentClient::assignmentCompleted() { // reset the logging target to the the CHILD_TARGET_NAME Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); qDebug("Assignment finished or never started - waiting for new assignment\n"); _currentAssignment = NULL; NodeList* nodeList = NodeList::getInstance(); // reset our NodeList by switching back to unassigned and clearing the list nodeList->setOwnerType(NODE_TYPE_UNASSIGNED); nodeList->reset(); }
void ThreadedAssignment::commonInit(const QString& targetName, NodeType_t nodeType) { // change the logging target name while the assignment is running Logging::setTargetName(targetName); NodeList* nodeList = NodeList::getInstance(); nodeList->setOwnerType(nodeType); QTimer* domainServerTimer = new QTimer(this); connect(domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit())); domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_USECS / 1000); QTimer* pingNodesTimer = new QTimer(this); connect(pingNodesTimer, SIGNAL(timeout()), nodeList, SLOT(pingInactiveNodes())); pingNodesTimer->start(PING_INACTIVE_NODE_INTERVAL_USECS / 1000); QTimer* silentNodeRemovalTimer = new QTimer(this); connect(silentNodeRemovalTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); silentNodeRemovalTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000); }
void AssignmentClient::assignmentCompleted() { // reset the logging target to the the CHILD_TARGET_NAME Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); qDebug("Assignment finished or never started - waiting for new assignment."); NodeList* nodeList = NodeList::getInstance(); // have us handle incoming NodeList datagrams again disconnect(&nodeList->getNodeSocket(), 0, _currentAssignment, 0); connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams); _currentAssignment = NULL; // reset our NodeList by switching back to unassigned and clearing the list nodeList->setOwnerType(NodeType::Unassigned); nodeList->reset(); nodeList->resetNodeInterestSet(); }
void AssignmentClient::assignmentCompleted() { // reset the logging target to the the CHILD_TARGET_NAME LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); qDebug("Assignment finished or never started - waiting for new assignment."); NodeList* nodeList = NodeList::getInstance(); // have us handle incoming NodeList datagrams again disconnect(&nodeList->getNodeSocket(), 0, _currentAssignment.data(), 0); connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams); // clear our current assignment shared pointer now that we're done with it // if the assignment thread is still around it has its own shared pointer to the assignment _currentAssignment.clear(); // reset our NodeList by switching back to unassigned and clearing the list nodeList->setOwnerType(NodeType::Unassigned); nodeList->reset(); nodeList->resetNodeInterestSet(); }
void childClient() { // this is one of the child forks or there is a single assignment client, continue assignment-client execution // set the logging target to the the CHILD_TARGET_NAME Logging::setTargetName(CHILD_TARGET_NAME); // create a NodeList as an unassigned client NodeList* nodeList = NodeList::createInstance(NODE_TYPE_UNASSIGNED); // set the custom assignment socket if we have it if (customAssignmentSocket.sin_addr.s_addr != 0) { nodeList->setAssignmentServerSocket((sockaddr*) &customAssignmentSocket); } // change the timeout on the nodelist socket to be as often as we want to re-request nodeList->getNodeSocket()->setBlockingReceiveTimeoutInUsecs(ASSIGNMENT_REQUEST_INTERVAL_USECS); timeval lastRequest = {}; unsigned char packetData[MAX_PACKET_SIZE]; ssize_t receivedBytes = 0; sockaddr_in senderSocket = {}; // create a request assignment, accept assignments defined by the overidden type Assignment requestAssignment(Assignment::RequestCommand, ::overiddenAssignmentType); while (true) { if (usecTimestampNow() - usecTimestamp(&lastRequest) >= ASSIGNMENT_REQUEST_INTERVAL_USECS) { gettimeofday(&lastRequest, NULL); // if we're here we have no assignment, so send a request qDebug() << "Sending an assignment request -" << requestAssignment << "\n"; nodeList->sendAssignment(requestAssignment); } if (nodeList->getNodeSocket()->receive((sockaddr*) &senderSocket, packetData, &receivedBytes) && (packetData[0] == PACKET_TYPE_DEPLOY_ASSIGNMENT || packetData[0] == PACKET_TYPE_CREATE_ASSIGNMENT) && packetVersionMatch(packetData)) { // construct the deployed assignment from the packet data Assignment* deployedAssignment = AssignmentFactory::unpackAssignment(packetData, receivedBytes); qDebug() << "Received an assignment -" << *deployedAssignment << "\n"; // switch our nodelist domain IP and port to whoever sent us the assignment if (packetData[0] == PACKET_TYPE_CREATE_ASSIGNMENT) { nodeList->setDomainIP(QHostAddress((sockaddr*) &senderSocket)); nodeList->setDomainPort(ntohs(senderSocket.sin_port)); qDebug("Destination IP for assignment is %s\n", nodeList->getDomainIP().toString().toStdString().c_str()); // run the deployed assignment deployedAssignment->run(); } else { qDebug("Received a bad destination socket for assignment.\n"); } qDebug("Assignment finished or never started - waiting for new assignment\n"); // delete the deployedAssignment delete deployedAssignment; // reset our NodeList by switching back to unassigned and clearing the list nodeList->setOwnerType(NODE_TYPE_UNASSIGNED); nodeList->reset(); // reset the logging target to the the CHILD_TARGET_NAME Logging::setTargetName(CHILD_TARGET_NAME); } } }
void OctreeServer::run() { // Before we do anything else, create our tree... _tree = createTree(); // change the logging target name while this is running Logging::setTargetName(getMyLoggingServerTargetName()); // Now would be a good time to parse our arguments, if we got them as assignment if (getNumPayloadBytes() > 0) { parsePayload(); } beforeRun(); // after payload has been processed qInstallMessageHandler(Logging::verboseMessageHandler); const char* STATUS_PORT = "--statusPort"; const char* statusPort = getCmdOption(_argc, _argv, STATUS_PORT); if (statusPort) { int statusPortNumber = atoi(statusPort); initMongoose(statusPortNumber); } const char* JURISDICTION_FILE = "--jurisdictionFile"; const char* jurisdictionFile = getCmdOption(_argc, _argv, JURISDICTION_FILE); if (jurisdictionFile) { qDebug("jurisdictionFile=%s\n", jurisdictionFile); qDebug("about to readFromFile().... jurisdictionFile=%s\n", jurisdictionFile); _jurisdiction = new JurisdictionMap(jurisdictionFile); qDebug("after readFromFile().... jurisdictionFile=%s\n", jurisdictionFile); } else { const char* JURISDICTION_ROOT = "--jurisdictionRoot"; const char* jurisdictionRoot = getCmdOption(_argc, _argv, JURISDICTION_ROOT); if (jurisdictionRoot) { qDebug("jurisdictionRoot=%s\n", jurisdictionRoot); } const char* JURISDICTION_ENDNODES = "--jurisdictionEndNodes"; const char* jurisdictionEndNodes = getCmdOption(_argc, _argv, JURISDICTION_ENDNODES); if (jurisdictionEndNodes) { qDebug("jurisdictionEndNodes=%s\n", jurisdictionEndNodes); } if (jurisdictionRoot || jurisdictionEndNodes) { _jurisdiction = new JurisdictionMap(jurisdictionRoot, jurisdictionEndNodes); } } NodeList* nodeList = NodeList::getInstance(); nodeList->setOwnerType(getMyNodeType()); // we need to ask the DS about agents so we can ping/reply with them const char nodeTypesOfInterest[] = { NODE_TYPE_AGENT, NODE_TYPE_ANIMATION_SERVER}; nodeList->setNodeTypesOfInterest(nodeTypesOfInterest, sizeof(nodeTypesOfInterest)); setvbuf(stdout, NULL, _IOLBF, 0); // tell our NodeList about our desire to get notifications nodeList->addHook(this); nodeList->linkedDataCreateCallback = &OctreeServer::attachQueryNodeToNode; srand((unsigned)time(0)); const char* VERBOSE_DEBUG = "--verboseDebug"; _verboseDebug = cmdOptionExists(_argc, _argv, VERBOSE_DEBUG); qDebug("verboseDebug=%s\n", debug::valueOf(_verboseDebug)); const char* DEBUG_SENDING = "--debugSending"; _debugSending = cmdOptionExists(_argc, _argv, DEBUG_SENDING); qDebug("debugSending=%s\n", debug::valueOf(_debugSending)); const char* DEBUG_RECEIVING = "--debugReceiving"; _debugReceiving = cmdOptionExists(_argc, _argv, DEBUG_RECEIVING); qDebug("debugReceiving=%s\n", debug::valueOf(_debugReceiving)); // By default we will persist, if you want to disable this, then pass in this parameter const char* NO_PERSIST = "--NoPersist"; if (cmdOptionExists(_argc, _argv, NO_PERSIST)) { _wantPersist = false; } qDebug("wantPersist=%s\n", debug::valueOf(_wantPersist)); // if we want Persistence, set up the local file and persist thread if (_wantPersist) { // Check to see if the user passed in a command line option for setting packet send rate const char* PERSIST_FILENAME = "--persistFilename"; const char* persistFilenameParameter = getCmdOption(_argc, _argv, PERSIST_FILENAME); if (persistFilenameParameter) { strcpy(_persistFilename, persistFilenameParameter); } else { strcpy(_persistFilename, getMyDefaultPersistFilename()); } qDebug("persistFilename=%s\n", _persistFilename); // now set up PersistThread _persistThread = new OctreePersistThread(_tree, _persistFilename); if (_persistThread) { _persistThread->initialize(true); } } // Debug option to demonstrate that the server's local time does not // need to be in sync with any other network node. This forces clock // skew for the individual server node const char* CLOCK_SKEW = "--clockSkew"; const char* clockSkewOption = getCmdOption(_argc, _argv, CLOCK_SKEW); if (clockSkewOption) { int clockSkew = atoi(clockSkewOption); usecTimestampNowForceClockSkew(clockSkew); qDebug("clockSkewOption=%s clockSkew=%d\n", clockSkewOption, clockSkew); } // Check to see if the user passed in a command line option for setting packet send rate const char* PACKETS_PER_SECOND = "--packetsPerSecond"; const char* packetsPerSecond = getCmdOption(_argc, _argv, PACKETS_PER_SECOND); if (packetsPerSecond) { _packetsPerClientPerInterval = atoi(packetsPerSecond) / INTERVALS_PER_SECOND; if (_packetsPerClientPerInterval < 1) { _packetsPerClientPerInterval = 1; } qDebug("packetsPerSecond=%s PACKETS_PER_CLIENT_PER_INTERVAL=%d\n", packetsPerSecond, _packetsPerClientPerInterval); } HifiSockAddr senderSockAddr; // set up our jurisdiction broadcaster... if (_jurisdiction) { _jurisdiction->setNodeType(getMyNodeType()); } _jurisdictionSender = new JurisdictionSender(_jurisdiction, getMyNodeType()); _jurisdictionSender->initialize(true); // set up our OctreeServerPacketProcessor _octreeInboundPacketProcessor = new OctreeInboundPacketProcessor(this); _octreeInboundPacketProcessor->initialize(true); // Convert now to tm struct for local timezone tm* localtm = localtime(&_started); const int MAX_TIME_LENGTH = 128; char localBuffer[MAX_TIME_LENGTH] = { 0 }; char utcBuffer[MAX_TIME_LENGTH] = { 0 }; strftime(localBuffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", localtm); // Convert now to tm struct for UTC tm* gmtm = gmtime(&_started); if (gmtm != NULL) { strftime(utcBuffer, MAX_TIME_LENGTH, " [%m/%d/%Y %X UTC]", gmtm); } qDebug() << "Now running... started at: " << localBuffer << utcBuffer << "\n"; QTimer* domainServerTimer = new QTimer(this); connect(domainServerTimer, SIGNAL(timeout()), this, SLOT(checkInWithDomainServerOrExit())); domainServerTimer->start(DOMAIN_SERVER_CHECK_IN_USECS / 1000); QTimer* silentNodeTimer = new QTimer(this); connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000); QTimer* pingNodesTimer = new QTimer(this); connect(pingNodesTimer, SIGNAL(timeout()), nodeList, SLOT(pingInactiveNodes())); pingNodesTimer->start(PING_INACTIVE_NODE_INTERVAL_USECS / 1000); }
void Agent::run() { NodeList* nodeList = NodeList::getInstance(); nodeList->setOwnerType(NODE_TYPE_AGENT); const char AGENT_NODE_TYPES_OF_INTEREST[2] = { NODE_TYPE_VOXEL_SERVER, NODE_TYPE_AUDIO_MIXER }; nodeList->setNodeTypesOfInterest(AGENT_NODE_TYPES_OF_INTEREST, sizeof(AGENT_NODE_TYPES_OF_INTEREST)); nodeList->getNodeSocket()->setBlocking(false); // figure out the URL for the script for this agent assignment QString scriptURLString("http://%1:8080/assignment/%2"); scriptURLString = scriptURLString.arg(NodeList::getInstance()->getDomainIP().toString(), uuidStringWithoutCurlyBraces(_uuid)); // setup curl for script download CURLcode curlResult; CURL* curlHandle = curl_easy_init(); // tell curl which file to grab curl_easy_setopt(curlHandle, CURLOPT_URL, scriptURLString.toStdString().c_str()); // send the data to the WriteMemoryCallback function curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, writeScriptDataToString); QString scriptContents; // pass the scriptContents QString to append data to curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, (void *)&scriptContents); // send a user agent since some servers will require it curl_easy_setopt(curlHandle, CURLOPT_USERAGENT, "libcurl-agent/1.0"); // make sure CURL fails on a 400 code curl_easy_setopt(curlHandle, CURLOPT_FAILONERROR, true); qDebug() << "Downloading script at" << scriptURLString << "\n"; // blocking get for JS file curlResult = curl_easy_perform(curlHandle); if (curlResult == CURLE_OK) { // cleanup curl curl_easy_cleanup(curlHandle); curl_global_cleanup(); QScriptEngine engine; // register meta-type for glm::vec3 conversions qScriptRegisterMetaType(&engine, vec3toScriptValue, vec3FromScriptValue); QScriptValue agentValue = engine.newQObject(this); engine.globalObject().setProperty("Agent", agentValue); VoxelScriptingInterface voxelScripter; QScriptValue voxelScripterValue = engine.newQObject(&voxelScripter); engine.globalObject().setProperty("Voxels", voxelScripterValue); QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE)); engine.globalObject().setProperty("TREE_SCALE", treeScaleValue); // let the VoxelPacketSender know how frequently we plan to call it voxelScripter.getVoxelPacketSender()->setProcessCallIntervalHint(INJECT_INTERVAL_USECS); // hook in a constructor for audio injectorss AudioInjector scriptedAudioInjector(BUFFER_LENGTH_SAMPLES_PER_CHANNEL); QScriptValue audioInjectorValue = engine.newQObject(&scriptedAudioInjector); engine.globalObject().setProperty("AudioInjector", audioInjectorValue); qDebug() << "Downloaded script:" << scriptContents << "\n"; QScriptValue result = engine.evaluate(scriptContents); qDebug() << "Evaluated script.\n"; if (engine.hasUncaughtException()) { int line = engine.uncaughtExceptionLineNumber(); qDebug() << "Uncaught exception at line" << line << ":" << result.toString() << "\n"; } timeval startTime; gettimeofday(&startTime, NULL); timeval lastDomainServerCheckIn = {}; sockaddr_in senderAddress; unsigned char receivedData[MAX_PACKET_SIZE]; ssize_t receivedBytes; int thisFrame = 0; NodeList::getInstance()->startSilentNodeRemovalThread(); while (!_shouldStop) { // if we're not hearing from the domain-server we should stop running if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { break; } // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) { gettimeofday(&lastDomainServerCheckIn, NULL); NodeList::getInstance()->sendDomainServerCheckIn(); } // find the audio-mixer in the NodeList so we can inject audio at it Node* audioMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AUDIO_MIXER); if (audioMixer && audioMixer->getActiveSocket()) { emit willSendAudioDataCallback(); } int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * INJECT_INTERVAL_USECS) - usecTimestampNow(); if (usecToSleep > 0) { usleep(usecToSleep); } if (audioMixer && audioMixer->getActiveSocket() && scriptedAudioInjector.hasSamplesToInject()) { // we have an audio mixer and samples to inject, send those off scriptedAudioInjector.injectAudio(NodeList::getInstance()->getNodeSocket(), audioMixer->getActiveSocket()); // clear out the audio injector so that it doesn't re-send what we just sent scriptedAudioInjector.clear(); } if (audioMixer && !audioMixer->getActiveSocket()) { // don't have an active socket for the audio-mixer, ping it now NodeList::getInstance()->pingPublicAndLocalSocketsForInactiveNode(audioMixer); } if (voxelScripter.getVoxelPacketSender()->voxelServersExist()) { // allow the scripter's call back to setup visual data emit willSendVisualDataCallback(); // release the queue of edit voxel messages. voxelScripter.getVoxelPacketSender()->releaseQueuedMessages(); // since we're in non-threaded mode, call process so that the packets are sent voxelScripter.getVoxelPacketSender()->process(); } if (engine.hasUncaughtException()) { int line = engine.uncaughtExceptionLineNumber(); qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n"; } while (NodeList::getInstance()->getNodeSocket()->receive((sockaddr*) &senderAddress, receivedData, &receivedBytes) && packetVersionMatch(receivedData)) { if (receivedData[0] == PACKET_TYPE_VOXEL_JURISDICTION) { voxelScripter.getJurisdictionListener()->queueReceivedPacket((sockaddr&) senderAddress, receivedData, receivedBytes); } else { NodeList::getInstance()->processNodeData((sockaddr*) &senderAddress, receivedData, receivedBytes); } } } NodeList::getInstance()->stopSilentNodeRemovalThread(); } else { // error in curl_easy_perform qDebug() << "curl_easy_perform for JS failed:" << curl_easy_strerror(curlResult) << "\n"; // cleanup curl curl_easy_cleanup(curlHandle); curl_global_cleanup(); } }
void AvatarMixer::run() { // change the logging target name while AvatarMixer is running Logging::setTargetName(AVATAR_MIXER_LOGGING_NAME); NodeList* nodeList = NodeList::getInstance(); nodeList->setOwnerType(NODE_TYPE_AVATAR_MIXER); nodeList->setNodeTypesOfInterest(&NODE_TYPE_AGENT, 1); nodeList->linkedDataCreateCallback = attachAvatarDataToNode; nodeList->startSilentNodeRemovalThread(); sockaddr nodeAddress = {}; ssize_t receivedBytes = 0; unsigned char packetData[MAX_PACKET_SIZE]; QUuid nodeUUID; Node* avatarNode = NULL; timeval lastDomainServerCheckIn = {}; while (true) { if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { break; } // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) { gettimeofday(&lastDomainServerCheckIn, NULL); NodeList::getInstance()->sendDomainServerCheckIn(); } nodeList->possiblyPingInactiveNodes(); if (nodeList->getNodeSocket()->receive(&nodeAddress, packetData, &receivedBytes) && packetVersionMatch(packetData)) { switch (packetData[0]) { case PACKET_TYPE_HEAD_DATA: nodeUUID = QUuid::fromRfc4122(QByteArray((char*) packetData + numBytesForPacketHeader(packetData), NUM_BYTES_RFC4122_UUID)); // add or update the node in our list avatarNode = nodeList->nodeWithUUID(nodeUUID); if (avatarNode) { // parse positional data from an node nodeList->updateNodeWithData(avatarNode, &nodeAddress, packetData, receivedBytes); } else { break; } case PACKET_TYPE_INJECT_AUDIO: broadcastAvatarData(nodeList, nodeUUID, &nodeAddress); break; case PACKET_TYPE_AVATAR_URLS: case PACKET_TYPE_AVATAR_FACE_VIDEO: nodeUUID = QUuid::fromRfc4122(QByteArray((char*) packetData + numBytesForPacketHeader(packetData), NUM_BYTES_RFC4122_UUID)); // let everyone else know about the update for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { if (node->getActiveSocket() && node->getUUID() != nodeUUID) { nodeList->getNodeSocket()->send(node->getActiveSocket(), packetData, receivedBytes); } } break; default: // hand this off to the NodeList nodeList->processNodeData(&nodeAddress, packetData, receivedBytes); break; } } } nodeList->stopSilentNodeRemovalThread(); }
void AvatarMixer::run() { // change the logging target name while AvatarMixer is running Logging::setTargetName(AVATAR_MIXER_LOGGING_NAME); NodeList* nodeList = NodeList::getInstance(); nodeList->setOwnerType(NODE_TYPE_AVATAR_MIXER); nodeList->linkedDataCreateCallback = attachAvatarDataToNode; nodeList->startSilentNodeRemovalThread(); sockaddr* nodeAddress = new sockaddr; ssize_t receivedBytes = 0; unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE]; uint16_t nodeID = 0; Node* avatarNode = NULL; timeval lastDomainServerCheckIn = {}; // we only need to hear back about avatar nodes from the DS nodeList->setNodeTypesOfInterest(&NODE_TYPE_AGENT, 1); while (true) { if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { break; } // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) { gettimeofday(&lastDomainServerCheckIn, NULL); NodeList::getInstance()->sendDomainServerCheckIn(); } if (nodeList->getNodeSocket()->receive(nodeAddress, packetData, &receivedBytes) && packetVersionMatch(packetData)) { switch (packetData[0]) { case PACKET_TYPE_HEAD_DATA: // grab the node ID from the packet unpackNodeId(packetData + numBytesForPacketHeader(packetData), &nodeID); // add or update the node in our list avatarNode = nodeList->addOrUpdateNode(nodeAddress, nodeAddress, NODE_TYPE_AGENT, nodeID); // parse positional data from an node nodeList->updateNodeWithData(avatarNode, packetData, receivedBytes); case PACKET_TYPE_INJECT_AUDIO: broadcastAvatarData(nodeList, nodeAddress); break; case PACKET_TYPE_AVATAR_VOXEL_URL: case PACKET_TYPE_AVATAR_FACE_VIDEO: // grab the node ID from the packet unpackNodeId(packetData + numBytesForPacketHeader(packetData), &nodeID); // let everyone else know about the update for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { if (node->getActiveSocket() && node->getNodeID() != nodeID) { nodeList->getNodeSocket()->send(node->getActiveSocket(), packetData, receivedBytes); } } break; default: // hand this off to the NodeList nodeList->processNodeData(nodeAddress, packetData, receivedBytes); break; } } } nodeList->stopSilentNodeRemovalThread(); }
//int main(int argc, const char * argv[]) { void VoxelServer::run() { const char VOXEL_SERVER_LOGGING_TARGET_NAME[] = "voxel-server"; // change the logging target name while this is running Logging::setTargetName(VOXEL_SERVER_LOGGING_TARGET_NAME); // Now would be a good time to parse our arguments, if we got them as assignment if (getNumPayloadBytes() > 0) { parsePayload(); } qInstallMessageHandler(Logging::verboseMessageHandler); const char* STATUS_PORT = "--statusPort"; const char* statusPort = getCmdOption(_argc, _argv, STATUS_PORT); if (statusPort) { int statusPortNumber = atoi(statusPort); initMongoose(statusPortNumber); } const char* JURISDICTION_FILE = "--jurisdictionFile"; const char* jurisdictionFile = getCmdOption(_argc, _argv, JURISDICTION_FILE); if (jurisdictionFile) { qDebug("jurisdictionFile=%s\n", jurisdictionFile); qDebug("about to readFromFile().... jurisdictionFile=%s\n", jurisdictionFile); _jurisdiction = new JurisdictionMap(jurisdictionFile); qDebug("after readFromFile().... jurisdictionFile=%s\n", jurisdictionFile); } else { const char* JURISDICTION_ROOT = "--jurisdictionRoot"; const char* jurisdictionRoot = getCmdOption(_argc, _argv, JURISDICTION_ROOT); if (jurisdictionRoot) { qDebug("jurisdictionRoot=%s\n", jurisdictionRoot); } const char* JURISDICTION_ENDNODES = "--jurisdictionEndNodes"; const char* jurisdictionEndNodes = getCmdOption(_argc, _argv, JURISDICTION_ENDNODES); if (jurisdictionEndNodes) { qDebug("jurisdictionEndNodes=%s\n", jurisdictionEndNodes); } if (jurisdictionRoot || jurisdictionEndNodes) { _jurisdiction = new JurisdictionMap(jurisdictionRoot, jurisdictionEndNodes); } } // should we send environments? Default is yes, but this command line suppresses sending const char* DUMP_VOXELS_ON_MOVE = "--dumpVoxelsOnMove"; _dumpVoxelsOnMove = cmdOptionExists(_argc, _argv, DUMP_VOXELS_ON_MOVE); qDebug("dumpVoxelsOnMove=%s\n", debug::valueOf(_dumpVoxelsOnMove)); // should we send environments? Default is yes, but this command line suppresses sending const char* SEND_ENVIRONMENTS = "--sendEnvironments"; bool dontSendEnvironments = !cmdOptionExists(_argc, _argv, SEND_ENVIRONMENTS); if (dontSendEnvironments) { qDebug("Sending environments suppressed...\n"); _sendEnvironments = false; } else { // should we send environments? Default is yes, but this command line suppresses sending const char* MINIMAL_ENVIRONMENT = "--minimalEnvironment"; _sendMinimalEnvironment = cmdOptionExists(_argc, _argv, MINIMAL_ENVIRONMENT); qDebug("Using Minimal Environment=%s\n", debug::valueOf(_sendMinimalEnvironment)); } qDebug("Sending environments=%s\n", debug::valueOf(_sendEnvironments)); NodeList* nodeList = NodeList::getInstance(); nodeList->setOwnerType(NODE_TYPE_VOXEL_SERVER); // we need to ask the DS about agents so we can ping/reply with them const char nodeTypesOfInterest[] = { NODE_TYPE_AGENT, NODE_TYPE_ANIMATION_SERVER}; nodeList->setNodeTypesOfInterest(nodeTypesOfInterest, sizeof(nodeTypesOfInterest)); setvbuf(stdout, NULL, _IOLBF, 0); // tell our NodeList about our desire to get notifications nodeList->addHook(&_nodeWatcher); nodeList->linkedDataCreateCallback = &attachVoxelNodeDataToNode; nodeList->startSilentNodeRemovalThread(); srand((unsigned)time(0)); const char* DISPLAY_VOXEL_STATS = "--displayVoxelStats"; _displayVoxelStats = cmdOptionExists(_argc, _argv, DISPLAY_VOXEL_STATS); qDebug("displayVoxelStats=%s\n", debug::valueOf(_displayVoxelStats)); const char* VERBOSE_DEBUG = "--verboseDebug"; _verboseDebug = cmdOptionExists(_argc, _argv, VERBOSE_DEBUG); qDebug("verboseDebug=%s\n", debug::valueOf(_verboseDebug)); const char* DEBUG_VOXEL_SENDING = "--debugVoxelSending"; _debugVoxelSending = cmdOptionExists(_argc, _argv, DEBUG_VOXEL_SENDING); qDebug("debugVoxelSending=%s\n", debug::valueOf(_debugVoxelSending)); const char* DEBUG_VOXEL_RECEIVING = "--debugVoxelReceiving"; _debugVoxelReceiving = cmdOptionExists(_argc, _argv, DEBUG_VOXEL_RECEIVING); qDebug("debugVoxelReceiving=%s\n", debug::valueOf(_debugVoxelReceiving)); const char* WANT_ANIMATION_DEBUG = "--shouldShowAnimationDebug"; _shouldShowAnimationDebug = cmdOptionExists(_argc, _argv, WANT_ANIMATION_DEBUG); qDebug("shouldShowAnimationDebug=%s\n", debug::valueOf(_shouldShowAnimationDebug)); // By default we will voxel persist, if you want to disable this, then pass in this parameter const char* NO_VOXEL_PERSIST = "--NoVoxelPersist"; if (cmdOptionExists(_argc, _argv, NO_VOXEL_PERSIST)) { _wantVoxelPersist = false; } qDebug("wantVoxelPersist=%s\n", debug::valueOf(_wantVoxelPersist)); // if we want Voxel Persistence, set up the local file and persist thread if (_wantVoxelPersist) { // Check to see if the user passed in a command line option for setting packet send rate const char* VOXELS_PERSIST_FILENAME = "--voxelsPersistFilename"; const char* voxelsPersistFilenameParameter = getCmdOption(_argc, _argv, VOXELS_PERSIST_FILENAME); if (voxelsPersistFilenameParameter) { strcpy(_voxelPersistFilename, voxelsPersistFilenameParameter); } else { //strcpy(voxelPersistFilename, _wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE); strcpy(_voxelPersistFilename, LOCAL_VOXELS_PERSIST_FILE); } qDebug("voxelPersistFilename=%s\n", _voxelPersistFilename); // now set up VoxelPersistThread _voxelPersistThread = new VoxelPersistThread(&_serverTree, _voxelPersistFilename); if (_voxelPersistThread) { _voxelPersistThread->initialize(true); } } // Check to see if the user passed in a command line option for loading an old style local // Voxel File. If so, load it now. This is not the same as a voxel persist file const char* INPUT_FILE = "-i"; const char* voxelsFilename = getCmdOption(_argc, _argv, INPUT_FILE); if (voxelsFilename) { _serverTree.readFromSVOFile(voxelsFilename); } // Check to see if the user passed in a command line option for setting packet send rate const char* PACKETS_PER_SECOND = "--packetsPerSecond"; const char* packetsPerSecond = getCmdOption(_argc, _argv, PACKETS_PER_SECOND); if (packetsPerSecond) { _packetsPerClientPerInterval = atoi(packetsPerSecond) / INTERVALS_PER_SECOND; if (_packetsPerClientPerInterval < 1) { _packetsPerClientPerInterval = 1; } qDebug("packetsPerSecond=%s PACKETS_PER_CLIENT_PER_INTERVAL=%d\n", packetsPerSecond, _packetsPerClientPerInterval); } sockaddr senderAddress; unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE]; ssize_t packetLength; timeval lastDomainServerCheckIn = {}; // set up our jurisdiction broadcaster... _jurisdictionSender = new JurisdictionSender(_jurisdiction); if (_jurisdictionSender) { _jurisdictionSender->initialize(true); } // set up our VoxelServerPacketProcessor _voxelServerPacketProcessor = new VoxelServerPacketProcessor(this); if (_voxelServerPacketProcessor) { _voxelServerPacketProcessor->initialize(true); } // Convert now to tm struct for local timezone tm* localtm = localtime(&_started); const int MAX_TIME_LENGTH = 128; char localBuffer[MAX_TIME_LENGTH] = { 0 }; char utcBuffer[MAX_TIME_LENGTH] = { 0 }; strftime(localBuffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", localtm); // Convert now to tm struct for UTC tm* gmtm = gmtime(&_started); if (gmtm != NULL) { strftime(utcBuffer, MAX_TIME_LENGTH, " [%m/%d/%Y %X UTC]", gmtm); } qDebug() << "Now running... started at: " << localBuffer << utcBuffer << "\n"; // loop to send to nodes requesting data while (true) { // check for >= in case one gets past the goalie if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { qDebug() << "Exit loop... getInstance()->getNumNoReplyDomainCheckIns() >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS\n"; break; } // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) { gettimeofday(&lastDomainServerCheckIn, NULL); NodeList::getInstance()->sendDomainServerCheckIn(); } // ping our inactive nodes to punch holes with them nodeList->possiblyPingInactiveNodes(); if (nodeList->getNodeSocket()->receive(&senderAddress, packetData, &packetLength) && packetVersionMatch(packetData)) { int numBytesPacketHeader = numBytesForPacketHeader(packetData); if (packetData[0] == PACKET_TYPE_VOXEL_QUERY) { // If we got a PACKET_TYPE_VOXEL_QUERY, then we're talking to an NODE_TYPE_AVATAR, and we // need to make sure we have it in our nodeList. QUuid nodeUUID = QUuid::fromRfc4122(QByteArray((char*)packetData + numBytesPacketHeader, NUM_BYTES_RFC4122_UUID)); Node* node = nodeList->nodeWithUUID(nodeUUID); if (node) { nodeList->updateNodeWithData(node, &senderAddress, packetData, packetLength); if (!node->getActiveSocket()) { // we don't have an active socket for this node, but they're talking to us // this means they've heard from us and can reply, let's assume public is active node->activatePublicSocket(); } VoxelNodeData* nodeData = (VoxelNodeData*) node->getLinkedData(); if (nodeData && !nodeData->isVoxelSendThreadInitalized()) { nodeData->initializeVoxelSendThread(this); } } } else if (packetData[0] == PACKET_TYPE_VOXEL_JURISDICTION_REQUEST) { if (_jurisdictionSender) { _jurisdictionSender->queueReceivedPacket(senderAddress, packetData, packetLength); } } else if (_voxelServerPacketProcessor && (packetData[0] == PACKET_TYPE_SET_VOXEL || packetData[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE || packetData[0] == PACKET_TYPE_ERASE_VOXEL || packetData[0] == PACKET_TYPE_Z_COMMAND)) { const char* messageName; switch (packetData[0]) { case PACKET_TYPE_SET_VOXEL: messageName = "PACKET_TYPE_SET_VOXEL"; break; case PACKET_TYPE_SET_VOXEL_DESTRUCTIVE: messageName = "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE"; break; case PACKET_TYPE_ERASE_VOXEL: messageName = "PACKET_TYPE_ERASE_VOXEL"; break; } int numBytesPacketHeader = numBytesForPacketHeader(packetData); if (packetData[0] != PACKET_TYPE_Z_COMMAND) { unsigned short int sequence = (*((unsigned short int*)(packetData + numBytesPacketHeader))); uint64_t sentAt = (*((uint64_t*)(packetData + numBytesPacketHeader + sizeof(sequence)))); uint64_t arrivedAt = usecTimestampNow(); uint64_t transitTime = arrivedAt - sentAt; if (wantShowAnimationDebug() || wantsDebugVoxelReceiving()) { printf("RECEIVE THREAD: got %s - command from client receivedBytes=%ld sequence=%d transitTime=%llu usecs\n", messageName, packetLength, sequence, transitTime); } } _voxelServerPacketProcessor->queueReceivedPacket(senderAddress, packetData, packetLength); } else { // let processNodeData handle it. NodeList::getInstance()->processNodeData(&senderAddress, packetData, packetLength); } } } // call NodeList::clear() so that all of our node specific objects, including our sending threads, are // properly shutdown and cleaned up. NodeList::getInstance()->clear(); if (_jurisdictionSender) { _jurisdictionSender->terminate(); delete _jurisdictionSender; } if (_voxelServerPacketProcessor) { _voxelServerPacketProcessor->terminate(); delete _voxelServerPacketProcessor; } if (_voxelPersistThread) { _voxelPersistThread->terminate(); delete _voxelPersistThread; } // tell our NodeList we're done with notifications nodeList->removeHook(&_nodeWatcher); delete _jurisdiction; _jurisdiction = NULL; qDebug() << "VoxelServer::run()... DONE\n"; }
//int main(int argc, const char * argv[]) { void VoxelServer::run() { const char VOXEL_SERVER_LOGGING_TARGET_NAME[] = "voxel-server"; // change the logging target name while this is running Logging::setTargetName(VOXEL_SERVER_LOGGING_TARGET_NAME); // Now would be a good time to parse our arguments, if we got them as assignment if (getNumPayloadBytes() > 0) { parsePayload(); } pthread_mutex_init(&_treeLock, NULL); qInstallMessageHandler(Logging::verboseMessageHandler); const char* JURISDICTION_FILE = "--jurisdictionFile"; const char* jurisdictionFile = getCmdOption(_argc, _argv, JURISDICTION_FILE); if (jurisdictionFile) { qDebug("jurisdictionFile=%s\n", jurisdictionFile); qDebug("about to readFromFile().... jurisdictionFile=%s\n", jurisdictionFile); _jurisdiction = new JurisdictionMap(jurisdictionFile); qDebug("after readFromFile().... jurisdictionFile=%s\n", jurisdictionFile); } else { const char* JURISDICTION_ROOT = "--jurisdictionRoot"; const char* jurisdictionRoot = getCmdOption(_argc, _argv, JURISDICTION_ROOT); if (jurisdictionRoot) { qDebug("jurisdictionRoot=%s\n", jurisdictionRoot); } const char* JURISDICTION_ENDNODES = "--jurisdictionEndNodes"; const char* jurisdictionEndNodes = getCmdOption(_argc, _argv, JURISDICTION_ENDNODES); if (jurisdictionEndNodes) { qDebug("jurisdictionEndNodes=%s\n", jurisdictionEndNodes); } if (jurisdictionRoot || jurisdictionEndNodes) { _jurisdiction = new JurisdictionMap(jurisdictionRoot, jurisdictionEndNodes); } } // should we send environments? Default is yes, but this command line suppresses sending const char* DUMP_VOXELS_ON_MOVE = "--dumpVoxelsOnMove"; _dumpVoxelsOnMove = cmdOptionExists(_argc, _argv, DUMP_VOXELS_ON_MOVE); qDebug("dumpVoxelsOnMove=%s\n", debug::valueOf(_dumpVoxelsOnMove)); // should we send environments? Default is yes, but this command line suppresses sending const char* DONT_SEND_ENVIRONMENTS = "--dontSendEnvironments"; bool dontSendEnvironments = getCmdOption(_argc, _argv, DONT_SEND_ENVIRONMENTS); if (dontSendEnvironments) { qDebug("Sending environments suppressed...\n"); _sendEnvironments = false; } else { // should we send environments? Default is yes, but this command line suppresses sending const char* MINIMAL_ENVIRONMENT = "--MinimalEnvironment"; _sendMinimalEnvironment = getCmdOption(_argc, _argv, MINIMAL_ENVIRONMENT); qDebug("Using Minimal Environment=%s\n", debug::valueOf(_sendMinimalEnvironment)); } qDebug("Sending environments=%s\n", debug::valueOf(_sendEnvironments)); NodeList* nodeList = NodeList::getInstance(); nodeList->setOwnerType(NODE_TYPE_VOXEL_SERVER); setvbuf(stdout, NULL, _IOLBF, 0); // tell our NodeList about our desire to get notifications nodeList->addHook(&_nodeWatcher); nodeList->linkedDataCreateCallback = &attachVoxelNodeDataToNode; nodeList->startSilentNodeRemovalThread(); srand((unsigned)time(0)); const char* DISPLAY_VOXEL_STATS = "--displayVoxelStats"; _displayVoxelStats = getCmdOption(_argc, _argv, DISPLAY_VOXEL_STATS); qDebug("displayVoxelStats=%s\n", debug::valueOf(_displayVoxelStats)); const char* DEBUG_VOXEL_SENDING = "--debugVoxelSending"; _debugVoxelSending = getCmdOption(_argc, _argv, DEBUG_VOXEL_SENDING); qDebug("debugVoxelSending=%s\n", debug::valueOf(_debugVoxelSending)); const char* DEBUG_VOXEL_RECEIVING = "--debugVoxelReceiving"; _debugVoxelReceiving = getCmdOption(_argc, _argv, DEBUG_VOXEL_RECEIVING); qDebug("debugVoxelReceiving=%s\n", debug::valueOf(_debugVoxelReceiving)); const char* WANT_ANIMATION_DEBUG = "--shouldShowAnimationDebug"; _shouldShowAnimationDebug = getCmdOption(_argc, _argv, WANT_ANIMATION_DEBUG); qDebug("shouldShowAnimationDebug=%s\n", debug::valueOf(_shouldShowAnimationDebug)); // By default we will voxel persist, if you want to disable this, then pass in this parameter const char* NO_VOXEL_PERSIST = "--NoVoxelPersist"; if (getCmdOption(_argc, _argv, NO_VOXEL_PERSIST)) { _wantVoxelPersist = false; } qDebug("wantVoxelPersist=%s\n", debug::valueOf(_wantVoxelPersist)); // if we want Voxel Persistence, load the local file now... bool persistantFileRead = false; if (_wantVoxelPersist) { // Check to see if the user passed in a command line option for setting packet send rate const char* VOXELS_PERSIST_FILENAME = "--voxelsPersistFilename"; const char* voxelsPersistFilenameParameter = getCmdOption(_argc, _argv, VOXELS_PERSIST_FILENAME); if (voxelsPersistFilenameParameter) { strcpy(_voxelPersistFilename, voxelsPersistFilenameParameter); } else { //strcpy(voxelPersistFilename, _wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE); strcpy(_voxelPersistFilename, LOCAL_VOXELS_PERSIST_FILE); } qDebug("loading voxels from file: %s...\n", _voxelPersistFilename); persistantFileRead = _serverTree.readFromSVOFile(_voxelPersistFilename); if (persistantFileRead) { PerformanceWarning warn(_shouldShowAnimationDebug, "persistVoxelsWhenDirty() - reaverageVoxelColors()", _shouldShowAnimationDebug); // after done inserting all these voxels, then reaverage colors _serverTree.reaverageVoxelColors(_serverTree.rootNode); qDebug("Voxels reAveraged\n"); } _serverTree.clearDirtyBit(); // the tree is clean since we just loaded it qDebug("DONE loading voxels from file... fileRead=%s\n", debug::valueOf(persistantFileRead)); unsigned long nodeCount = _serverTree.rootNode->getSubTreeNodeCount(); unsigned long internalNodeCount = _serverTree.rootNode->getSubTreeInternalNodeCount(); unsigned long leafNodeCount = _serverTree.rootNode->getSubTreeLeafNodeCount(); qDebug("Nodes after loading scene %lu nodes %lu internal %lu leaves\n", nodeCount, internalNodeCount, leafNodeCount); // now set up VoxelPersistThread _voxelPersistThread = new VoxelPersistThread(&_serverTree, _voxelPersistFilename); if (_voxelPersistThread) { _voxelPersistThread->initialize(true); } } // Check to see if the user passed in a command line option for loading an old style local // Voxel File. If so, load it now. This is not the same as a voxel persist file const char* INPUT_FILE = "-i"; const char* voxelsFilename = getCmdOption(_argc, _argv, INPUT_FILE); if (voxelsFilename) { _serverTree.readFromSVOFile(voxelsFilename); } // Check to see if the user passed in a command line option for setting packet send rate const char* PACKETS_PER_SECOND = "--packetsPerSecond"; const char* packetsPerSecond = getCmdOption(_argc, _argv, PACKETS_PER_SECOND); if (packetsPerSecond) { _packetsPerClientPerInterval = atoi(packetsPerSecond) / INTERVALS_PER_SECOND; if (_packetsPerClientPerInterval < 1) { _packetsPerClientPerInterval = 1; } qDebug("packetsPerSecond=%s PACKETS_PER_CLIENT_PER_INTERVAL=%d\n", packetsPerSecond, _packetsPerClientPerInterval); } // for now, initialize the environments with fixed values _environmentData[1].setID(1); _environmentData[1].setGravity(1.0f); _environmentData[1].setAtmosphereCenter(glm::vec3(0.5, 0.5, (0.25 - 0.06125)) * (float)TREE_SCALE); _environmentData[1].setAtmosphereInnerRadius(0.030625f * TREE_SCALE); _environmentData[1].setAtmosphereOuterRadius(0.030625f * TREE_SCALE * 1.05f); _environmentData[2].setID(2); _environmentData[2].setGravity(1.0f); _environmentData[2].setAtmosphereCenter(glm::vec3(0.5f, 0.5f, 0.5f) * (float)TREE_SCALE); _environmentData[2].setAtmosphereInnerRadius(0.1875f * TREE_SCALE); _environmentData[2].setAtmosphereOuterRadius(0.1875f * TREE_SCALE * 1.05f); _environmentData[2].setScatteringWavelengths(glm::vec3(0.475f, 0.570f, 0.650f)); // swaps red and blue sockaddr senderAddress; unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE]; ssize_t packetLength; timeval lastDomainServerCheckIn = {}; // set up our jurisdiction broadcaster... _jurisdictionSender = new JurisdictionSender(_jurisdiction); if (_jurisdictionSender) { _jurisdictionSender->initialize(true); } // set up our VoxelServerPacketProcessor _voxelServerPacketProcessor = new VoxelServerPacketProcessor(this); if (_voxelServerPacketProcessor) { _voxelServerPacketProcessor->initialize(true); } // loop to send to nodes requesting data while (true) { if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { break; } // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) { gettimeofday(&lastDomainServerCheckIn, NULL); NodeList::getInstance()->sendDomainServerCheckIn(_uuid.toRfc4122().constData()); } if (nodeList->getNodeSocket()->receive(&senderAddress, packetData, &packetLength) && packetVersionMatch(packetData)) { int numBytesPacketHeader = numBytesForPacketHeader(packetData); if (packetData[0] == PACKET_TYPE_HEAD_DATA) { // If we got a PACKET_TYPE_HEAD_DATA, then we're talking to an NODE_TYPE_AVATAR, and we // need to make sure we have it in our nodeList. uint16_t nodeID = 0; unpackNodeId(packetData + numBytesPacketHeader, &nodeID); Node* node = NodeList::getInstance()->addOrUpdateNode(&senderAddress, &senderAddress, NODE_TYPE_AGENT, nodeID); NodeList::getInstance()->updateNodeWithData(node, packetData, packetLength); VoxelNodeData* nodeData = (VoxelNodeData*) node->getLinkedData(); if (nodeData && !nodeData->isVoxelSendThreadInitalized()) { nodeData->initializeVoxelSendThread(this); } } else if (packetData[0] == PACKET_TYPE_PING) { // If the packet is a ping, let processNodeData handle it. NodeList::getInstance()->processNodeData(&senderAddress, packetData, packetLength); } else if (packetData[0] == PACKET_TYPE_DOMAIN) { NodeList::getInstance()->processNodeData(&senderAddress, packetData, packetLength); } else if (packetData[0] == PACKET_TYPE_VOXEL_JURISDICTION_REQUEST) { if (_jurisdictionSender) { _jurisdictionSender->queueReceivedPacket(senderAddress, packetData, packetLength); } } else if (_voxelServerPacketProcessor) { _voxelServerPacketProcessor->queueReceivedPacket(senderAddress, packetData, packetLength); } else { qDebug("unknown packet ignored... packetData[0]=%c\n", packetData[0]); } } } delete _jurisdiction; if (_jurisdictionSender) { _jurisdictionSender->terminate(); delete _jurisdictionSender; } if (_voxelServerPacketProcessor) { _voxelServerPacketProcessor->terminate(); delete _voxelServerPacketProcessor; } if (_voxelPersistThread) { _voxelPersistThread->terminate(); delete _voxelPersistThread; } // tell our NodeList we're done with notifications nodeList->removeHook(&_nodeWatcher); pthread_mutex_destroy(&_treeLock); }