mirror of
https://github.com/lubosz/overte.git
synced 2025-08-08 02:48:12 +02:00
Merge branch 'master' of https://github.com/worklist/hifi into blendface
This commit is contained in:
commit
1bd8ea947a
48 changed files with 1031 additions and 752 deletions
|
@ -14,7 +14,6 @@ set(CMAKE_AUTOMOC ON)
|
||||||
|
|
||||||
add_subdirectory(animation-server)
|
add_subdirectory(animation-server)
|
||||||
add_subdirectory(assignment-client)
|
add_subdirectory(assignment-client)
|
||||||
add_subdirectory(assignment-server)
|
|
||||||
add_subdirectory(domain-server)
|
add_subdirectory(domain-server)
|
||||||
add_subdirectory(eve)
|
add_subdirectory(eve)
|
||||||
add_subdirectory(interface)
|
add_subdirectory(interface)
|
||||||
|
|
36
README.md
36
README.md
|
@ -94,7 +94,7 @@ I want to run my own virtual world!
|
||||||
|
|
||||||
In order to set up your own virtual world, you need to set up and run your own
|
In order to set up your own virtual world, you need to set up and run your own
|
||||||
local "domain". At a minimum, you must run a domain-server, voxel-server,
|
local "domain". At a minimum, you must run a domain-server, voxel-server,
|
||||||
audio-mixer, and avatar-mixer to have a working virtual world. The audio-mixer and avatar-mixer are assignments given from the domain-server to any assignment-client that reports directly to it.
|
audio-mixer, and avatar-mixer to have a working virtual world. The audio-mixer, avatar-mixer, and voxel-server are assignments given from the domain-server to any assignment-client that reports directly to it.
|
||||||
|
|
||||||
Complete the steps above to build the system components, using the default Cmake Unix Makefiles generator. Start with an empty build directory.
|
Complete the steps above to build the system components, using the default Cmake Unix Makefiles generator. Start with an empty build directory.
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ window, change directory into the build directory, make the needed components, a
|
||||||
First we make the targets we'll need.
|
First we make the targets we'll need.
|
||||||
|
|
||||||
cd build
|
cd build
|
||||||
make domain-server voxel-server assignment-client
|
make domain-server assignment-client
|
||||||
|
|
||||||
If after this step you're seeing something like the following
|
If after this step you're seeing something like the following
|
||||||
|
|
||||||
|
@ -114,35 +114,16 @@ If after this step you're seeing something like the following
|
||||||
|
|
||||||
you likely had Cmake generate Xcode project files and have not run `cmake ..` in a clean build directory.
|
you likely had Cmake generate Xcode project files and have not run `cmake ..` in a clean build directory.
|
||||||
|
|
||||||
Then, launch the static components - a domain-server and a voxel-server. All of the targets will run in the foreground, so you'll either want to background it yourself or open a seperate terminal window per target.
|
Then, launch the static domain-server. All of the targets will run in the foreground, so you'll either want to background it yourself or open a seperate terminal window per target.
|
||||||
|
|
||||||
cd domain-server && ./domain-server
|
cd domain-server && ./domain-server
|
||||||
./voxel-server/voxel-server --local > /tmp/voxel-server.log 2>&1 &
|
|
||||||
|
|
||||||
Then, run an assignment-client with 2 forks to fulfill the avatar-mixer and audio-mixer assignments. It uses localhost as its assignment-server and talks to it on port 40102 (the default domain-server port).
|
Then, run an assignment-client with 3 forks to fulfill the avatar-mixer, audio-mixer, and voxel-server assignments. It uses localhost as its assignment-server and talks to it on port 40102 (the default domain-server port).
|
||||||
|
|
||||||
./assignment-client/assignment-client -n 2 -a localhost -p 40102
|
./assignment-client/assignment-client -n 3
|
||||||
|
|
||||||
Any target can be terminated with CTRL-C (SIGINT) in the associated terminal window.
|
Any target can be terminated with CTRL-C (SIGINT) in the associated terminal window.
|
||||||
|
|
||||||
Determine the IP address of the machine you're running these servers on. Here's
|
|
||||||
a handy resource that explains how to do this for different operating systems.
|
|
||||||
http://kb.iu.edu/data/aapa.html
|
|
||||||
|
|
||||||
On Mac OS X, and many Unix systems you can use the ifconfig command. Typically,
|
|
||||||
the following command will give you the IP address you need to use.
|
|
||||||
|
|
||||||
ifconfig | grep inet | grep broadcast
|
|
||||||
|
|
||||||
You should get something like this:
|
|
||||||
|
|
||||||
inet 192.168.1.104 netmask 0xffffff00 broadcast 192.168.1.255
|
|
||||||
|
|
||||||
Your IP address is the first set of numbers. In this case "192.168.1.104". You
|
|
||||||
may now use this IP address to access your domain. If you are running a local
|
|
||||||
DNS or other name service you should be able to access this IP address by name
|
|
||||||
as well.
|
|
||||||
|
|
||||||
To test things out you'll want to run the Interface client. You can make that target with the following command:
|
To test things out you'll want to run the Interface client. You can make that target with the following command:
|
||||||
|
|
||||||
make interface
|
make interface
|
||||||
|
@ -150,9 +131,8 @@ To test things out you'll want to run the Interface client. You can make that ta
|
||||||
Then run the executable it builds, or open interface.app if you're on OS X.
|
Then run the executable it builds, or open interface.app if you're on OS X.
|
||||||
|
|
||||||
To access your local domain in Interface, open the Preferences dialog box, from
|
To access your local domain in Interface, open the Preferences dialog box, from
|
||||||
the Interface menu on OS X or the File menu on Linux, and enter the IP address of the local DNS name for the
|
the Interface menu on OS X or the File menu on Linux, and enter "localhost" for the
|
||||||
server computer in the "Domain" edit control.
|
server hostname in the "Domain" edit control.
|
||||||
|
|
||||||
In the voxel-server/src directory you will find a README that explains in
|
In the voxel-server/src directory you will find a README that explains in
|
||||||
further detail how to setup and administer a voxel-server.
|
further detail how to setup and administer a voxel-server.
|
||||||
|
|
|
@ -685,9 +685,9 @@ int main(int argc, const char * argv[])
|
||||||
nodeList->setDomainIPToLocalhost();
|
nodeList->setDomainIPToLocalhost();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* domainIP = getCmdOption(argc, argv, "--domain");
|
const char* domainHostname = getCmdOption(argc, argv, "--domain");
|
||||||
if (domainIP) {
|
if (domainHostname) {
|
||||||
NodeList::getInstance()->setDomainIP(domainIP);
|
NodeList::getInstance()->setDomainHostname(domainHostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeList->linkedDataCreateCallback = NULL; // do we need a callback?
|
nodeList->linkedDataCreateCallback = NULL; // do we need a callback?
|
||||||
|
|
|
@ -24,4 +24,12 @@ include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||||
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
|
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
|
||||||
link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR})
|
link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR})
|
||||||
link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR})
|
link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR})
|
||||||
link_hifi_library(voxel-server-library ${TARGET_NAME} ${ROOT_DIR})
|
link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR})
|
||||||
|
link_hifi_library(voxel-server-library ${TARGET_NAME} ${ROOT_DIR})
|
||||||
|
|
||||||
|
# link the stk library
|
||||||
|
set(STK_ROOT_DIR ${ROOT_DIR}/externals/stk)
|
||||||
|
find_package(STK REQUIRED)
|
||||||
|
target_link_libraries(${TARGET_NAME} ${STK_LIBRARIES})
|
||||||
|
include_directories(${STK_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
|
|
@ -9,24 +9,28 @@
|
||||||
#include <QtScript/QScriptEngine>
|
#include <QtScript/QScriptEngine>
|
||||||
#include <QtNetwork/QtNetwork>
|
#include <QtNetwork/QtNetwork>
|
||||||
|
|
||||||
|
#include <AvatarData.h>
|
||||||
#include <NodeList.h>
|
#include <NodeList.h>
|
||||||
|
|
||||||
#include "AvatarData.h"
|
|
||||||
|
|
||||||
#include "Agent.h"
|
#include "Agent.h"
|
||||||
|
#include "voxels/VoxelScriptingInterface.h"
|
||||||
|
|
||||||
Agent::Agent() :
|
Agent::Agent(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes) {
|
||||||
_shouldStop(false)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Agent::run(QUrl scriptURL) {
|
void Agent::run() {
|
||||||
NodeList::getInstance()->setOwnerType(NODE_TYPE_AGENT);
|
NodeList::getInstance()->setOwnerType(NODE_TYPE_AGENT);
|
||||||
NodeList::getInstance()->setNodeTypesOfInterest(&NODE_TYPE_AVATAR_MIXER, 1);
|
NodeList::getInstance()->setNodeTypesOfInterest(&NODE_TYPE_VOXEL_SERVER, 1);
|
||||||
|
|
||||||
QNetworkAccessManager manager;
|
QNetworkAccessManager manager;
|
||||||
|
|
||||||
|
// 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(),
|
||||||
|
this->getUUIDStringWithoutCurlyBraces());
|
||||||
|
QUrl scriptURL(scriptURLString);
|
||||||
|
|
||||||
qDebug() << "Attemping download of " << scriptURL << "\n";
|
qDebug() << "Attemping download of " << scriptURL << "\n";
|
||||||
|
|
||||||
QNetworkReply* reply = manager.get(QNetworkRequest(scriptURL));
|
QNetworkReply* reply = manager.get(QNetworkRequest(scriptURL));
|
||||||
|
@ -39,14 +43,13 @@ void Agent::run(QUrl scriptURL) {
|
||||||
|
|
||||||
QScriptEngine engine;
|
QScriptEngine engine;
|
||||||
|
|
||||||
AvatarData *testAvatarData = new AvatarData;
|
|
||||||
|
|
||||||
QScriptValue avatarDataValue = engine.newQObject(testAvatarData);
|
|
||||||
engine.globalObject().setProperty("Avatar", avatarDataValue);
|
|
||||||
|
|
||||||
QScriptValue agentValue = engine.newQObject(this);
|
QScriptValue agentValue = engine.newQObject(this);
|
||||||
engine.globalObject().setProperty("Agent", agentValue);
|
engine.globalObject().setProperty("Agent", agentValue);
|
||||||
|
|
||||||
|
VoxelScriptingInterface voxelScripter;
|
||||||
|
QScriptValue voxelScripterValue = engine.newQObject(&voxelScripter);
|
||||||
|
engine.globalObject().setProperty("Voxels", voxelScripterValue);
|
||||||
|
|
||||||
qDebug() << "Downloaded script:" << scriptString << "\n";
|
qDebug() << "Downloaded script:" << scriptString << "\n";
|
||||||
qDebug() << "Evaluated script:" << engine.evaluate(scriptString).toString() << "\n";
|
qDebug() << "Evaluated script:" << engine.evaluate(scriptString).toString() << "\n";
|
||||||
|
|
||||||
|
@ -75,9 +78,10 @@ void Agent::run(QUrl scriptURL) {
|
||||||
NodeList::getInstance()->sendDomainServerCheckIn();
|
NodeList::getInstance()->sendDomainServerCheckIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// allow the scripter's call back to setup visual data
|
||||||
emit preSendCallback();
|
emit preSendCallback();
|
||||||
|
// flush the voxel packet queue
|
||||||
testAvatarData->sendData();
|
voxelScripter.getVoxelPacketSender()->process();
|
||||||
|
|
||||||
if (NodeList::getInstance()->getNodeSocket()->receive((sockaddr*) &senderAddress, receivedData, &receivedBytes)) {
|
if (NodeList::getInstance()->getNodeSocket()->receive((sockaddr*) &senderAddress, receivedData, &receivedBytes)) {
|
||||||
NodeList::getInstance()->processNodeData((sockaddr*) &senderAddress, receivedData, receivedBytes);
|
NodeList::getInstance()->processNodeData((sockaddr*) &senderAddress, receivedData, receivedBytes);
|
||||||
|
|
|
@ -9,19 +9,19 @@
|
||||||
#ifndef __hifi__Agent__
|
#ifndef __hifi__Agent__
|
||||||
#define __hifi__Agent__
|
#define __hifi__Agent__
|
||||||
|
|
||||||
#include "SharedUtil.h"
|
|
||||||
|
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
#include <QtCore/QUrl>
|
#include <QtCore/QUrl>
|
||||||
|
|
||||||
class Agent : public QObject {
|
#include <Assignment.h>
|
||||||
|
|
||||||
|
class Agent : public Assignment {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
Agent();
|
Agent(const unsigned char* dataBuffer, int numBytes);
|
||||||
|
|
||||||
bool volatile _shouldStop;
|
bool volatile _shouldStop;
|
||||||
|
|
||||||
void run(QUrl scriptUrl);
|
void run();
|
||||||
signals:
|
signals:
|
||||||
void preSendCallback();
|
void preSendCallback();
|
||||||
};
|
};
|
||||||
|
|
36
assignment-client/src/AssignmentFactory.cpp
Normal file
36
assignment-client/src/AssignmentFactory.cpp
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
//
|
||||||
|
// AssignmentFactory.cpp
|
||||||
|
// hifi
|
||||||
|
//
|
||||||
|
// Created by Stephen Birarda on 9/17/13.
|
||||||
|
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <PacketHeaders.h>
|
||||||
|
|
||||||
|
#include "Agent.h"
|
||||||
|
#include "audio/AudioMixer.h"
|
||||||
|
#include "avatars/AvatarMixer.h"
|
||||||
|
#include <VoxelServer.h>
|
||||||
|
|
||||||
|
#include "AssignmentFactory.h"
|
||||||
|
|
||||||
|
Assignment* AssignmentFactory::unpackAssignment(const unsigned char* dataBuffer, int numBytes) {
|
||||||
|
int headerBytes = numBytesForPacketHeader(dataBuffer);
|
||||||
|
|
||||||
|
Assignment::Type assignmentType = Assignment::AllTypes;
|
||||||
|
memcpy(&assignmentType, dataBuffer + headerBytes, sizeof(Assignment::Type));
|
||||||
|
|
||||||
|
switch (assignmentType) {
|
||||||
|
case Assignment::AudioMixerType:
|
||||||
|
return new AudioMixer(dataBuffer, numBytes);
|
||||||
|
case Assignment::AvatarMixerType:
|
||||||
|
return new AvatarMixer(dataBuffer, numBytes);
|
||||||
|
case Assignment::AgentType:
|
||||||
|
return new Agent(dataBuffer, numBytes);
|
||||||
|
case Assignment::VoxelServerType:
|
||||||
|
return new VoxelServer(dataBuffer, numBytes);
|
||||||
|
default:
|
||||||
|
return new Assignment(dataBuffer, numBytes);
|
||||||
|
}
|
||||||
|
}
|
19
assignment-client/src/AssignmentFactory.h
Normal file
19
assignment-client/src/AssignmentFactory.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
//
|
||||||
|
// AssignmentFactory.h
|
||||||
|
// hifi
|
||||||
|
//
|
||||||
|
// Created by Stephen Birarda on 9/17/13.
|
||||||
|
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __hifi__AssignmentFactory__
|
||||||
|
#define __hifi__AssignmentFactory__
|
||||||
|
|
||||||
|
#include "Assignment.h"
|
||||||
|
|
||||||
|
class AssignmentFactory {
|
||||||
|
public:
|
||||||
|
static Assignment* unpackAssignment(const unsigned char* dataBuffer, int numBytes);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* defined(__hifi__AssignmentFactory__) */
|
|
@ -69,6 +69,10 @@ void attachNewBufferToNode(Node *newNode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudioMixer::AudioMixer(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void AudioMixer::run() {
|
void AudioMixer::run() {
|
||||||
// change the logging target name while this is running
|
// change the logging target name while this is running
|
||||||
Logging::setTargetName(AUDIO_MIXER_LOGGING_TARGET_NAME);
|
Logging::setTargetName(AUDIO_MIXER_LOGGING_TARGET_NAME);
|
||||||
|
@ -125,7 +129,7 @@ void AudioMixer::run() {
|
||||||
// send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed
|
// 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) {
|
if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) {
|
||||||
gettimeofday(&lastDomainServerCheckIn, NULL);
|
gettimeofday(&lastDomainServerCheckIn, NULL);
|
||||||
NodeList::getInstance()->sendDomainServerCheckIn();
|
NodeList::getInstance()->sendDomainServerCheckIn(this->getUUID().toRfc4122().constData());
|
||||||
|
|
||||||
if (Logging::shouldSendStats() && numStatCollections > 0) {
|
if (Logging::shouldSendStats() && numStatCollections > 0) {
|
||||||
// if we should be sending stats to Logstash send the appropriate average now
|
// if we should be sending stats to Logstash send the appropriate average now
|
||||||
|
@ -421,7 +425,7 @@ void AudioMixer::run() {
|
||||||
if (usecToSleep > 0) {
|
if (usecToSleep > 0) {
|
||||||
usleep(usecToSleep);
|
usleep(usecToSleep);
|
||||||
} else {
|
} else {
|
||||||
std::cout << "Took too much time, not sleeping!\n";
|
qDebug("Took too much time, not sleeping!\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,11 +9,15 @@
|
||||||
#ifndef __hifi__AudioMixer__
|
#ifndef __hifi__AudioMixer__
|
||||||
#define __hifi__AudioMixer__
|
#define __hifi__AudioMixer__
|
||||||
|
|
||||||
|
#include <Assignment.h>
|
||||||
|
|
||||||
/// Handles assignments of type AudioMixer - mixing streams of audio and re-distributing to various clients.
|
/// Handles assignments of type AudioMixer - mixing streams of audio and re-distributing to various clients.
|
||||||
class AudioMixer {
|
class AudioMixer : public Assignment {
|
||||||
public:
|
public:
|
||||||
|
AudioMixer(const unsigned char* dataBuffer, int numBytes);
|
||||||
|
|
||||||
/// runs the audio mixer
|
/// runs the audio mixer
|
||||||
static void run();
|
void run();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__hifi__AudioMixer__) */
|
#endif /* defined(__hifi__AudioMixer__) */
|
|
@ -83,6 +83,10 @@ void broadcastAvatarData(NodeList* nodeList, sockaddr* nodeAddress) {
|
||||||
nodeList->getNodeSocket()->send(nodeAddress, broadcastPacket, currentBufferPosition - broadcastPacket);
|
nodeList->getNodeSocket()->send(nodeAddress, broadcastPacket, currentBufferPosition - broadcastPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AvatarMixer::AvatarMixer(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void AvatarMixer::run() {
|
void AvatarMixer::run() {
|
||||||
// change the logging target name while AvatarMixer is running
|
// change the logging target name while AvatarMixer is running
|
||||||
Logging::setTargetName(AVATAR_MIXER_LOGGING_NAME);
|
Logging::setTargetName(AVATAR_MIXER_LOGGING_NAME);
|
||||||
|
@ -115,7 +119,7 @@ void AvatarMixer::run() {
|
||||||
// send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed
|
// 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) {
|
if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) {
|
||||||
gettimeofday(&lastDomainServerCheckIn, NULL);
|
gettimeofday(&lastDomainServerCheckIn, NULL);
|
||||||
NodeList::getInstance()->sendDomainServerCheckIn();
|
NodeList::getInstance()->sendDomainServerCheckIn(this->getUUID().toRfc4122().constData());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nodeList->getNodeSocket()->receive(nodeAddress, packetData, &receivedBytes) &&
|
if (nodeList->getNodeSocket()->receive(nodeAddress, packetData, &receivedBytes) &&
|
|
@ -9,13 +9,15 @@
|
||||||
#ifndef __hifi__AvatarMixer__
|
#ifndef __hifi__AvatarMixer__
|
||||||
#define __hifi__AvatarMixer__
|
#define __hifi__AvatarMixer__
|
||||||
|
|
||||||
#include <iostream>
|
#include <Assignment.h>
|
||||||
|
|
||||||
/// Handles assignments of type AvatarMixer - distribution of avatar data to various clients
|
/// Handles assignments of type AvatarMixer - distribution of avatar data to various clients
|
||||||
class AvatarMixer {
|
class AvatarMixer : public Assignment {
|
||||||
public:
|
public:
|
||||||
|
AvatarMixer(const unsigned char* dataBuffer, int numBytes);
|
||||||
|
|
||||||
/// runs the avatar mixer
|
/// runs the avatar mixer
|
||||||
static void run();
|
void run();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__hifi__AvatarMixer__) */
|
#endif /* defined(__hifi__AvatarMixer__) */
|
|
@ -14,16 +14,19 @@
|
||||||
|
|
||||||
#include <QtCore/QCoreApplication>
|
#include <QtCore/QCoreApplication>
|
||||||
|
|
||||||
#include "Agent.h"
|
|
||||||
#include <Assignment.h>
|
|
||||||
#include <AudioMixer.h>
|
|
||||||
#include <AvatarMixer.h>
|
|
||||||
#include <Logging.h>
|
#include <Logging.h>
|
||||||
#include <NodeList.h>
|
#include <NodeList.h>
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
#include <VoxelServer.h>
|
#include <VoxelServer.h>
|
||||||
|
|
||||||
|
#include "Agent.h"
|
||||||
|
#include "Assignment.h"
|
||||||
|
#include "AssignmentFactory.h"
|
||||||
|
#include "audio/AudioMixer.h"
|
||||||
|
#include "avatars/AvatarMixer.h"
|
||||||
|
|
||||||
const long long ASSIGNMENT_REQUEST_INTERVAL_USECS = 1 * 1000 * 1000;
|
const long long ASSIGNMENT_REQUEST_INTERVAL_USECS = 1 * 1000 * 1000;
|
||||||
const char PARENT_TARGET_NAME[] = "assignment-client-monitor";
|
const char PARENT_TARGET_NAME[] = "assignment-client-monitor";
|
||||||
const char CHILD_TARGET_NAME[] = "assignment-client";
|
const char CHILD_TARGET_NAME[] = "assignment-client";
|
||||||
|
@ -31,6 +34,7 @@ const char CHILD_TARGET_NAME[] = "assignment-client";
|
||||||
pid_t* childForks = NULL;
|
pid_t* childForks = NULL;
|
||||||
sockaddr_in customAssignmentSocket = {};
|
sockaddr_in customAssignmentSocket = {};
|
||||||
int numForks = 0;
|
int numForks = 0;
|
||||||
|
Assignment::Type overiddenAssignmentType = Assignment::AllTypes;
|
||||||
|
|
||||||
void childClient() {
|
void childClient() {
|
||||||
// this is one of the child forks or there is a single assignment client, continue assignment-client execution
|
// this is one of the child forks or there is a single assignment client, continue assignment-client execution
|
||||||
|
@ -56,8 +60,8 @@ void childClient() {
|
||||||
|
|
||||||
sockaddr_in senderSocket = {};
|
sockaddr_in senderSocket = {};
|
||||||
|
|
||||||
// create a request assignment, accept all assignments, pass the desired pool (if it exists)
|
// create a request assignment, accept assignments defined by the overidden type
|
||||||
Assignment requestAssignment(Assignment::RequestCommand, Assignment::AllTypes);
|
Assignment requestAssignment(Assignment::RequestCommand, ::overiddenAssignmentType);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (usecTimestampNow() - usecTimestamp(&lastRequest) >= ASSIGNMENT_REQUEST_INTERVAL_USECS) {
|
if (usecTimestampNow() - usecTimestamp(&lastRequest) >= ASSIGNMENT_REQUEST_INTERVAL_USECS) {
|
||||||
|
@ -72,51 +76,40 @@ void childClient() {
|
||||||
&& packetVersionMatch(packetData)) {
|
&& packetVersionMatch(packetData)) {
|
||||||
|
|
||||||
// construct the deployed assignment from the packet data
|
// construct the deployed assignment from the packet data
|
||||||
Assignment deployedAssignment(packetData, receivedBytes);
|
Assignment* deployedAssignment = AssignmentFactory::unpackAssignment(packetData, receivedBytes);
|
||||||
|
|
||||||
qDebug() << "Received an assignment -" << deployedAssignment << "\n";
|
qDebug() << "Received an assignment -" << *deployedAssignment << "\n";
|
||||||
|
|
||||||
// switch our nodelist DOMAIN_IP
|
// switch our nodelist DOMAIN_IP
|
||||||
if (packetData[0] == PACKET_TYPE_CREATE_ASSIGNMENT ||
|
if (packetData[0] == PACKET_TYPE_CREATE_ASSIGNMENT ||
|
||||||
deployedAssignment.getAttachedPublicSocket()->sa_family == AF_INET) {
|
deployedAssignment->getAttachedPublicSocket()->sa_family == AF_INET) {
|
||||||
|
|
||||||
in_addr domainSocketAddr = {};
|
|
||||||
|
sockaddr* domainSocket = NULL;
|
||||||
|
|
||||||
if (packetData[0] == PACKET_TYPE_CREATE_ASSIGNMENT) {
|
if (packetData[0] == PACKET_TYPE_CREATE_ASSIGNMENT) {
|
||||||
// the domain server IP address is the address we got this packet from
|
// the domain server IP address is the address we got this packet from
|
||||||
domainSocketAddr = senderSocket.sin_addr;
|
domainSocket = (sockaddr*) &senderSocket;
|
||||||
} else {
|
} else {
|
||||||
// grab the domain server IP address from the packet from the AS
|
// grab the domain server IP address from the packet from the AS
|
||||||
domainSocketAddr = ((sockaddr_in*) deployedAssignment.getAttachedPublicSocket())->sin_addr;
|
domainSocket = (sockaddr*) deployedAssignment->getAttachedPublicSocket();
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeList->setDomainIP(inet_ntoa(domainSocketAddr));
|
nodeList->setDomainIP(QHostAddress(domainSocket));
|
||||||
|
|
||||||
qDebug("Destination IP for assignment is %s\n", inet_ntoa(domainSocketAddr));
|
qDebug("Destination IP for assignment is %s\n", nodeList->getDomainIP().toString().toStdString().c_str());
|
||||||
|
|
||||||
if (deployedAssignment.getType() == Assignment::AudioMixerType) {
|
// run the deployed assignment
|
||||||
AudioMixer::run();
|
deployedAssignment->run();
|
||||||
} else if (deployedAssignment.getType() == Assignment::AvatarMixerType) {
|
|
||||||
AvatarMixer::run();
|
|
||||||
} else if (deployedAssignment.getType() == Assignment::VoxelServerType) {
|
|
||||||
VoxelServer::run();
|
|
||||||
} else {
|
|
||||||
// figure out the URL for the script for this agent assignment
|
|
||||||
QString scriptURLString("http://%1:8080/assignment/%2");
|
|
||||||
scriptURLString = scriptURLString.arg(inet_ntoa(domainSocketAddr),
|
|
||||||
deployedAssignment.getUUIDStringWithoutCurlyBraces());
|
|
||||||
|
|
||||||
qDebug() << "Starting an Agent assignment-client with script at" << scriptURLString << "\n";
|
|
||||||
|
|
||||||
Agent scriptAgent;
|
|
||||||
scriptAgent.run(QUrl(scriptURLString));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
qDebug("Received a bad destination socket for assignment.\n");
|
qDebug("Received a bad destination socket for assignment.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug("Assignment finished or never started - waiting for new 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
|
// reset our NodeList by switching back to unassigned and clearing the list
|
||||||
nodeList->setOwnerType(NODE_TYPE_UNASSIGNED);
|
nodeList->setOwnerType(NODE_TYPE_UNASSIGNED);
|
||||||
nodeList->clear();
|
nodeList->clear();
|
||||||
|
@ -161,6 +154,7 @@ void sigchldHandler(int sig) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void parentMonitor() {
|
void parentMonitor() {
|
||||||
|
@ -206,11 +200,20 @@ int main(int argc, const char* argv[]) {
|
||||||
if (customAssignmentServerHostname) {
|
if (customAssignmentServerHostname) {
|
||||||
const char* customAssignmentServerPortString = getCmdOption(argc, argv, CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION);
|
const char* customAssignmentServerPortString = getCmdOption(argc, argv, CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION);
|
||||||
unsigned short assignmentServerPort = customAssignmentServerPortString
|
unsigned short assignmentServerPort = customAssignmentServerPortString
|
||||||
? atoi(customAssignmentServerPortString) : ASSIGNMENT_SERVER_PORT;
|
? atoi(customAssignmentServerPortString) : DEFAULT_DOMAIN_SERVER_PORT;
|
||||||
|
|
||||||
::customAssignmentSocket = socketForHostnameAndHostOrderPort(customAssignmentServerHostname, assignmentServerPort);
|
::customAssignmentSocket = socketForHostnameAndHostOrderPort(customAssignmentServerHostname, assignmentServerPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char ASSIGNMENT_TYPE_OVVERIDE_OPTION[] = "-t";
|
||||||
|
const char* assignmentTypeString = getCmdOption(argc, argv, ASSIGNMENT_TYPE_OVVERIDE_OPTION);
|
||||||
|
|
||||||
|
if (assignmentTypeString) {
|
||||||
|
// the user is asking to only be assigned to a particular type of assignment
|
||||||
|
// so set that as the ::overridenAssignmentType to be used in requests
|
||||||
|
::overiddenAssignmentType = (Assignment::Type) atoi(assignmentTypeString);
|
||||||
|
}
|
||||||
|
|
||||||
const char* NUM_FORKS_PARAMETER = "-n";
|
const char* NUM_FORKS_PARAMETER = "-n";
|
||||||
const char* numForksString = getCmdOption(argc, argv, NUM_FORKS_PARAMETER);
|
const char* numForksString = getCmdOption(argc, argv, NUM_FORKS_PARAMETER);
|
||||||
|
|
||||||
|
|
15
assignment-client/src/voxels/VoxelScriptingInterface.cpp
Normal file
15
assignment-client/src/voxels/VoxelScriptingInterface.cpp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
//
|
||||||
|
// VoxelScriptingInterface.cpp
|
||||||
|
// hifi
|
||||||
|
//
|
||||||
|
// Created by Stephen Birarda on 9/17/13.
|
||||||
|
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "VoxelScriptingInterface.h"
|
||||||
|
|
||||||
|
void VoxelScriptingInterface::queueVoxelAdd(float x, float y, float z, float scale, uchar red, uchar green, uchar blue) {
|
||||||
|
// setup a VoxelDetail struct with the data
|
||||||
|
VoxelDetail addVoxelDetail = {x, y, z, scale, red, green, blue};
|
||||||
|
_voxelPacketSender.sendVoxelEditMessage(PACKET_TYPE_SET_VOXEL, addVoxelDetail);
|
||||||
|
}
|
36
assignment-client/src/voxels/VoxelScriptingInterface.h
Normal file
36
assignment-client/src/voxels/VoxelScriptingInterface.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
//
|
||||||
|
// VoxelScriptingInterface.h
|
||||||
|
// hifi
|
||||||
|
//
|
||||||
|
// Created by Stephen Birarda on 9/17/13.
|
||||||
|
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __hifi__VoxelScriptingInterface__
|
||||||
|
#define __hifi__VoxelScriptingInterface__
|
||||||
|
|
||||||
|
#include <QtCore/QObject>
|
||||||
|
|
||||||
|
#include <VoxelEditPacketSender.h>
|
||||||
|
|
||||||
|
/// handles scripting of voxel commands from JS passed to assigned clients
|
||||||
|
class VoxelScriptingInterface : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
VoxelEditPacketSender* getVoxelPacketSender() { return &_voxelPacketSender; }
|
||||||
|
public slots:
|
||||||
|
/// queues the creation of a voxel which will be sent by calling process on the PacketSender
|
||||||
|
/// \param x the x-coordinate of the voxel (in VS space)
|
||||||
|
/// \param y the y-coordinate of the voxel (in VS space)
|
||||||
|
/// \param z the z-coordinate of the voxel (in VS space)
|
||||||
|
/// \param scale the scale of the voxel (in VS space)
|
||||||
|
/// \param red the R value for RGB color of voxel
|
||||||
|
/// \param green the G value for RGB color of voxel
|
||||||
|
/// \param blue the B value for RGB color of voxel
|
||||||
|
void queueVoxelAdd(float x, float y, float z, float scale, uchar red, uchar green, uchar blue);
|
||||||
|
private:
|
||||||
|
/// attached VoxelEditPacketSender that handles queuing and sending of packets to VS
|
||||||
|
VoxelEditPacketSender _voxelPacketSender;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* defined(__hifi__VoxelScriptingInterface__) */
|
|
@ -1,13 +0,0 @@
|
||||||
cmake_minimum_required(VERSION 2.8)
|
|
||||||
|
|
||||||
set(TARGET_NAME assignment-server)
|
|
||||||
|
|
||||||
set(ROOT_DIR ..)
|
|
||||||
set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
|
|
||||||
|
|
||||||
include(${MACRO_DIR}/SetupHifiProject.cmake)
|
|
||||||
setup_hifi_project(${TARGET_NAME} TRUE)
|
|
||||||
|
|
||||||
# link in the shared library
|
|
||||||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
|
||||||
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
|
|
|
@ -1,108 +0,0 @@
|
||||||
//
|
|
||||||
// main.cpp
|
|
||||||
// assignment-server
|
|
||||||
//
|
|
||||||
// Created by Stephen Birarda on 7/1/13.
|
|
||||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <fstream>
|
|
||||||
#include <deque>
|
|
||||||
|
|
||||||
#include <QtCore/QString>
|
|
||||||
|
|
||||||
#include <Assignment.h>
|
|
||||||
#include <Logging.h>
|
|
||||||
#include <PacketHeaders.h>
|
|
||||||
#include <SharedUtil.h>
|
|
||||||
#include <UDPSocket.h>
|
|
||||||
|
|
||||||
const int MAX_PACKET_SIZE_BYTES = 1400;
|
|
||||||
const long long NUM_DEFAULT_ASSIGNMENT_STALENESS_USECS = 10 * 1000 * 1000;
|
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
|
||||||
|
|
||||||
qInstallMessageHandler(Logging::verboseMessageHandler);
|
|
||||||
|
|
||||||
std::deque<Assignment*> assignmentQueue;
|
|
||||||
|
|
||||||
sockaddr_in senderSocket;
|
|
||||||
unsigned char senderData[MAX_PACKET_SIZE_BYTES] = {};
|
|
||||||
ssize_t receivedBytes = 0;
|
|
||||||
|
|
||||||
UDPSocket serverSocket(ASSIGNMENT_SERVER_PORT);
|
|
||||||
|
|
||||||
unsigned char assignmentPacket[MAX_PACKET_SIZE_BYTES];
|
|
||||||
int numSendHeaderBytes = populateTypeAndVersion(assignmentPacket, PACKET_TYPE_DEPLOY_ASSIGNMENT);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (serverSocket.receive((sockaddr*) &senderSocket, &senderData, &receivedBytes)) {
|
|
||||||
if (senderData[0] == PACKET_TYPE_REQUEST_ASSIGNMENT) {
|
|
||||||
// construct the requested assignment from the packet data
|
|
||||||
Assignment requestAssignment(senderData, receivedBytes);
|
|
||||||
|
|
||||||
qDebug() << "Received request for assignment:" << requestAssignment << "\n";
|
|
||||||
qDebug() << "Current queue size is" << assignmentQueue.size() << "\n";
|
|
||||||
|
|
||||||
// make sure there are assignments in the queue at all
|
|
||||||
if (assignmentQueue.size() > 0) {
|
|
||||||
|
|
||||||
std::deque<Assignment*>::iterator assignment = assignmentQueue.begin();
|
|
||||||
|
|
||||||
// enumerate assignments until we find one to give this client (if possible)
|
|
||||||
while (assignment != assignmentQueue.end()) {
|
|
||||||
|
|
||||||
// if this assignment is stale then get rid of it and check the next one
|
|
||||||
if (usecTimestampNow() - usecTimestamp(&((*assignment)->getTime()))
|
|
||||||
>= NUM_DEFAULT_ASSIGNMENT_STALENESS_USECS) {
|
|
||||||
delete *assignment;
|
|
||||||
assignment = assignmentQueue.erase(assignment);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if the requestor is on the same network as the destination for the assignment
|
|
||||||
if (senderSocket.sin_addr.s_addr ==
|
|
||||||
((sockaddr_in*) (*assignment)->getAttachedPublicSocket())->sin_addr.s_addr) {
|
|
||||||
// if this is the case we remove the public socket on the assignment by setting it to NULL
|
|
||||||
// this ensures the local IP and port sent to the requestor is the local address of destination
|
|
||||||
(*assignment)->setAttachedPublicSocket(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int numAssignmentBytes = (*assignment)->packToBuffer(assignmentPacket + numSendHeaderBytes);
|
|
||||||
|
|
||||||
// send the assignment
|
|
||||||
serverSocket.send((sockaddr*) &senderSocket,
|
|
||||||
assignmentPacket,
|
|
||||||
numSendHeaderBytes + numAssignmentBytes);
|
|
||||||
|
|
||||||
|
|
||||||
// delete this assignment now that it has been sent out
|
|
||||||
delete *assignment;
|
|
||||||
// remove it from the deque and make the iterator the next assignment
|
|
||||||
assignmentQueue.erase(assignment);
|
|
||||||
|
|
||||||
// stop looping - we've handed out an assignment
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (senderData[0] == PACKET_TYPE_CREATE_ASSIGNMENT && packetVersionMatch(senderData)) {
|
|
||||||
// construct the create assignment from the packet data
|
|
||||||
Assignment* createdAssignment = new Assignment(senderData, receivedBytes);
|
|
||||||
|
|
||||||
qDebug() << "Received a created assignment:" << *createdAssignment << "\n";
|
|
||||||
qDebug() << "Current queue size is" << assignmentQueue.size() << "\n";
|
|
||||||
|
|
||||||
// assignment server is likely on a public server
|
|
||||||
// assume that the address we now have for the sender is the public address/port
|
|
||||||
// and store that with the assignment so it can be given to the requestor later if necessary
|
|
||||||
createdAssignment->setAttachedPublicSocket((sockaddr*) &senderSocket);
|
|
||||||
|
|
||||||
// add this assignment to the queue
|
|
||||||
assignmentQueue.push_back(createdAssignment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,7 +2,15 @@ MACRO(SETUP_HIFI_PROJECT TARGET INCLUDE_QT)
|
||||||
project(${TARGET})
|
project(${TARGET})
|
||||||
|
|
||||||
# grab the implemenation and header files
|
# grab the implemenation and header files
|
||||||
file(GLOB TARGET_SRCS src/*.cpp src/*.h src/*.c)
|
file(GLOB TARGET_SRCS src/*)
|
||||||
|
|
||||||
|
file(GLOB SRC_SUBDIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/src/*)
|
||||||
|
foreach(DIR ${SRC_SUBDIRS})
|
||||||
|
if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/${DIR})
|
||||||
|
FILE(GLOB DIR_CONTENTS src/${DIR}/*)
|
||||||
|
SET(TARGET_SRCS ${TARGET_SRCS} ${DIR_CONTENTS})
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
# add the executable
|
# add the executable
|
||||||
add_executable(${TARGET} ${TARGET_SRCS})
|
add_executable(${TARGET} ${TARGET_SRCS})
|
||||||
|
|
|
@ -36,11 +36,22 @@ body {
|
||||||
}
|
}
|
||||||
#deploy-button {
|
#deploy-button {
|
||||||
background-color: #0DFFBB;
|
background-color: #0DFFBB;
|
||||||
right: 0px;
|
right: 85px;
|
||||||
}
|
}
|
||||||
#deploy-button:hover {
|
#deploy-button:hover {
|
||||||
background-color: #28FF57;
|
background-color: #28FF57;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#instance-field {
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
top: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#instance-field input {
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
#stop-button {
|
#stop-button {
|
||||||
background-color: #CC1F00;
|
background-color: #CC1F00;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
|
|
|
@ -14,6 +14,9 @@
|
||||||
Run
|
Run
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div class='big-field' id='instance-field'>
|
||||||
|
<input type='text' name='instances' placeholder='# of instances'>
|
||||||
|
</div>
|
||||||
<!-- %div#stop-button.big-button -->
|
<!-- %div#stop-button.big-button -->
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -20,6 +20,11 @@ $(document).ready(function(){
|
||||||
// add the script
|
// add the script
|
||||||
+ script + '\r\n'
|
+ script + '\r\n'
|
||||||
+ '--' + boundary + '--';
|
+ '--' + boundary + '--';
|
||||||
|
|
||||||
|
var headers = {};
|
||||||
|
if ($('#instance-field input').val()) {
|
||||||
|
headers['ASSIGNMENT-INSTANCES'] = $('#instance-field input').val();
|
||||||
|
}
|
||||||
|
|
||||||
// post form to assignment in order to create an assignment
|
// post form to assignment in order to create an assignment
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
@ -27,6 +32,7 @@ $(document).ready(function(){
|
||||||
data: body,
|
data: body,
|
||||||
type: "POST",
|
type: "POST",
|
||||||
url: "/assignment",
|
url: "/assignment",
|
||||||
|
headers: headers,
|
||||||
success: function (data, status) {
|
success: function (data, status) {
|
||||||
console.log(data);
|
console.log(data);
|
||||||
console.log(status);
|
console.log(status);
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include <QtCore/QCoreApplication>
|
#include <QtCore/QCoreApplication>
|
||||||
|
#include <QtCore/QMap>
|
||||||
#include <QtCore/QMutex>
|
#include <QtCore/QMutex>
|
||||||
|
|
||||||
#include <civetweb.h>
|
#include <civetweb.h>
|
||||||
|
@ -58,7 +59,7 @@ unsigned char* addNodeToBroadcastPacket(unsigned char* currentPosition, Node* no
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mongooseRequestHandler(struct mg_connection *conn) {
|
static int mongooseRequestHandler(struct mg_connection *conn) {
|
||||||
const struct mg_request_info *ri = mg_get_request_info(conn);
|
const struct mg_request_info* ri = mg_get_request_info(conn);
|
||||||
|
|
||||||
if (strcmp(ri->uri, "/assignment") == 0 && strcmp(ri->request_method, "POST") == 0) {
|
if (strcmp(ri->uri, "/assignment") == 0 && strcmp(ri->request_method, "POST") == 0) {
|
||||||
// return a 200
|
// return a 200
|
||||||
|
@ -76,9 +77,20 @@ static int mongooseRequestHandler(struct mg_connection *conn) {
|
||||||
const char ASSIGNMENT_SCRIPT_HOST_LOCATION[] = "resources/web/assignment";
|
const char ASSIGNMENT_SCRIPT_HOST_LOCATION[] = "resources/web/assignment";
|
||||||
|
|
||||||
static void mongooseUploadHandler(struct mg_connection *conn, const char *path) {
|
static void mongooseUploadHandler(struct mg_connection *conn, const char *path) {
|
||||||
|
|
||||||
// create an assignment for this saved script, for now make it local only
|
// create an assignment for this saved script, for now make it local only
|
||||||
Assignment *scriptAssignment = new Assignment(Assignment::CreateCommand, Assignment::AgentType, Assignment::LocalLocation);
|
Assignment *scriptAssignment = new Assignment(Assignment::CreateCommand, Assignment::AgentType, Assignment::LocalLocation);
|
||||||
|
|
||||||
|
// check how many instances of this assignment the user wants by checking the ASSIGNMENT-INSTANCES header
|
||||||
|
const char ASSIGNMENT_INSTANCES_HTTP_HEADER[] = "ASSIGNMENT-INSTANCES";
|
||||||
|
const char *requestInstancesHeader = mg_get_header(conn, ASSIGNMENT_INSTANCES_HTTP_HEADER);
|
||||||
|
|
||||||
|
if (requestInstancesHeader) {
|
||||||
|
// the user has requested a number of instances greater than 1
|
||||||
|
// so set that on the created assignment
|
||||||
|
scriptAssignment->setNumberOfInstances(atoi(requestInstancesHeader));
|
||||||
|
}
|
||||||
|
|
||||||
QString newPath(ASSIGNMENT_SCRIPT_HOST_LOCATION);
|
QString newPath(ASSIGNMENT_SCRIPT_HOST_LOCATION);
|
||||||
newPath += "/";
|
newPath += "/";
|
||||||
// append the UUID for this script as the new filename, remove the curly braces
|
// append the UUID for this script as the new filename, remove the curly braces
|
||||||
|
@ -94,7 +106,6 @@ static void mongooseUploadHandler(struct mg_connection *conn, const char *path)
|
||||||
::assignmentQueueMutex.lock();
|
::assignmentQueueMutex.lock();
|
||||||
::assignmentQueue.push_back(scriptAssignment);
|
::assignmentQueue.push_back(scriptAssignment);
|
||||||
::assignmentQueueMutex.unlock();
|
::assignmentQueueMutex.unlock();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, const char* argv[]) {
|
int main(int argc, const char* argv[]) {
|
||||||
|
@ -103,7 +114,11 @@ int main(int argc, const char* argv[]) {
|
||||||
|
|
||||||
qInstallMessageHandler(Logging::verboseMessageHandler);
|
qInstallMessageHandler(Logging::verboseMessageHandler);
|
||||||
|
|
||||||
NodeList* nodeList = NodeList::createInstance(NODE_TYPE_DOMAIN, DOMAIN_LISTEN_PORT);
|
const char CUSTOM_PORT_OPTION[] = "-p";
|
||||||
|
const char* customPortString = getCmdOption(argc, argv, CUSTOM_PORT_OPTION);
|
||||||
|
unsigned short domainServerPort = customPortString ? atoi(customPortString) : DOMAIN_LISTEN_PORT;
|
||||||
|
|
||||||
|
NodeList* nodeList = NodeList::createInstance(NODE_TYPE_DOMAIN, domainServerPort);
|
||||||
|
|
||||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||||
|
|
||||||
|
@ -121,20 +136,8 @@ int main(int argc, const char* argv[]) {
|
||||||
in_addr_t serverLocalAddress = getLocalAddress();
|
in_addr_t serverLocalAddress = getLocalAddress();
|
||||||
|
|
||||||
nodeList->startSilentNodeRemovalThread();
|
nodeList->startSilentNodeRemovalThread();
|
||||||
|
|
||||||
timeval lastStatSendTime = {};
|
timeval lastStatSendTime = {};
|
||||||
const char ASSIGNMENT_SERVER_OPTION[] = "-a";
|
|
||||||
|
|
||||||
// grab the overriden assignment-server hostname from argv, if it exists
|
|
||||||
const char* customAssignmentServer = getCmdOption(argc, argv, ASSIGNMENT_SERVER_OPTION);
|
|
||||||
if (customAssignmentServer) {
|
|
||||||
sockaddr_in customAssignmentSocket = socketForHostnameAndHostOrderPort(customAssignmentServer, ASSIGNMENT_SERVER_PORT);
|
|
||||||
nodeList->setAssignmentServerSocket((sockaddr*) &customAssignmentSocket);
|
|
||||||
}
|
|
||||||
|
|
||||||
// use a map to keep track of iterations of silence for assignment creation requests
|
|
||||||
const long long GLOBAL_ASSIGNMENT_REQUEST_INTERVAL_USECS = 1 * 1000 * 1000;
|
|
||||||
timeval lastGlobalAssignmentRequest = {};
|
|
||||||
|
|
||||||
// as a domain-server we will always want an audio mixer and avatar mixer
|
// as a domain-server we will always want an audio mixer and avatar mixer
|
||||||
// setup the create assignments for those
|
// setup the create assignments for those
|
||||||
|
@ -145,10 +148,20 @@ int main(int argc, const char* argv[]) {
|
||||||
Assignment avatarMixerAssignment(Assignment::CreateCommand,
|
Assignment avatarMixerAssignment(Assignment::CreateCommand,
|
||||||
Assignment::AvatarMixerType,
|
Assignment::AvatarMixerType,
|
||||||
Assignment::LocalLocation);
|
Assignment::LocalLocation);
|
||||||
|
|
||||||
Assignment voxelServerAssignment(Assignment::CreateCommand,
|
Assignment voxelServerAssignment(Assignment::CreateCommand,
|
||||||
Assignment::VoxelServerType,
|
Assignment::VoxelServerType,
|
||||||
Assignment::LocalLocation);
|
Assignment::LocalLocation);
|
||||||
|
|
||||||
|
// Handle Domain/Voxel Server configuration command line arguments
|
||||||
|
const char VOXEL_CONFIG_OPTION[] = "--voxelServerConfig";
|
||||||
|
const char* voxelServerConfig = getCmdOption(argc, argv, VOXEL_CONFIG_OPTION);
|
||||||
|
if (voxelServerConfig) {
|
||||||
|
qDebug("Reading Voxel Server Configuration.\n");
|
||||||
|
qDebug() << " config: " << voxelServerConfig << "\n";
|
||||||
|
int payloadLength = strlen(voxelServerConfig) + sizeof(char);
|
||||||
|
voxelServerAssignment.setPayload((const uchar*)voxelServerConfig, payloadLength);
|
||||||
|
}
|
||||||
|
|
||||||
// construct a local socket to send with our created assignments to the global AS
|
// construct a local socket to send with our created assignments to the global AS
|
||||||
sockaddr_in localSocket = {};
|
sockaddr_in localSocket = {};
|
||||||
|
@ -157,13 +170,13 @@ int main(int argc, const char* argv[]) {
|
||||||
localSocket.sin_addr.s_addr = serverLocalAddress;
|
localSocket.sin_addr.s_addr = serverLocalAddress;
|
||||||
|
|
||||||
// setup the mongoose web server
|
// setup the mongoose web server
|
||||||
struct mg_context *ctx;
|
struct mg_context* ctx;
|
||||||
struct mg_callbacks callbacks = {};
|
struct mg_callbacks callbacks = {};
|
||||||
|
|
||||||
QString documentRoot = QString("%1/resources/web").arg(QCoreApplication::applicationDirPath());
|
QString documentRoot = QString("%1/resources/web").arg(QCoreApplication::applicationDirPath());
|
||||||
|
|
||||||
// list of options. Last element must be NULL.
|
// list of options. Last element must be NULL.
|
||||||
const char *options[] = {"listening_ports", "8080",
|
const char* options[] = {"listening_ports", "8080",
|
||||||
"document_root", documentRoot.toStdString().c_str(), NULL};
|
"document_root", documentRoot.toStdString().c_str(), NULL};
|
||||||
|
|
||||||
callbacks.begin_request = mongooseRequestHandler;
|
callbacks.begin_request = mongooseRequestHandler;
|
||||||
|
@ -204,10 +217,9 @@ int main(int argc, const char* argv[]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const int MIN_VOXEL_SERVER_CHECKS = 10;
|
const int MIN_VOXEL_SERVER_CHECKS = 10;
|
||||||
if (checkForVoxelServerAttempt > MIN_VOXEL_SERVER_CHECKS &&
|
if (checkForVoxelServerAttempt > MIN_VOXEL_SERVER_CHECKS && voxelServerCount == 0 &&
|
||||||
voxelServerCount == 0 &&
|
|
||||||
std::find(::assignmentQueue.begin(), ::assignmentQueue.end(), &voxelServerAssignment) == ::assignmentQueue.end()) {
|
std::find(::assignmentQueue.begin(), ::assignmentQueue.end(), &voxelServerAssignment) == ::assignmentQueue.end()) {
|
||||||
qDebug("Missing a Voxel Server and assignment not in queue. Adding.\n");
|
qDebug("Missing a voxel server and assignment not in queue. Adding.\n");
|
||||||
::assignmentQueue.push_front(&voxelServerAssignment);
|
::assignmentQueue.push_front(&voxelServerAssignment);
|
||||||
}
|
}
|
||||||
checkForVoxelServerAttempt++;
|
checkForVoxelServerAttempt++;
|
||||||
|
@ -237,77 +249,107 @@ int main(int argc, const char* argv[]) {
|
||||||
nodePublicAddress.sin_addr.s_addr = 0;
|
nodePublicAddress.sin_addr.s_addr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node* newNode = nodeList->addOrUpdateNode((sockaddr*) &nodePublicAddress,
|
bool matchedUUID = true;
|
||||||
(sockaddr*) &nodeLocalAddress,
|
|
||||||
nodeType,
|
|
||||||
nodeList->getLastNodeID());
|
|
||||||
|
|
||||||
// if addOrUpdateNode returns NULL this was a solo node we already have, don't talk back to it
|
if ((nodeType == NODE_TYPE_AVATAR_MIXER || nodeType == NODE_TYPE_AUDIO_MIXER) &&
|
||||||
if (newNode) {
|
!nodeList->soloNodeOfType(nodeType)) {
|
||||||
if (newNode->getNodeID() == nodeList->getLastNodeID()) {
|
// if this is an audio-mixer or an avatar-mixer and we don't have one yet
|
||||||
nodeList->increaseNodeID();
|
// we need to check the GUID of the assignment in the queue
|
||||||
|
// (if it exists) to make sure there is a match
|
||||||
|
|
||||||
|
// reset matchedUUID to false so there is no match by default
|
||||||
|
matchedUUID = false;
|
||||||
|
|
||||||
|
// pull the UUID passed with the check in
|
||||||
|
QUuid checkInUUID = QUuid::fromRfc4122(QByteArray((const char*) packetData + numBytesSenderHeader +
|
||||||
|
sizeof(NODE_TYPE),
|
||||||
|
NUM_BYTES_RFC4122_UUID));
|
||||||
|
|
||||||
|
// lock the assignment queue
|
||||||
|
::assignmentQueueMutex.lock();
|
||||||
|
|
||||||
|
std::deque<Assignment*>::iterator assignment = ::assignmentQueue.begin();
|
||||||
|
|
||||||
|
Assignment::Type matchType = nodeType == NODE_TYPE_AUDIO_MIXER
|
||||||
|
? Assignment::AudioMixerType : Assignment::AvatarMixerType;
|
||||||
|
|
||||||
|
|
||||||
|
// enumerate the assignments and see if there is a type and UUID match
|
||||||
|
while (assignment != ::assignmentQueue.end()) {
|
||||||
|
|
||||||
|
if ((*assignment)->getType() == matchType
|
||||||
|
&& (*assignment)->getUUID() == checkInUUID) {
|
||||||
|
// type and UUID match
|
||||||
|
matchedUUID = true;
|
||||||
|
|
||||||
|
// remove this assignment from the queue
|
||||||
|
::assignmentQueue.erase(assignment);
|
||||||
|
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// no match, keep looking
|
||||||
|
assignment++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int numHeaderBytes = populateTypeAndVersion(broadcastPacket, PACKET_TYPE_DOMAIN);
|
// unlock the assignment queue
|
||||||
|
::assignmentQueueMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchedUUID) {
|
||||||
|
Node* newNode = nodeList->addOrUpdateNode((sockaddr*) &nodePublicAddress,
|
||||||
|
(sockaddr*) &nodeLocalAddress,
|
||||||
|
nodeType,
|
||||||
|
nodeList->getLastNodeID());
|
||||||
|
|
||||||
currentBufferPos = broadcastPacket + numHeaderBytes;
|
// if addOrUpdateNode returns NULL this was a solo node we already have, don't talk back to it
|
||||||
startPointer = currentBufferPos;
|
if (newNode) {
|
||||||
|
if (newNode->getNodeID() == nodeList->getLastNodeID()) {
|
||||||
unsigned char* nodeTypesOfInterest = packetData + numBytesSenderHeader + sizeof(NODE_TYPE)
|
nodeList->increaseNodeID();
|
||||||
+ numBytesSocket + sizeof(unsigned char);
|
}
|
||||||
int numInterestTypes = *(nodeTypesOfInterest - 1);
|
|
||||||
|
int numHeaderBytes = populateTypeAndVersion(broadcastPacket, PACKET_TYPE_DOMAIN);
|
||||||
if (numInterestTypes > 0) {
|
|
||||||
// if the node has sent no types of interest, assume they want nothing but their own ID back
|
currentBufferPos = broadcastPacket + numHeaderBytes;
|
||||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
startPointer = currentBufferPos;
|
||||||
if (!node->matches((sockaddr*) &nodePublicAddress, (sockaddr*) &nodeLocalAddress, nodeType) &&
|
|
||||||
memchr(nodeTypesOfInterest, node->getType(), numInterestTypes)) {
|
int numBytesUUID = (nodeType == NODE_TYPE_AUDIO_MIXER || nodeType == NODE_TYPE_AVATAR_MIXER)
|
||||||
// this is not the node themselves
|
? NUM_BYTES_RFC4122_UUID
|
||||||
// and this is an node of a type in the passed node types of interest
|
: 0;
|
||||||
// or the node did not pass us any specific types they are interested in
|
|
||||||
|
unsigned char* nodeTypesOfInterest = packetData + numBytesSenderHeader + numBytesUUID +
|
||||||
if (memchr(SOLO_NODE_TYPES, node->getType(), sizeof(SOLO_NODE_TYPES)) == NULL) {
|
sizeof(NODE_TYPE) + numBytesSocket + sizeof(unsigned char);
|
||||||
// this is an node of which there can be multiple, just add them to the packet
|
int numInterestTypes = *(nodeTypesOfInterest - 1);
|
||||||
|
|
||||||
|
if (numInterestTypes > 0) {
|
||||||
|
// if the node has sent no types of interest, assume they want nothing but their own ID back
|
||||||
|
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||||
|
if (!node->matches((sockaddr*) &nodePublicAddress, (sockaddr*) &nodeLocalAddress, nodeType) &&
|
||||||
|
memchr(nodeTypesOfInterest, node->getType(), numInterestTypes)) {
|
||||||
|
|
||||||
// don't send avatar nodes to other avatars, that will come from avatar mixer
|
// don't send avatar nodes to other avatars, that will come from avatar mixer
|
||||||
if (nodeType != NODE_TYPE_AGENT || node->getType() != NODE_TYPE_AGENT) {
|
if (nodeType != NODE_TYPE_AGENT || node->getType() != NODE_TYPE_AGENT) {
|
||||||
currentBufferPos = addNodeToBroadcastPacket(currentBufferPos, &(*node));
|
currentBufferPos = addNodeToBroadcastPacket(currentBufferPos, &(*node));
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
// solo node, we need to only send newest
|
|
||||||
if (newestSoloNodes[node->getType()] == NULL ||
|
|
||||||
newestSoloNodes[node->getType()]->getWakeMicrostamp() < node->getWakeMicrostamp()) {
|
|
||||||
// we have to set the newer solo node to add it to the broadcast later
|
|
||||||
newestSoloNodes[node->getType()] = &(*node);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::map<char, Node *>::iterator soloNode = newestSoloNodes.begin();
|
// update last receive to now
|
||||||
soloNode != newestSoloNodes.end();
|
uint64_t timeNow = usecTimestampNow();
|
||||||
soloNode++) {
|
newNode->setLastHeardMicrostamp(timeNow);
|
||||||
// this is the newest alive solo node, add them to the packet
|
|
||||||
currentBufferPos = addNodeToBroadcastPacket(currentBufferPos, soloNode->second);
|
// add the node ID to the end of the pointer
|
||||||
}
|
currentBufferPos += packNodeId(currentBufferPos, newNode->getNodeID());
|
||||||
|
|
||||||
|
// send the constructed list back to this node
|
||||||
|
nodeList->getNodeSocket()->send((sockaddr*)&replyDestinationSocket,
|
||||||
|
broadcastPacket,
|
||||||
|
(currentBufferPos - startPointer) + numHeaderBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update last receive to now
|
|
||||||
uint64_t timeNow = usecTimestampNow();
|
|
||||||
newNode->setLastHeardMicrostamp(timeNow);
|
|
||||||
|
|
||||||
if (packetData[0] == PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY
|
|
||||||
&& memchr(SOLO_NODE_TYPES, nodeType, sizeof(SOLO_NODE_TYPES))) {
|
|
||||||
newNode->setWakeMicrostamp(timeNow);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the node ID to the end of the pointer
|
|
||||||
currentBufferPos += packNodeId(currentBufferPos, newNode->getNodeID());
|
|
||||||
|
|
||||||
// send the constructed list back to this node
|
|
||||||
nodeList->getNodeSocket()->send((sockaddr*)&replyDestinationSocket,
|
|
||||||
broadcastPacket,
|
|
||||||
(currentBufferPos - startPointer) + numHeaderBytes);
|
|
||||||
}
|
}
|
||||||
} else if (packetData[0] == PACKET_TYPE_REQUEST_ASSIGNMENT) {
|
} else if (packetData[0] == PACKET_TYPE_REQUEST_ASSIGNMENT) {
|
||||||
|
|
||||||
|
@ -320,65 +362,65 @@ int main(int argc, const char* argv[]) {
|
||||||
std::deque<Assignment*>::iterator assignment = ::assignmentQueue.begin();
|
std::deque<Assignment*>::iterator assignment = ::assignmentQueue.begin();
|
||||||
|
|
||||||
while (assignment != ::assignmentQueue.end()) {
|
while (assignment != ::assignmentQueue.end()) {
|
||||||
|
// construct the requested assignment from the packet data
|
||||||
|
Assignment requestAssignment(packetData, receivedBytes);
|
||||||
|
|
||||||
// give this assignment out, no conditions stop us from giving it to the local assignment client
|
if (requestAssignment.getType() == Assignment::AllTypes ||
|
||||||
int numHeaderBytes = populateTypeAndVersion(broadcastPacket, PACKET_TYPE_CREATE_ASSIGNMENT);
|
(*assignment)->getType() == requestAssignment.getType()) {
|
||||||
int numAssignmentBytes = (*assignment)->packToBuffer(broadcastPacket + numHeaderBytes);
|
// attach our local socket to the assignment
|
||||||
|
(*assignment)->setAttachedLocalSocket((sockaddr*) &localSocket);
|
||||||
nodeList->getNodeSocket()->send((sockaddr*) &nodePublicAddress,
|
|
||||||
broadcastPacket,
|
// give this assignment out, either the type matches or the requestor said they will take any
|
||||||
numHeaderBytes + numAssignmentBytes);
|
int numHeaderBytes = populateTypeAndVersion(broadcastPacket, PACKET_TYPE_CREATE_ASSIGNMENT);
|
||||||
|
int numAssignmentBytes = (*assignment)->packToBuffer(broadcastPacket + numHeaderBytes);
|
||||||
// remove the assignment from the queue
|
|
||||||
::assignmentQueue.erase(assignment);
|
nodeList->getNodeSocket()->send((sockaddr*) &nodePublicAddress,
|
||||||
|
broadcastPacket,
|
||||||
if ((*assignment)->getType() == Assignment::AgentType) {
|
numHeaderBytes + numAssignmentBytes);
|
||||||
// if this is a script assignment we need to delete it to avoid a memory leak
|
|
||||||
delete *assignment;
|
if ((*assignment)->getType() == Assignment::AgentType) {
|
||||||
|
// if this is a script assignment we need to delete it to avoid a memory leak
|
||||||
|
// or if there is more than one instance to send out, simpy decrease the number of instances
|
||||||
|
if ((*assignment)->getNumberOfInstances() > 1) {
|
||||||
|
(*assignment)->decrementNumberOfInstances();
|
||||||
|
} else {
|
||||||
|
::assignmentQueue.erase(assignment);
|
||||||
|
delete *assignment;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// remove the assignment from the queue
|
||||||
|
::assignmentQueue.erase(assignment);
|
||||||
|
|
||||||
|
if ((*assignment)->getType() != Assignment::VoxelServerType) {
|
||||||
|
// keep audio-mixer and avatar-mixer assignments in the queue
|
||||||
|
// until we get a check-in from that GUID
|
||||||
|
// but stick it at the back so the others have a chance to go out
|
||||||
|
::assignmentQueue.push_back(*assignment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop looping, we've handed out an assignment
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// push forward the iterator to check the next assignment
|
||||||
|
assignment++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop looping, we've handed out an assignment
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
::assignmentQueueMutex.unlock();
|
::assignmentQueueMutex.unlock();
|
||||||
}
|
} else if (packetData[0] == PACKET_TYPE_CREATE_ASSIGNMENT) {
|
||||||
}
|
// this is a create assignment likely recieved from a server needed more clients to help with load
|
||||||
|
|
||||||
// if ASSIGNMENT_REQUEST_INTERVAL_USECS have passed since last global assignment request then fire off another
|
|
||||||
if (usecTimestampNow() - usecTimestamp(&lastGlobalAssignmentRequest) >= GLOBAL_ASSIGNMENT_REQUEST_INTERVAL_USECS) {
|
|
||||||
gettimeofday(&lastGlobalAssignmentRequest, NULL);
|
|
||||||
|
|
||||||
::assignmentQueueMutex.lock();
|
|
||||||
|
|
||||||
// go through our queue and see if there are any assignments to send to the global assignment server
|
|
||||||
std::deque<Assignment*>::iterator assignment = ::assignmentQueue.begin();
|
|
||||||
|
|
||||||
while (assignment != assignmentQueue.end()) {
|
|
||||||
|
|
||||||
if ((*assignment)->getLocation() != Assignment::LocalLocation) {
|
// unpack it
|
||||||
// attach our local socket to the assignment so the assignment-server can optionally hand it out
|
Assignment* createAssignment = new Assignment(packetData, receivedBytes);
|
||||||
(*assignment)->setAttachedLocalSocket((sockaddr*) &localSocket);
|
|
||||||
|
qDebug() << "Received a create assignment -" << *createAssignment << "\n";
|
||||||
nodeList->sendAssignment(*(*assignment));
|
|
||||||
|
// add the assignment at the back of the queue
|
||||||
// remove the assignment from the queue
|
::assignmentQueueMutex.lock();
|
||||||
::assignmentQueue.erase(assignment);
|
::assignmentQueue.push_back(createAssignment);
|
||||||
|
::assignmentQueueMutex.unlock();
|
||||||
if ((*assignment)->getType() == Assignment::AgentType) {
|
|
||||||
// if this is a script assignment we need to delete it to avoid a memory leak
|
|
||||||
delete *assignment;
|
|
||||||
}
|
|
||||||
|
|
||||||
// stop looping, we've handed out an assignment
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
// push forward the iterator to check the next assignment
|
|
||||||
assignment++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
::assignmentQueueMutex.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Logging::shouldSendStats()) {
|
if (Logging::shouldSendStats()) {
|
||||||
|
|
|
@ -183,18 +183,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
// --domain or --local options
|
// --domain or --local options
|
||||||
NodeList::getInstance()->loadData(_settings);
|
NodeList::getInstance()->loadData(_settings);
|
||||||
|
|
||||||
const char* domainIP = getCmdOption(argc, constArgv, "--domain");
|
|
||||||
if (domainIP) {
|
|
||||||
NodeList::getInstance()->setDomainIP(domainIP);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle Local Domain testing with the --local command line
|
|
||||||
if (cmdOptionExists(argc, constArgv, "--local")) {
|
|
||||||
qDebug("Local Domain MODE!\n");
|
|
||||||
|
|
||||||
NodeList::getInstance()->setDomainIPToLocalhost();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check to see if the user passed in a command line option for loading a local
|
// Check to see if the user passed in a command line option for loading a local
|
||||||
// Voxel File.
|
// Voxel File.
|
||||||
_voxelsFilename = getCmdOption(argc, constArgv, "-i");
|
_voxelsFilename = getCmdOption(argc, constArgv, "-i");
|
||||||
|
|
|
@ -17,9 +17,8 @@
|
||||||
#define SETTINGS_VERSION_KEY "info-version"
|
#define SETTINGS_VERSION_KEY "info-version"
|
||||||
#define MAX_DIALOG_HEIGHT_RATIO 0.9
|
#define MAX_DIALOG_HEIGHT_RATIO 0.9
|
||||||
|
|
||||||
InfoView::InfoView(bool forced) {
|
InfoView::InfoView(bool forced) :
|
||||||
_forced = forced;
|
_forced(forced) {
|
||||||
settings()->setAttribute(QWebSettings::LocalContentCanAccessFileUrls, true);
|
|
||||||
|
|
||||||
switchToResourcesParentIfRequired();
|
switchToResourcesParentIfRequired();
|
||||||
QString absPath = QFileInfo("resources/html/interface-welcome-allsvg.html").absoluteFilePath();
|
QString absPath = QFileInfo("resources/html/interface-welcome-allsvg.html").absoluteFilePath();
|
||||||
|
|
|
@ -688,6 +688,48 @@ void Menu::aboutApp() {
|
||||||
InfoView::forcedShow();
|
InfoView::forcedShow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateDSHostname(const QString& domainServerHostname) {
|
||||||
|
QString newHostname(DEFAULT_DOMAIN_HOSTNAME);
|
||||||
|
|
||||||
|
if (domainServerHostname.size() > 0) {
|
||||||
|
// the user input a new hostname, use that
|
||||||
|
newHostname = domainServerHostname;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the domain server hostname is new
|
||||||
|
if (NodeList::getInstance()->getDomainHostname() != newHostname) {
|
||||||
|
|
||||||
|
NodeList::getInstance()->clear();
|
||||||
|
|
||||||
|
// kill the local voxels
|
||||||
|
Application::getInstance()->getVoxels()->killLocalVoxels();
|
||||||
|
|
||||||
|
// reset the environment to default
|
||||||
|
Application::getInstance()->getEnvironment()->resetToDefault();
|
||||||
|
|
||||||
|
// set the new hostname
|
||||||
|
NodeList::getInstance()->setDomainHostname(newHostname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int QLINE_MINIMUM_WIDTH = 400;
|
||||||
|
|
||||||
|
|
||||||
|
QLineEdit* lineEditForDomainHostname() {
|
||||||
|
QString currentDomainHostname = NodeList::getInstance()->getDomainHostname();
|
||||||
|
|
||||||
|
if (NodeList::getInstance()->getDomainPort() != DEFAULT_DOMAIN_SERVER_PORT) {
|
||||||
|
// add the port to the currentDomainHostname string if it is custom
|
||||||
|
currentDomainHostname.append(QString(":%1").arg(NodeList::getInstance()->getDomainPort()));
|
||||||
|
}
|
||||||
|
|
||||||
|
QLineEdit* domainServerLineEdit = new QLineEdit(currentDomainHostname);
|
||||||
|
domainServerLineEdit->setPlaceholderText(DEFAULT_DOMAIN_HOSTNAME);
|
||||||
|
domainServerLineEdit->setMinimumWidth(QLINE_MINIMUM_WIDTH);
|
||||||
|
|
||||||
|
return domainServerLineEdit;
|
||||||
|
}
|
||||||
|
|
||||||
void Menu::editPreferences() {
|
void Menu::editPreferences() {
|
||||||
Application* applicationInstance = Application::getInstance();
|
Application* applicationInstance = Application::getInstance();
|
||||||
QDialog dialog(applicationInstance->getGLWidget());
|
QDialog dialog(applicationInstance->getGLWidget());
|
||||||
|
@ -698,11 +740,8 @@ void Menu::editPreferences() {
|
||||||
QFormLayout* form = new QFormLayout();
|
QFormLayout* form = new QFormLayout();
|
||||||
layout->addLayout(form, 1);
|
layout->addLayout(form, 1);
|
||||||
|
|
||||||
const int QLINE_MINIMUM_WIDTH = 400;
|
QLineEdit* domainServerLineEdit = lineEditForDomainHostname();
|
||||||
|
form->addRow("Domain server:", domainServerLineEdit);
|
||||||
QLineEdit* domainServerHostname = new QLineEdit(QString(NodeList::getInstance()->getDomainHostname()));
|
|
||||||
domainServerHostname->setMinimumWidth(QLINE_MINIMUM_WIDTH);
|
|
||||||
form->addRow("Domain server:", domainServerHostname);
|
|
||||||
|
|
||||||
QLineEdit* avatarURL = new QLineEdit(applicationInstance->getAvatar()->getVoxels()->getVoxelURL().toString());
|
QLineEdit* avatarURL = new QLineEdit(applicationInstance->getAvatar()->getVoxels()->getVoxelURL().toString());
|
||||||
avatarURL->setMinimumWidth(QLINE_MINIMUM_WIDTH);
|
avatarURL->setMinimumWidth(QLINE_MINIMUM_WIDTH);
|
||||||
|
@ -743,30 +782,7 @@ void Menu::editPreferences() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray newHostname;
|
updateDSHostname(domainServerLineEdit->text());
|
||||||
|
|
||||||
if (domainServerHostname->text().size() > 0) {
|
|
||||||
// the user input a new hostname, use that
|
|
||||||
newHostname = domainServerHostname->text().toLocal8Bit();
|
|
||||||
} else {
|
|
||||||
// the user left the field blank, use the default hostname
|
|
||||||
newHostname = QByteArray(DEFAULT_DOMAIN_HOSTNAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if the domain server hostname is new
|
|
||||||
if (memcmp(NodeList::getInstance()->getDomainHostname(), newHostname.constData(), newHostname.size()) != 0) {
|
|
||||||
|
|
||||||
NodeList::getInstance()->clear();
|
|
||||||
|
|
||||||
// kill the local voxels
|
|
||||||
applicationInstance->getVoxels()->killLocalVoxels();
|
|
||||||
|
|
||||||
// reset the environment to default
|
|
||||||
applicationInstance->getEnvironment()->resetToDefault();
|
|
||||||
|
|
||||||
// set the new hostname
|
|
||||||
NodeList::getInstance()->setDomainHostname(newHostname.constData());
|
|
||||||
}
|
|
||||||
|
|
||||||
QUrl avatarVoxelURL(avatarURL->text());
|
QUrl avatarVoxelURL(avatarURL->text());
|
||||||
applicationInstance->getAvatar()->getVoxels()->setVoxelURL(avatarVoxelURL);
|
applicationInstance->getAvatar()->getVoxels()->setVoxelURL(avatarVoxelURL);
|
||||||
|
@ -798,12 +814,10 @@ void Menu::goToDomain() {
|
||||||
|
|
||||||
QFormLayout* form = new QFormLayout();
|
QFormLayout* form = new QFormLayout();
|
||||||
layout->addLayout(form, 1);
|
layout->addLayout(form, 1);
|
||||||
|
|
||||||
|
|
||||||
const int QLINE_MINIMUM_WIDTH = 400;
|
QLineEdit* domainServerLineEdit = lineEditForDomainHostname();
|
||||||
|
form->addRow("Domain server:", domainServerLineEdit);
|
||||||
QLineEdit* domainServerHostname = new QLineEdit(QString(NodeList::getInstance()->getDomainHostname()));
|
|
||||||
domainServerHostname->setMinimumWidth(QLINE_MINIMUM_WIDTH);
|
|
||||||
form->addRow("Domain server:", domainServerHostname);
|
|
||||||
|
|
||||||
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept()));
|
dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept()));
|
||||||
|
@ -816,30 +830,7 @@ void Menu::goToDomain() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray newHostname;
|
updateDSHostname(domainServerLineEdit->text());
|
||||||
|
|
||||||
if (domainServerHostname->text().size() > 0) {
|
|
||||||
// the user input a new hostname, use that
|
|
||||||
newHostname = domainServerHostname->text().toLocal8Bit();
|
|
||||||
} else {
|
|
||||||
// the user left the field blank, use the default hostname
|
|
||||||
newHostname = QByteArray(DEFAULT_DOMAIN_HOSTNAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if the domain server hostname is new
|
|
||||||
if (memcmp(NodeList::getInstance()->getDomainHostname(), newHostname.constData(), newHostname.size()) != 0) {
|
|
||||||
|
|
||||||
NodeList::getInstance()->clear();
|
|
||||||
|
|
||||||
// kill the local voxels
|
|
||||||
applicationInstance->getVoxels()->killLocalVoxels();
|
|
||||||
|
|
||||||
// reset the environment to default
|
|
||||||
applicationInstance->getEnvironment()->resetToDefault();
|
|
||||||
|
|
||||||
// set the new hostname
|
|
||||||
NodeList::getInstance()->setDomainHostname(newHostname.constData());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Menu::goToLocation() {
|
void Menu::goToLocation() {
|
||||||
|
|
|
@ -16,10 +16,4 @@ include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||||
include_glm(${TARGET_NAME} ${ROOT_DIR})
|
include_glm(${TARGET_NAME} ${ROOT_DIR})
|
||||||
|
|
||||||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||||
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
|
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
|
||||||
|
|
||||||
# link the stk library
|
|
||||||
set(STK_ROOT_DIR ${ROOT_DIR}/externals/stk)
|
|
||||||
find_package(STK REQUIRED)
|
|
||||||
target_link_libraries(${TARGET_NAME} ${STK_LIBRARIES})
|
|
||||||
include_directories(${STK_INCLUDE_DIRS})
|
|
|
@ -6,9 +6,13 @@ set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
|
||||||
set(TARGET_NAME shared)
|
set(TARGET_NAME shared)
|
||||||
project(${TARGET_NAME})
|
project(${TARGET_NAME})
|
||||||
|
|
||||||
|
find_package(Qt5Network REQUIRED)
|
||||||
|
|
||||||
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
|
include(${MACRO_DIR}/SetupHifiLibrary.cmake)
|
||||||
setup_hifi_library(${TARGET_NAME})
|
setup_hifi_library(${TARGET_NAME})
|
||||||
|
|
||||||
|
qt5_use_modules(${TARGET_NAME} Network)
|
||||||
|
|
||||||
set(EXTERNAL_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external)
|
set(EXTERNAL_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external)
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
|
|
|
@ -14,14 +14,15 @@
|
||||||
const char IPv4_ADDRESS_DESIGNATOR = 4;
|
const char IPv4_ADDRESS_DESIGNATOR = 4;
|
||||||
const char IPv6_ADDRESS_DESIGNATOR = 6;
|
const char IPv6_ADDRESS_DESIGNATOR = 6;
|
||||||
|
|
||||||
const int NUM_BYTES_RFC4122_UUID = 16;
|
|
||||||
|
|
||||||
Assignment::Assignment(Assignment::Command command, Assignment::Type type, Assignment::Location location) :
|
Assignment::Assignment(Assignment::Command command, Assignment::Type type, Assignment::Location location) :
|
||||||
_command(command),
|
_command(command),
|
||||||
_type(type),
|
_type(type),
|
||||||
_location(location),
|
_location(location),
|
||||||
_attachedPublicSocket(NULL),
|
_attachedPublicSocket(NULL),
|
||||||
_attachedLocalSocket(NULL)
|
_attachedLocalSocket(NULL),
|
||||||
|
_numberOfInstances(1),
|
||||||
|
_payload(NULL),
|
||||||
|
_numPayloadBytes(0)
|
||||||
{
|
{
|
||||||
// set the create time on this assignment
|
// set the create time on this assignment
|
||||||
gettimeofday(&_time, NULL);
|
gettimeofday(&_time, NULL);
|
||||||
|
@ -35,7 +36,10 @@ Assignment::Assignment(Assignment::Command command, Assignment::Type type, Assig
|
||||||
Assignment::Assignment(const unsigned char* dataBuffer, int numBytes) :
|
Assignment::Assignment(const unsigned char* dataBuffer, int numBytes) :
|
||||||
_location(GlobalLocation),
|
_location(GlobalLocation),
|
||||||
_attachedPublicSocket(NULL),
|
_attachedPublicSocket(NULL),
|
||||||
_attachedLocalSocket(NULL)
|
_attachedLocalSocket(NULL),
|
||||||
|
_numberOfInstances(1),
|
||||||
|
_payload(NULL),
|
||||||
|
_numPayloadBytes(0)
|
||||||
{
|
{
|
||||||
// set the create time on this assignment
|
// set the create time on this assignment
|
||||||
gettimeofday(&_time, NULL);
|
gettimeofday(&_time, NULL);
|
||||||
|
@ -52,41 +56,67 @@ Assignment::Assignment(const unsigned char* dataBuffer, int numBytes) :
|
||||||
|
|
||||||
numBytesRead += numBytesForPacketHeader(dataBuffer);
|
numBytesRead += numBytesForPacketHeader(dataBuffer);
|
||||||
|
|
||||||
|
memcpy(&_type, dataBuffer + numBytesRead, sizeof(Assignment::Type));
|
||||||
|
numBytesRead += sizeof(Assignment::Type);
|
||||||
|
|
||||||
if (dataBuffer[0] != PACKET_TYPE_REQUEST_ASSIGNMENT) {
|
if (dataBuffer[0] != PACKET_TYPE_REQUEST_ASSIGNMENT) {
|
||||||
// read the GUID for this assignment
|
// read the GUID for this assignment
|
||||||
_uuid = QUuid::fromRfc4122(QByteArray((const char*) dataBuffer + numBytesRead, NUM_BYTES_RFC4122_UUID));
|
_uuid = QUuid::fromRfc4122(QByteArray((const char*) dataBuffer + numBytesRead, NUM_BYTES_RFC4122_UUID));
|
||||||
numBytesRead += NUM_BYTES_RFC4122_UUID;
|
numBytesRead += NUM_BYTES_RFC4122_UUID;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&_type, dataBuffer + numBytesRead, sizeof(Assignment::Type));
|
if (_command != Assignment::RequestCommand) {
|
||||||
numBytesRead += sizeof(Assignment::Type);
|
|
||||||
|
|
||||||
if (numBytes > numBytesRead) {
|
|
||||||
|
|
||||||
sockaddr* newSocket = NULL;
|
sockaddr* newSocket = NULL;
|
||||||
|
|
||||||
if (dataBuffer[numBytesRead++] == IPv4_ADDRESS_DESIGNATOR) {
|
if (dataBuffer[numBytesRead++] == IPv4_ADDRESS_DESIGNATOR) {
|
||||||
// IPv4 address
|
// IPv4 address
|
||||||
newSocket = (sockaddr*) new sockaddr_in;
|
newSocket = (sockaddr*) new sockaddr_in;
|
||||||
unpackSocket(dataBuffer + numBytesRead, newSocket);
|
numBytesRead += unpackSocket(dataBuffer + numBytesRead, newSocket);
|
||||||
|
|
||||||
|
if (_command == Assignment::CreateCommand) {
|
||||||
|
delete _attachedLocalSocket;
|
||||||
|
_attachedLocalSocket = newSocket;
|
||||||
|
} else {
|
||||||
|
delete _attachedPublicSocket;
|
||||||
|
_attachedPublicSocket = newSocket;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// IPv6 address, or bad designator
|
// IPv6 address, or bad designator
|
||||||
qDebug("Received a socket that cannot be unpacked!\n");
|
qDebug("Received a socket that cannot be unpacked!\n");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (_command == Assignment::CreateCommand) {
|
|
||||||
delete _attachedLocalSocket;
|
if (numBytes > numBytesRead) {
|
||||||
_attachedLocalSocket = newSocket;
|
_numPayloadBytes = numBytes - numBytesRead;
|
||||||
} else {
|
_payload = new uchar[_numPayloadBytes];
|
||||||
delete _attachedPublicSocket;
|
memcpy(_payload, dataBuffer + numBytesRead, _numPayloadBytes);
|
||||||
_attachedPublicSocket = newSocket;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Assignment::~Assignment() {
|
Assignment::~Assignment() {
|
||||||
delete _attachedPublicSocket;
|
delete _attachedPublicSocket;
|
||||||
delete _attachedLocalSocket;
|
delete _attachedLocalSocket;
|
||||||
|
delete[] _payload;
|
||||||
|
_numPayloadBytes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int MAX_PAYLOAD_BYTES = 1024;
|
||||||
|
|
||||||
|
void Assignment::setPayload(const uchar* payload, int numBytes) {
|
||||||
|
|
||||||
|
if (numBytes > MAX_PAYLOAD_BYTES) {
|
||||||
|
qDebug("Set payload called with number of bytes greater than maximum (%d). Will only transfer %d bytes.\n",
|
||||||
|
MAX_PAYLOAD_BYTES,
|
||||||
|
MAX_PAYLOAD_BYTES);
|
||||||
|
|
||||||
|
_numPayloadBytes = 1024;
|
||||||
|
} else {
|
||||||
|
_numPayloadBytes = numBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] _payload;
|
||||||
|
_payload = new uchar[_numPayloadBytes];
|
||||||
|
memcpy(_payload, payload, _numPayloadBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Assignment::getUUIDStringWithoutCurlyBraces() const {
|
QString Assignment::getUUIDStringWithoutCurlyBraces() const {
|
||||||
|
@ -120,15 +150,15 @@ void Assignment::setAttachedLocalSocket(const sockaddr* attachedLocalSocket) {
|
||||||
int Assignment::packToBuffer(unsigned char* buffer) {
|
int Assignment::packToBuffer(unsigned char* buffer) {
|
||||||
int numPackedBytes = 0;
|
int numPackedBytes = 0;
|
||||||
|
|
||||||
// pack the UUID for this assignment, if this is an assignment create or deploy
|
|
||||||
if (_command != Assignment::RequestCommand) {
|
|
||||||
memcpy(buffer, _uuid.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID);
|
|
||||||
numPackedBytes += NUM_BYTES_RFC4122_UUID;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(buffer + numPackedBytes, &_type, sizeof(_type));
|
memcpy(buffer + numPackedBytes, &_type, sizeof(_type));
|
||||||
numPackedBytes += sizeof(_type);
|
numPackedBytes += sizeof(_type);
|
||||||
|
|
||||||
|
// pack the UUID for this assignment, if this is an assignment create or deploy
|
||||||
|
if (_command != Assignment::RequestCommand) {
|
||||||
|
memcpy(buffer + numPackedBytes, _uuid.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID);
|
||||||
|
numPackedBytes += NUM_BYTES_RFC4122_UUID;
|
||||||
|
}
|
||||||
|
|
||||||
if (_attachedPublicSocket || _attachedLocalSocket) {
|
if (_attachedPublicSocket || _attachedLocalSocket) {
|
||||||
sockaddr* socketToPack = (_attachedPublicSocket) ? _attachedPublicSocket : _attachedLocalSocket;
|
sockaddr* socketToPack = (_attachedPublicSocket) ? _attachedPublicSocket : _attachedLocalSocket;
|
||||||
|
|
||||||
|
@ -138,10 +168,17 @@ int Assignment::packToBuffer(unsigned char* buffer) {
|
||||||
|
|
||||||
numPackedBytes += packSocket(buffer + numPackedBytes, socketToPack);
|
numPackedBytes += packSocket(buffer + numPackedBytes, socketToPack);
|
||||||
}
|
}
|
||||||
|
if (_numPayloadBytes) {
|
||||||
|
memcpy(buffer + numPackedBytes, _payload, _numPayloadBytes);
|
||||||
|
numPackedBytes += _numPayloadBytes;
|
||||||
|
}
|
||||||
return numPackedBytes;
|
return numPackedBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Assignment::run() {
|
||||||
|
// run method ovveridden by subclasses
|
||||||
|
}
|
||||||
|
|
||||||
QDebug operator<<(QDebug debug, const Assignment &assignment) {
|
QDebug operator<<(QDebug debug, const Assignment &assignment) {
|
||||||
debug << "T:" << assignment.getType();
|
debug << "T:" << assignment.getType();
|
||||||
return debug.nospace();
|
return debug.nospace();
|
||||||
|
|
|
@ -15,8 +15,11 @@
|
||||||
|
|
||||||
#include "NodeList.h"
|
#include "NodeList.h"
|
||||||
|
|
||||||
|
const int NUM_BYTES_RFC4122_UUID = 16;
|
||||||
|
|
||||||
/// Holds information used for request, creation, and deployment of assignments
|
/// Holds information used for request, creation, and deployment of assignments
|
||||||
class Assignment {
|
class Assignment : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum Type {
|
enum Type {
|
||||||
|
@ -56,12 +59,20 @@ public:
|
||||||
Assignment::Location getLocation() const { return _location; }
|
Assignment::Location getLocation() const { return _location; }
|
||||||
const timeval& getTime() const { return _time; }
|
const timeval& getTime() const { return _time; }
|
||||||
|
|
||||||
|
uchar* getPayload() { return _payload; }
|
||||||
|
int getNumPayloadBytes() const { return _numPayloadBytes; }
|
||||||
|
void setPayload(const uchar *payload, int numBytes);
|
||||||
|
|
||||||
|
int getNumberOfInstances() const { return _numberOfInstances; }
|
||||||
|
void setNumberOfInstances(int numberOfInstances) { _numberOfInstances = numberOfInstances; }
|
||||||
|
void decrementNumberOfInstances() { --_numberOfInstances; }
|
||||||
|
|
||||||
const sockaddr* getAttachedPublicSocket() { return _attachedPublicSocket; }
|
const sockaddr* getAttachedPublicSocket() { return _attachedPublicSocket; }
|
||||||
void setAttachedPublicSocket(const sockaddr* attachedPublicSocket);
|
void setAttachedPublicSocket(const sockaddr* attachedPublicSocket);
|
||||||
|
|
||||||
const sockaddr* getAttachedLocalSocket() { return _attachedLocalSocket; }
|
const sockaddr* getAttachedLocalSocket() { return _attachedLocalSocket; }
|
||||||
void setAttachedLocalSocket(const sockaddr* attachedLocalSocket);
|
void setAttachedLocalSocket(const sockaddr* attachedLocalSocket);
|
||||||
|
|
||||||
/// Packs the assignment to the passed buffer
|
/// Packs the assignment to the passed buffer
|
||||||
/// \param buffer the buffer in which to pack the assignment
|
/// \param buffer the buffer in which to pack the assignment
|
||||||
/// \return number of bytes packed into buffer
|
/// \return number of bytes packed into buffer
|
||||||
|
@ -70,6 +81,9 @@ public:
|
||||||
/// Sets _time to the current time given by gettimeofday
|
/// Sets _time to the current time given by gettimeofday
|
||||||
void setCreateTimeToNow() { gettimeofday(&_time, NULL); }
|
void setCreateTimeToNow() { gettimeofday(&_time, NULL); }
|
||||||
|
|
||||||
|
/// blocking run of the assignment
|
||||||
|
virtual void run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QUuid _uuid; /// the 16 byte UUID for this assignment
|
QUuid _uuid; /// the 16 byte UUID for this assignment
|
||||||
Assignment::Command _command; /// the command for this assignment (Create, Deploy, Request)
|
Assignment::Command _command; /// the command for this assignment (Create, Deploy, Request)
|
||||||
|
@ -78,6 +92,9 @@ private:
|
||||||
sockaddr* _attachedPublicSocket; /// pointer to a public socket that relates to assignment, depends on direction
|
sockaddr* _attachedPublicSocket; /// pointer to a public socket that relates to assignment, depends on direction
|
||||||
sockaddr* _attachedLocalSocket; /// pointer to a local socket that relates to assignment, depends on direction
|
sockaddr* _attachedLocalSocket; /// pointer to a local socket that relates to assignment, depends on direction
|
||||||
timeval _time; /// time the assignment was created (set in constructor)
|
timeval _time; /// time the assignment was created (set in constructor)
|
||||||
|
int _numberOfInstances; /// the number of instances of this assignment
|
||||||
|
uchar *_payload; /// an optional payload attached to this assignment, a maximum for 1024 bytes will be packed
|
||||||
|
int _numPayloadBytes; /// number of bytes in the payload, up to a maximum of 1024
|
||||||
};
|
};
|
||||||
|
|
||||||
QDebug operator<<(QDebug debug, const Assignment &assignment);
|
QDebug operator<<(QDebug debug, const Assignment &assignment);
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
|
#include <QtNetwork/QHostInfo>
|
||||||
|
|
||||||
#include "Assignment.h"
|
#include "Assignment.h"
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
|
@ -31,9 +32,8 @@ const char SOLO_NODE_TYPES[2] = {
|
||||||
NODE_TYPE_AUDIO_MIXER
|
NODE_TYPE_AUDIO_MIXER
|
||||||
};
|
};
|
||||||
|
|
||||||
const char DEFAULT_DOMAIN_HOSTNAME[MAX_HOSTNAME_BYTES] = "root.highfidelity.io";
|
const QString DEFAULT_DOMAIN_HOSTNAME = "root.highfidelity.io";
|
||||||
const char DEFAULT_DOMAIN_IP[INET_ADDRSTRLEN] = ""; // IP Address will be re-set by lookup on startup
|
const unsigned short DEFAULT_DOMAIN_SERVER_PORT = 40102;
|
||||||
const int DEFAULT_DOMAINSERVER_PORT = 40102;
|
|
||||||
|
|
||||||
bool silentNodeThreadStopFlag = false;
|
bool silentNodeThreadStopFlag = false;
|
||||||
bool pingUnknownNodeThreadStopFlag = false;
|
bool pingUnknownNodeThreadStopFlag = false;
|
||||||
|
@ -59,6 +59,9 @@ NodeList* NodeList::getInstance() {
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) :
|
NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) :
|
||||||
|
_domainHostname(DEFAULT_DOMAIN_HOSTNAME),
|
||||||
|
_domainIP(),
|
||||||
|
_domainPort(DEFAULT_DOMAIN_SERVER_PORT),
|
||||||
_nodeBuckets(),
|
_nodeBuckets(),
|
||||||
_numNodes(0),
|
_numNodes(0),
|
||||||
_nodeSocket(newSocketListenPort),
|
_nodeSocket(newSocketListenPort),
|
||||||
|
@ -69,8 +72,7 @@ NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) :
|
||||||
_numNoReplyDomainCheckIns(0),
|
_numNoReplyDomainCheckIns(0),
|
||||||
_assignmentServerSocket(NULL)
|
_assignmentServerSocket(NULL)
|
||||||
{
|
{
|
||||||
memcpy(_domainHostname, DEFAULT_DOMAIN_HOSTNAME, sizeof(DEFAULT_DOMAIN_HOSTNAME));
|
|
||||||
memcpy(_domainIP, DEFAULT_DOMAIN_IP, sizeof(DEFAULT_DOMAIN_IP));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeList::~NodeList() {
|
NodeList::~NodeList() {
|
||||||
|
@ -82,22 +84,29 @@ NodeList::~NodeList() {
|
||||||
stopSilentNodeRemovalThread();
|
stopSilentNodeRemovalThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeList::setDomainHostname(const char* domainHostname) {
|
void NodeList::setDomainHostname(const QString& domainHostname) {
|
||||||
memset(_domainHostname, 0, sizeof(_domainHostname));
|
|
||||||
memcpy(_domainHostname, domainHostname, strlen(domainHostname));
|
|
||||||
|
|
||||||
// reset the domain IP so the hostname is checked again
|
int colonIndex = domainHostname.indexOf(':');
|
||||||
setDomainIP("");
|
|
||||||
}
|
if (colonIndex > 0) {
|
||||||
|
// the user has included a custom DS port with the hostname
|
||||||
void NodeList::setDomainIP(const char* domainIP) {
|
|
||||||
memset(_domainIP, 0, sizeof(_domainIP));
|
// the new hostname is everything up to the colon
|
||||||
memcpy(_domainIP, domainIP, strlen(domainIP));
|
_domainHostname = domainHostname.left(colonIndex);
|
||||||
}
|
|
||||||
|
// grab the port by reading the string after the colon
|
||||||
void NodeList::setDomainIPToLocalhost() {
|
_domainPort = atoi(domainHostname.mid(colonIndex + 1, domainHostname.size()).toLocal8Bit().constData());
|
||||||
int ip = getLocalAddress();
|
|
||||||
sprintf(_domainIP, "%d.%d.%d.%d", (ip & 0xFF), ((ip >> 8) & 0xFF),((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF));
|
qDebug() << "Updated hostname to" << _domainHostname << "and port to" << _domainPort << "\n";
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// no port included with the hostname, simply set the member variable and reset the domain server port to default
|
||||||
|
_domainHostname = domainHostname;
|
||||||
|
_domainPort = DEFAULT_DOMAIN_SERVER_PORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset our _domainIP to the null address so that a lookup happens on next check in
|
||||||
|
_domainIP.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeList::timePingReply(sockaddr *nodeAddress, unsigned char *packetData) {
|
void NodeList::timePingReply(sockaddr *nodeAddress, unsigned char *packetData) {
|
||||||
|
@ -117,10 +126,7 @@ void NodeList::processNodeData(sockaddr* senderAddress, unsigned char* packetDat
|
||||||
switch (packetData[0]) {
|
switch (packetData[0]) {
|
||||||
case PACKET_TYPE_DOMAIN: {
|
case PACKET_TYPE_DOMAIN: {
|
||||||
// only process the DS if this is our current domain server
|
// only process the DS if this is our current domain server
|
||||||
sockaddr_in domainServerSocket = *(sockaddr_in*) senderAddress;
|
if (_domainIP == QHostAddress(senderAddress)) {
|
||||||
const char* domainSenderIP = inet_ntoa(domainServerSocket.sin_addr);
|
|
||||||
|
|
||||||
if (memcmp(domainSenderIP, _domainIP, strlen(domainSenderIP)) == 0) {
|
|
||||||
processDomainServerList(packetData, dataBytes);
|
processDomainServerList(packetData, dataBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,23 +274,33 @@ void NodeList::setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNo
|
||||||
_nodeTypesOfInterest[numNodeTypesOfInterest] = '\0';
|
_nodeTypesOfInterest[numNodeTypesOfInterest] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeList::sendDomainServerCheckIn() {
|
void NodeList::sendDomainServerCheckIn(const char* assignmentUUID) {
|
||||||
static bool printedDomainServerIP = false;
|
static bool printedDomainServerIP = false;
|
||||||
|
|
||||||
// Lookup the IP address of the domain server if we need to
|
// Lookup the IP address of the domain server if we need to
|
||||||
if (atoi(_domainIP) == 0) {
|
if (_domainIP.isNull()) {
|
||||||
printf("Looking up %s\n", _domainHostname);
|
qDebug("Looking up DS hostname %s.\n", _domainHostname.toStdString().c_str());
|
||||||
struct hostent* pHostInfo;
|
|
||||||
if ((pHostInfo = gethostbyname(_domainHostname)) != NULL) {
|
QHostInfo domainServerHostInfo = QHostInfo::fromName(_domainHostname);
|
||||||
sockaddr_in tempAddress;
|
|
||||||
memcpy(&tempAddress.sin_addr, pHostInfo->h_addr_list[0], pHostInfo->h_length);
|
for (int i = 0; i < domainServerHostInfo.addresses().size(); i++) {
|
||||||
strcpy(_domainIP, inet_ntoa(tempAddress.sin_addr));
|
if (domainServerHostInfo.addresses()[i].protocol() == QAbstractSocket::IPv4Protocol) {
|
||||||
qDebug("Domain Server: %s\n", _domainHostname);
|
_domainIP = domainServerHostInfo.addresses()[i];
|
||||||
} else {
|
|
||||||
qDebug("Failed domain server lookup\n");
|
qDebug("DS at %s is at %s\n", _domainHostname.toStdString().c_str(), _domainIP.toString().toStdString().c_str());
|
||||||
|
|
||||||
|
printedDomainServerIP = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we got here without a break out of the for loop then we failed to lookup the address
|
||||||
|
if (i == domainServerHostInfo.addresses().size() - 1) {
|
||||||
|
qDebug("Failed domain server lookup\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (!printedDomainServerIP) {
|
} else if (!printedDomainServerIP) {
|
||||||
qDebug("Domain Server IP: %s\n", _domainIP);
|
qDebug("Domain Server IP: %s\n", _domainIP.toString().toStdString().c_str());
|
||||||
printedDomainServerIP = true;
|
printedDomainServerIP = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,9 +313,9 @@ void NodeList::sendDomainServerCheckIn() {
|
||||||
|
|
||||||
const int IP_ADDRESS_BYTES = 4;
|
const int IP_ADDRESS_BYTES = 4;
|
||||||
|
|
||||||
// check in packet has header, node type, port, IP, node types of interest, null termination
|
// check in packet has header, optional UUID, node type, port, IP, node types of interest, null termination
|
||||||
int numPacketBytes = sizeof(PACKET_TYPE) + sizeof(PACKET_VERSION) + sizeof(NODE_TYPE) + sizeof(uint16_t) +
|
int numPacketBytes = sizeof(PACKET_TYPE) + sizeof(PACKET_VERSION) + sizeof(NODE_TYPE) +
|
||||||
IP_ADDRESS_BYTES + numBytesNodesOfInterest + sizeof(unsigned char);
|
NUM_BYTES_RFC4122_UUID + sizeof(uint16_t) + IP_ADDRESS_BYTES + numBytesNodesOfInterest + sizeof(unsigned char);
|
||||||
|
|
||||||
checkInPacket = new unsigned char[numPacketBytes];
|
checkInPacket = new unsigned char[numPacketBytes];
|
||||||
unsigned char* packetPosition = checkInPacket;
|
unsigned char* packetPosition = checkInPacket;
|
||||||
|
@ -313,7 +329,13 @@ void NodeList::sendDomainServerCheckIn() {
|
||||||
|
|
||||||
*(packetPosition++) = _ownerType;
|
*(packetPosition++) = _ownerType;
|
||||||
|
|
||||||
packetPosition += packSocket(checkInPacket + numHeaderBytes + sizeof(NODE_TYPE),
|
if (assignmentUUID) {
|
||||||
|
// if we've got an assignment UUID to send add that here
|
||||||
|
memcpy(packetPosition, assignmentUUID, NUM_BYTES_RFC4122_UUID);
|
||||||
|
packetPosition += NUM_BYTES_RFC4122_UUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
packetPosition += packSocket(checkInPacket + (packetPosition - checkInPacket),
|
||||||
getLocalAddress(),
|
getLocalAddress(),
|
||||||
htons(_nodeSocket.getListeningPort()));
|
htons(_nodeSocket.getListeningPort()));
|
||||||
|
|
||||||
|
@ -331,7 +353,7 @@ void NodeList::sendDomainServerCheckIn() {
|
||||||
checkInPacketSize = packetPosition - checkInPacket;
|
checkInPacketSize = packetPosition - checkInPacket;
|
||||||
}
|
}
|
||||||
|
|
||||||
_nodeSocket.send(_domainIP, DEFAULT_DOMAINSERVER_PORT, checkInPacket, checkInPacketSize);
|
_nodeSocket.send(_domainIP.toString().toStdString().c_str(), _domainPort, checkInPacket, checkInPacketSize);
|
||||||
|
|
||||||
// increment the count of un-replied check-ins
|
// increment the count of un-replied check-ins
|
||||||
_numNoReplyDomainCheckIns++;
|
_numNoReplyDomainCheckIns++;
|
||||||
|
@ -364,7 +386,7 @@ int NodeList::processDomainServerList(unsigned char* packetData, size_t dataByte
|
||||||
// if the public socket address is 0 then it's reachable at the same IP
|
// if the public socket address is 0 then it's reachable at the same IP
|
||||||
// as the domain server
|
// as the domain server
|
||||||
if (nodePublicSocket.sin_addr.s_addr == 0) {
|
if (nodePublicSocket.sin_addr.s_addr == 0) {
|
||||||
inet_aton(_domainIP, &nodePublicSocket.sin_addr);
|
nodePublicSocket.sin_addr.s_addr = htonl(_domainIP.toIPv4Address());
|
||||||
}
|
}
|
||||||
|
|
||||||
addOrUpdateNode((sockaddr*) &nodePublicSocket, (sockaddr*) &nodeLocalSocket, nodeType, nodeId);
|
addOrUpdateNode((sockaddr*) &nodePublicSocket, (sockaddr*) &nodeLocalSocket, nodeType, nodeId);
|
||||||
|
@ -376,9 +398,9 @@ int NodeList::processDomainServerList(unsigned char* packetData, size_t dataByte
|
||||||
return readNodes;
|
return readNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char GLOBAL_ASSIGNMENT_SERVER_HOSTNAME[] = "assignment.highfidelity.io";
|
const char LOCAL_ASSIGNMENT_SERVER_HOSTNAME[] = "localhost";
|
||||||
const sockaddr_in GLOBAL_ASSIGNMENT_SOCKET = socketForHostnameAndHostOrderPort(GLOBAL_ASSIGNMENT_SERVER_HOSTNAME,
|
const sockaddr_in DEFAULT_LOCAL_ASSIGNMENT_SOCKET = socketForHostnameAndHostOrderPort(LOCAL_ASSIGNMENT_SERVER_HOSTNAME,
|
||||||
ASSIGNMENT_SERVER_PORT);
|
DEFAULT_DOMAIN_SERVER_PORT);
|
||||||
void NodeList::sendAssignment(Assignment& assignment) {
|
void NodeList::sendAssignment(Assignment& assignment) {
|
||||||
unsigned char assignmentPacket[MAX_PACKET_SIZE];
|
unsigned char assignmentPacket[MAX_PACKET_SIZE];
|
||||||
|
|
||||||
|
@ -390,7 +412,7 @@ void NodeList::sendAssignment(Assignment& assignment) {
|
||||||
int numAssignmentBytes = assignment.packToBuffer(assignmentPacket + numHeaderBytes);
|
int numAssignmentBytes = assignment.packToBuffer(assignmentPacket + numHeaderBytes);
|
||||||
|
|
||||||
sockaddr* assignmentServerSocket = (_assignmentServerSocket == NULL)
|
sockaddr* assignmentServerSocket = (_assignmentServerSocket == NULL)
|
||||||
? (sockaddr*) &GLOBAL_ASSIGNMENT_SOCKET
|
? (sockaddr*) &DEFAULT_LOCAL_ASSIGNMENT_SOCKET
|
||||||
: _assignmentServerSocket;
|
: _assignmentServerSocket;
|
||||||
|
|
||||||
_nodeSocket.send(assignmentServerSocket, assignmentPacket, numHeaderBytes + numAssignmentBytes);
|
_nodeSocket.send(assignmentServerSocket, assignmentPacket, numHeaderBytes + numAssignmentBytes);
|
||||||
|
@ -555,8 +577,7 @@ void NodeList::loadData(QSettings *settings) {
|
||||||
QString domainServerHostname = settings->value(DOMAIN_SERVER_SETTING_KEY).toString();
|
QString domainServerHostname = settings->value(DOMAIN_SERVER_SETTING_KEY).toString();
|
||||||
|
|
||||||
if (domainServerHostname.size() > 0) {
|
if (domainServerHostname.size() > 0) {
|
||||||
memset(_domainHostname, 0, MAX_HOSTNAME_BYTES);
|
_domainHostname = domainServerHostname;
|
||||||
memcpy(_domainHostname, domainServerHostname.toLocal8Bit().constData(), domainServerHostname.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
settings->endGroup();
|
settings->endGroup();
|
||||||
|
@ -565,7 +586,7 @@ void NodeList::loadData(QSettings *settings) {
|
||||||
void NodeList::saveData(QSettings* settings) {
|
void NodeList::saveData(QSettings* settings) {
|
||||||
settings->beginGroup(DOMAIN_SERVER_SETTING_KEY);
|
settings->beginGroup(DOMAIN_SERVER_SETTING_KEY);
|
||||||
|
|
||||||
if (memcmp(_domainHostname, DEFAULT_DOMAIN_HOSTNAME, strlen(DEFAULT_DOMAIN_HOSTNAME)) != 0) {
|
if (_domainHostname != DEFAULT_DOMAIN_HOSTNAME) {
|
||||||
// the user is using a different hostname, store it
|
// the user is using a different hostname, store it
|
||||||
settings->setValue(DOMAIN_SERVER_SETTING_KEY, QVariant(_domainHostname));
|
settings->setValue(DOMAIN_SERVER_SETTING_KEY, QVariant(_domainHostname));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <QtNetwork/QHostAddress>
|
||||||
#include <QtCore/QSettings>
|
#include <QtCore/QSettings>
|
||||||
|
|
||||||
#include "Node.h"
|
#include "Node.h"
|
||||||
|
@ -36,9 +37,8 @@ extern const char SOLO_NODE_TYPES[2];
|
||||||
|
|
||||||
const int MAX_HOSTNAME_BYTES = 256;
|
const int MAX_HOSTNAME_BYTES = 256;
|
||||||
|
|
||||||
extern const char DEFAULT_DOMAIN_HOSTNAME[MAX_HOSTNAME_BYTES];
|
extern const QString DEFAULT_DOMAIN_HOSTNAME;
|
||||||
extern const char DEFAULT_DOMAIN_IP[INET_ADDRSTRLEN]; // IP Address will be re-set by lookup on startup
|
extern const unsigned short DEFAULT_DOMAIN_SERVER_PORT;
|
||||||
extern const int DEFAULT_DOMAINSERVER_PORT;
|
|
||||||
|
|
||||||
const int UNKNOWN_NODE_ID = 0;
|
const int UNKNOWN_NODE_ID = 0;
|
||||||
|
|
||||||
|
@ -65,15 +65,18 @@ public:
|
||||||
NodeListIterator begin() const;
|
NodeListIterator begin() const;
|
||||||
NodeListIterator end() const;
|
NodeListIterator end() const;
|
||||||
|
|
||||||
|
|
||||||
NODE_TYPE getOwnerType() const { return _ownerType; }
|
NODE_TYPE getOwnerType() const { return _ownerType; }
|
||||||
void setOwnerType(NODE_TYPE ownerType) { _ownerType = ownerType; }
|
void setOwnerType(NODE_TYPE ownerType) { _ownerType = ownerType; }
|
||||||
|
|
||||||
const char* getDomainHostname() const { return _domainHostname; }
|
const QString& getDomainHostname() const { return _domainHostname; }
|
||||||
void setDomainHostname(const char* domainHostname);
|
void setDomainHostname(const QString& domainHostname);
|
||||||
|
|
||||||
void setDomainIP(const char* domainIP);
|
const QHostAddress& getDomainIP() const { return _domainIP; }
|
||||||
void setDomainIPToLocalhost();
|
void setDomainIP(const QHostAddress& domainIP) { _domainIP = domainIP; }
|
||||||
|
void setDomainIPToLocalhost() { _domainIP = QHostAddress(INADDR_LOOPBACK); }
|
||||||
|
|
||||||
|
unsigned short getDomainPort() const { return _domainPort; }
|
||||||
|
void setDomainPort(unsigned short domainPort) { _domainPort = domainPort; }
|
||||||
|
|
||||||
uint16_t getLastNodeID() const { return _lastNodeID; }
|
uint16_t getLastNodeID() const { return _lastNodeID; }
|
||||||
void increaseNodeID() { (++_lastNodeID == UNKNOWN_NODE_ID) ? ++_lastNodeID : _lastNodeID; }
|
void increaseNodeID() { (++_lastNodeID == UNKNOWN_NODE_ID) ? ++_lastNodeID : _lastNodeID; }
|
||||||
|
@ -96,7 +99,7 @@ public:
|
||||||
|
|
||||||
void setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest);
|
void setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest);
|
||||||
|
|
||||||
void sendDomainServerCheckIn();
|
void sendDomainServerCheckIn(const char* assignmentUUID = NULL);
|
||||||
int processDomainServerList(unsigned char *packetData, size_t dataBytes);
|
int processDomainServerList(unsigned char *packetData, size_t dataBytes);
|
||||||
|
|
||||||
void setAssignmentServerSocket(sockaddr* serverSocket) { _assignmentServerSocket = serverSocket; }
|
void setAssignmentServerSocket(sockaddr* serverSocket) { _assignmentServerSocket = serverSocket; }
|
||||||
|
@ -140,8 +143,9 @@ private:
|
||||||
|
|
||||||
void addNodeToList(Node* newNode);
|
void addNodeToList(Node* newNode);
|
||||||
|
|
||||||
char _domainHostname[MAX_HOSTNAME_BYTES];
|
QString _domainHostname;
|
||||||
char _domainIP[INET_ADDRSTRLEN];
|
QHostAddress _domainIP;
|
||||||
|
unsigned short _domainPort;
|
||||||
Node** _nodeBuckets[MAX_NUM_NODES / NODES_PER_BUCKET];
|
Node** _nodeBuckets[MAX_NUM_NODES / NODES_PER_BUCKET];
|
||||||
int _numNodes;
|
int _numNodes;
|
||||||
UDPSocket _nodeSocket;
|
UDPSocket _nodeSocket;
|
||||||
|
|
|
@ -26,7 +26,7 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) {
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
case PACKET_TYPE_VOXEL_STATS:
|
case PACKET_TYPE_VOXEL_STATS:
|
||||||
return 2;
|
return 2;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,4 @@ const int MAX_PACKET_HEADER_BYTES = sizeof(PACKET_TYPE) + sizeof(PACKET_VERSION)
|
||||||
#define ADD_SCENE_COMMAND "add scene"
|
#define ADD_SCENE_COMMAND "add scene"
|
||||||
#define TEST_COMMAND "a message"
|
#define TEST_COMMAND "a message"
|
||||||
|
|
||||||
const unsigned short ASSIGNMENT_SERVER_PORT = 7007;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -275,7 +275,7 @@ int UDPSocket::send(sockaddr* destAddress, const void* data, size_t byteLength)
|
||||||
return sent_bytes;
|
return sent_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
int UDPSocket::send(char* destAddress, int destPort, const void* data, size_t byteLength) const {
|
int UDPSocket::send(const char* destAddress, int destPort, const void* data, size_t byteLength) const {
|
||||||
|
|
||||||
// change address and port on reusable global to passed variables
|
// change address and port on reusable global to passed variables
|
||||||
destSockaddr.sin_addr.s_addr = inet_addr(destAddress);
|
destSockaddr.sin_addr.s_addr = inet_addr(destAddress);
|
||||||
|
|
|
@ -31,7 +31,7 @@ public:
|
||||||
void setBlockingReceiveTimeoutInUsecs(int timeoutUsecs);
|
void setBlockingReceiveTimeoutInUsecs(int timeoutUsecs);
|
||||||
|
|
||||||
int send(sockaddr* destAddress, const void* data, size_t byteLength) const;
|
int send(sockaddr* destAddress, const void* data, size_t byteLength) const;
|
||||||
int send(char* destAddress, int destPort, const void* data, size_t byteLength) const;
|
int send(const char* destAddress, int destPort, const void* data, size_t byteLength) const;
|
||||||
|
|
||||||
bool receive(void* receivedData, ssize_t* receivedBytes) const;
|
bool receive(void* receivedData, ssize_t* receivedBytes) const;
|
||||||
bool receive(sockaddr* recvAddress, void* receivedData, ssize_t* receivedBytes) const;
|
bool receive(sockaddr* recvAddress, void* receivedData, ssize_t* receivedBytes) const;
|
||||||
|
|
|
@ -28,14 +28,17 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) :
|
||||||
_voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE];
|
_voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE];
|
||||||
_voxelPacketAt = _voxelPacket;
|
_voxelPacketAt = _voxelPacket;
|
||||||
resetVoxelPacket();
|
resetVoxelPacket();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelNodeData::initializeVoxelSendThread(VoxelServer* voxelServer) {
|
||||||
// Create voxel sending thread...
|
// Create voxel sending thread...
|
||||||
uint16_t nodeID = getOwningNode()->getNodeID();
|
uint16_t nodeID = getOwningNode()->getNodeID();
|
||||||
_voxelSendThread = new VoxelSendThread(nodeID);
|
_voxelSendThread = new VoxelSendThread(nodeID, voxelServer);
|
||||||
_voxelSendThread->initialize(true);
|
_voxelSendThread->initialize(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void VoxelNodeData::resetVoxelPacket() {
|
void VoxelNodeData::resetVoxelPacket() {
|
||||||
// If we're moving, and the client asked for low res, then we force monochrome, otherwise, use
|
// If we're moving, and the client asked for low res, then we force monochrome, otherwise, use
|
||||||
// the clients requested color state.
|
// the clients requested color state.
|
||||||
|
@ -57,8 +60,10 @@ void VoxelNodeData::writeToPacket(unsigned char* buffer, int bytes) {
|
||||||
VoxelNodeData::~VoxelNodeData() {
|
VoxelNodeData::~VoxelNodeData() {
|
||||||
delete[] _voxelPacket;
|
delete[] _voxelPacket;
|
||||||
|
|
||||||
_voxelSendThread->terminate();
|
if (_voxelSendThread) {
|
||||||
delete _voxelSendThread;
|
_voxelSendThread->terminate();
|
||||||
|
delete _voxelSendThread;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VoxelNodeData::updateCurrentViewFrustum() {
|
bool VoxelNodeData::updateCurrentViewFrustum() {
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <VoxelSceneStats.h>
|
#include <VoxelSceneStats.h>
|
||||||
|
|
||||||
class VoxelSendThread;
|
class VoxelSendThread;
|
||||||
|
class VoxelServer;
|
||||||
|
|
||||||
class VoxelNodeData : public AvatarData {
|
class VoxelNodeData : public AvatarData {
|
||||||
public:
|
public:
|
||||||
|
@ -65,6 +66,9 @@ public:
|
||||||
|
|
||||||
VoxelSceneStats stats;
|
VoxelSceneStats stats;
|
||||||
|
|
||||||
|
void initializeVoxelSendThread(VoxelServer* voxelServer);
|
||||||
|
bool isVoxelSendThreadInitalized() { return _voxelSendThread; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VoxelNodeData(const VoxelNodeData &);
|
VoxelNodeData(const VoxelNodeData &);
|
||||||
VoxelNodeData& operator= (const VoxelNodeData&);
|
VoxelNodeData& operator= (const VoxelNodeData&);
|
||||||
|
|
|
@ -16,10 +16,11 @@ extern EnvironmentData environmentData[3];
|
||||||
|
|
||||||
#include "VoxelSendThread.h"
|
#include "VoxelSendThread.h"
|
||||||
#include "VoxelServer.h"
|
#include "VoxelServer.h"
|
||||||
#include "VoxelServerState.h"
|
#include "VoxelServerConsts.h"
|
||||||
|
|
||||||
VoxelSendThread::VoxelSendThread(uint16_t nodeID) :
|
VoxelSendThread::VoxelSendThread(uint16_t nodeID, VoxelServer* myServer) :
|
||||||
_nodeID(nodeID) {
|
_nodeID(nodeID),
|
||||||
|
_myServer(myServer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VoxelSendThread::process() {
|
bool VoxelSendThread::process() {
|
||||||
|
@ -35,7 +36,7 @@ bool VoxelSendThread::process() {
|
||||||
// Sometimes the node data has not yet been linked, in which case we can't really do anything
|
// Sometimes the node data has not yet been linked, in which case we can't really do anything
|
||||||
if (nodeData) {
|
if (nodeData) {
|
||||||
bool viewFrustumChanged = nodeData->updateCurrentViewFrustum();
|
bool viewFrustumChanged = nodeData->updateCurrentViewFrustum();
|
||||||
if (::debugVoxelSending) {
|
if (_myServer->wantsDebugVoxelSending()) {
|
||||||
printf("nodeData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged));
|
printf("nodeData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged));
|
||||||
}
|
}
|
||||||
deepestLevelVoxelDistributor(node, nodeData, viewFrustumChanged);
|
deepestLevelVoxelDistributor(node, nodeData, viewFrustumChanged);
|
||||||
|
@ -47,7 +48,7 @@ bool VoxelSendThread::process() {
|
||||||
if (usecToSleep > 0) {
|
if (usecToSleep > 0) {
|
||||||
usleep(usecToSleep);
|
usleep(usecToSleep);
|
||||||
} else {
|
} else {
|
||||||
if (::debugVoxelSending) {
|
if (_myServer->wantsDebugVoxelSending()) {
|
||||||
std::cout << "Last send took too much time, not sleeping!\n";
|
std::cout << "Last send took too much time, not sleeping!\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,7 +95,7 @@ void VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int&
|
||||||
/// Version of voxel distributor that sends the deepest LOD level at once
|
/// Version of voxel distributor that sends the deepest LOD level at once
|
||||||
void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nodeData, bool viewFrustumChanged) {
|
void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nodeData, bool viewFrustumChanged) {
|
||||||
|
|
||||||
pthread_mutex_lock(&::treeLock);
|
_myServer->lockTree();
|
||||||
|
|
||||||
int truePacketsSent = 0;
|
int truePacketsSent = 0;
|
||||||
int trueBytesSent = 0;
|
int trueBytesSent = 0;
|
||||||
|
@ -113,7 +114,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
|
||||||
if (wantColor != nodeData->getCurrentPacketIsColor()) {
|
if (wantColor != nodeData->getCurrentPacketIsColor()) {
|
||||||
|
|
||||||
if (nodeData->isPacketWaiting()) {
|
if (nodeData->isPacketWaiting()) {
|
||||||
if (::debugVoxelSending) {
|
if (_myServer->wantsDebugVoxelSending()) {
|
||||||
printf("wantColor=%s --- SENDING PARTIAL PACKET! nodeData->getCurrentPacketIsColor()=%s\n",
|
printf("wantColor=%s --- SENDING PARTIAL PACKET! nodeData->getCurrentPacketIsColor()=%s\n",
|
||||||
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()));
|
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()));
|
||||||
}
|
}
|
||||||
|
@ -121,7 +122,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
|
||||||
handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
|
handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (::debugVoxelSending) {
|
if (_myServer->wantsDebugVoxelSending()) {
|
||||||
printf("wantColor=%s --- FIXING HEADER! nodeData->getCurrentPacketIsColor()=%s\n",
|
printf("wantColor=%s --- FIXING HEADER! nodeData->getCurrentPacketIsColor()=%s\n",
|
||||||
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()));
|
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()));
|
||||||
}
|
}
|
||||||
|
@ -129,7 +130,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (::debugVoxelSending) {
|
if (_myServer->wantsDebugVoxelSending()) {
|
||||||
printf("wantColor=%s getCurrentPacketIsColor()=%s, viewFrustumChanged=%s, getWantLowResMoving()=%s\n",
|
printf("wantColor=%s getCurrentPacketIsColor()=%s, viewFrustumChanged=%s, getWantLowResMoving()=%s\n",
|
||||||
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()),
|
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()),
|
||||||
debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->getWantLowResMoving()));
|
debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->getWantLowResMoving()));
|
||||||
|
@ -137,7 +138,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
|
||||||
|
|
||||||
const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL;
|
const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL;
|
||||||
|
|
||||||
if (::debugVoxelSending) {
|
if (_myServer->wantsDebugVoxelSending()) {
|
||||||
printf("deepestLevelVoxelDistributor() viewFrustumChanged=%s, nodeBag.isEmpty=%s, viewSent=%s\n",
|
printf("deepestLevelVoxelDistributor() viewFrustumChanged=%s, nodeBag.isEmpty=%s, viewSent=%s\n",
|
||||||
debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty()),
|
debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty()),
|
||||||
debug::valueOf(nodeData->getViewSent())
|
debug::valueOf(nodeData->getViewSent())
|
||||||
|
@ -148,7 +149,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
|
||||||
// the current view frustum for things to send.
|
// the current view frustum for things to send.
|
||||||
if (viewFrustumChanged || nodeData->nodeBag.isEmpty()) {
|
if (viewFrustumChanged || nodeData->nodeBag.isEmpty()) {
|
||||||
uint64_t now = usecTimestampNow();
|
uint64_t now = usecTimestampNow();
|
||||||
if (::debugVoxelSending) {
|
if (_myServer->wantsDebugVoxelSending()) {
|
||||||
printf("(viewFrustumChanged=%s || nodeData->nodeBag.isEmpty() =%s)...\n",
|
printf("(viewFrustumChanged=%s || nodeData->nodeBag.isEmpty() =%s)...\n",
|
||||||
debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty()));
|
debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty()));
|
||||||
if (nodeData->getLastTimeBagEmpty() > 0) {
|
if (nodeData->getLastTimeBagEmpty() > 0) {
|
||||||
|
@ -166,7 +167,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
|
||||||
|
|
||||||
// if our view has changed, we need to reset these things...
|
// if our view has changed, we need to reset these things...
|
||||||
if (viewFrustumChanged) {
|
if (viewFrustumChanged) {
|
||||||
if (::dumpVoxelsOnMove) {
|
if (_myServer->wantDumpVoxelsOnMove()) {
|
||||||
nodeData->nodeBag.deleteAll();
|
nodeData->nodeBag.deleteAll();
|
||||||
}
|
}
|
||||||
nodeData->map.erase();
|
nodeData->map.erase();
|
||||||
|
@ -180,7 +181,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
|
||||||
|
|
||||||
nodeData->stats.sceneCompleted();
|
nodeData->stats.sceneCompleted();
|
||||||
|
|
||||||
if (::displayVoxelStats) {
|
if (_myServer->wantDisplayVoxelStats()) {
|
||||||
nodeData->stats.printDebugDetails();
|
nodeData->stats.printDebugDetails();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,10 +192,10 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
|
||||||
if (isFullScene) {
|
if (isFullScene) {
|
||||||
nodeData->nodeBag.deleteAll();
|
nodeData->nodeBag.deleteAll();
|
||||||
}
|
}
|
||||||
nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, ::serverTree.rootNode, ::jurisdiction);
|
nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, _myServer->getServerTree().rootNode, _myServer->getJurisdiction());
|
||||||
|
|
||||||
// This is the start of "resending" the scene.
|
// This is the start of "resending" the scene.
|
||||||
nodeData->nodeBag.insert(serverTree.rootNode);
|
nodeData->nodeBag.insert(_myServer->getServerTree().rootNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have something in our nodeBag, then turn them into packets and send them out...
|
// If we have something in our nodeBag, then turn them into packets and send them out...
|
||||||
|
@ -203,8 +204,8 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
|
||||||
int packetsSentThisInterval = 0;
|
int packetsSentThisInterval = 0;
|
||||||
uint64_t start = usecTimestampNow();
|
uint64_t start = usecTimestampNow();
|
||||||
|
|
||||||
bool shouldSendEnvironments = ::sendEnvironments && shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS);
|
bool shouldSendEnvironments = _myServer->wantSendEnvironments() && shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS);
|
||||||
while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - (shouldSendEnvironments ? 1 : 0)) {
|
while (packetsSentThisInterval < _myServer->getPacketsPerClientPerInterval() - (shouldSendEnvironments ? 1 : 0)) {
|
||||||
// Check to see if we're taking too long, and if so bail early...
|
// Check to see if we're taking too long, and if so bail early...
|
||||||
uint64_t now = usecTimestampNow();
|
uint64_t now = usecTimestampNow();
|
||||||
long elapsedUsec = (now - start);
|
long elapsedUsec = (now - start);
|
||||||
|
@ -212,7 +213,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
|
||||||
long usecRemaining = (VOXEL_SEND_INTERVAL_USECS - elapsedUsec);
|
long usecRemaining = (VOXEL_SEND_INTERVAL_USECS - elapsedUsec);
|
||||||
|
|
||||||
if (elapsedUsecPerPacket + SENDING_TIME_TO_SPARE > usecRemaining) {
|
if (elapsedUsecPerPacket + SENDING_TIME_TO_SPARE > usecRemaining) {
|
||||||
if (::debugVoxelSending) {
|
if (_myServer->wantsDebugVoxelSending()) {
|
||||||
printf("packetLoop() usecRemaining=%ld bailing early took %ld usecs to generate %d bytes in %d packets (%ld usec avg), %d nodes still to send\n",
|
printf("packetLoop() usecRemaining=%ld bailing early took %ld usecs to generate %d bytes in %d packets (%ld usec avg), %d nodes still to send\n",
|
||||||
usecRemaining, elapsedUsec, trueBytesSent, truePacketsSent, elapsedUsecPerPacket,
|
usecRemaining, elapsedUsec, trueBytesSent, truePacketsSent, elapsedUsecPerPacket,
|
||||||
nodeData->nodeBag.count());
|
nodeData->nodeBag.count());
|
||||||
|
@ -234,10 +235,10 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
|
||||||
WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum,
|
WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum,
|
||||||
wantOcclusionCulling, coverageMap, boundaryLevelAdjust,
|
wantOcclusionCulling, coverageMap, boundaryLevelAdjust,
|
||||||
nodeData->getLastTimeBagEmpty(),
|
nodeData->getLastTimeBagEmpty(),
|
||||||
isFullScene, &nodeData->stats, ::jurisdiction);
|
isFullScene, &nodeData->stats, _myServer->getJurisdiction());
|
||||||
|
|
||||||
nodeData->stats.encodeStarted();
|
nodeData->stats.encodeStarted();
|
||||||
bytesWritten = serverTree.encodeTreeBitstream(subTree, _tempOutputBuffer, MAX_VOXEL_PACKET_SIZE - 1,
|
bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, _tempOutputBuffer, MAX_VOXEL_PACKET_SIZE - 1,
|
||||||
nodeData->nodeBag, params);
|
nodeData->nodeBag, params);
|
||||||
nodeData->stats.encodeStopped();
|
nodeData->stats.encodeStopped();
|
||||||
|
|
||||||
|
@ -254,17 +255,17 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
|
||||||
handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
|
handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
|
||||||
nodeData->resetVoxelPacket();
|
nodeData->resetVoxelPacket();
|
||||||
}
|
}
|
||||||
packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; // done for now, no nodes left
|
packetsSentThisInterval = _myServer->getPacketsPerClientPerInterval(); // done for now, no nodes left
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// send the environment packet
|
// send the environment packet
|
||||||
if (shouldSendEnvironments) {
|
if (shouldSendEnvironments) {
|
||||||
int numBytesPacketHeader = populateTypeAndVersion(_tempOutputBuffer, PACKET_TYPE_ENVIRONMENT_DATA);
|
int numBytesPacketHeader = populateTypeAndVersion(_tempOutputBuffer, PACKET_TYPE_ENVIRONMENT_DATA);
|
||||||
int envPacketLength = numBytesPacketHeader;
|
int envPacketLength = numBytesPacketHeader;
|
||||||
int environmentsToSend = ::sendMinimalEnvironment ? 1 : sizeof(environmentData) / sizeof(EnvironmentData);
|
int environmentsToSend = _myServer->getSendMinimalEnvironment() ? 1 : _myServer->getEnvironmentDataCount();
|
||||||
|
|
||||||
for (int i = 0; i < environmentsToSend; i++) {
|
for (int i = 0; i < environmentsToSend; i++) {
|
||||||
envPacketLength += environmentData[i].getBroadcastData(_tempOutputBuffer + envPacketLength);
|
envPacketLength += _myServer->getEnvironmentData(i)->getBroadcastData(_tempOutputBuffer + envPacketLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), _tempOutputBuffer, envPacketLength);
|
NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), _tempOutputBuffer, envPacketLength);
|
||||||
|
@ -283,7 +284,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
|
||||||
printf("WARNING! packetLoop() took %d milliseconds to generate %d bytes in %d packets, %d nodes still to send\n",
|
printf("WARNING! packetLoop() took %d milliseconds to generate %d bytes in %d packets, %d nodes still to send\n",
|
||||||
elapsedmsec, trueBytesSent, truePacketsSent, nodeData->nodeBag.count());
|
elapsedmsec, trueBytesSent, truePacketsSent, nodeData->nodeBag.count());
|
||||||
}
|
}
|
||||||
} else if (::debugVoxelSending) {
|
} else if (_myServer->wantsDebugVoxelSending()) {
|
||||||
printf("packetLoop() took %d milliseconds to generate %d bytes in %d packets, %d nodes still to send\n",
|
printf("packetLoop() took %d milliseconds to generate %d bytes in %d packets, %d nodes still to send\n",
|
||||||
elapsedmsec, trueBytesSent, truePacketsSent, nodeData->nodeBag.count());
|
elapsedmsec, trueBytesSent, truePacketsSent, nodeData->nodeBag.count());
|
||||||
}
|
}
|
||||||
|
@ -293,7 +294,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
|
||||||
if (nodeData->nodeBag.isEmpty()) {
|
if (nodeData->nodeBag.isEmpty()) {
|
||||||
nodeData->updateLastKnownViewFrustum();
|
nodeData->updateLastKnownViewFrustum();
|
||||||
nodeData->setViewSent(true);
|
nodeData->setViewSent(true);
|
||||||
if (::debugVoxelSending) {
|
if (_myServer->wantsDebugVoxelSending()) {
|
||||||
nodeData->map.printStats();
|
nodeData->map.printStats();
|
||||||
}
|
}
|
||||||
nodeData->map.erase(); // It would be nice if we could save this, and only reset it when the view frustum changes
|
nodeData->map.erase(); // It would be nice if we could save this, and only reset it when the view frustum changes
|
||||||
|
@ -301,6 +302,6 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
|
||||||
|
|
||||||
} // end if bag wasn't empty, and so we sent stuff...
|
} // end if bag wasn't empty, and so we sent stuff...
|
||||||
|
|
||||||
pthread_mutex_unlock(&::treeLock);
|
_myServer->unlockTree();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,17 +16,19 @@
|
||||||
#include <VoxelTree.h>
|
#include <VoxelTree.h>
|
||||||
#include <VoxelNodeBag.h>
|
#include <VoxelNodeBag.h>
|
||||||
#include "VoxelNodeData.h"
|
#include "VoxelNodeData.h"
|
||||||
|
#include "VoxelServer.h"
|
||||||
|
|
||||||
/// Threaded processor for sending voxel packets to a single client
|
/// Threaded processor for sending voxel packets to a single client
|
||||||
class VoxelSendThread : public virtual GenericThread {
|
class VoxelSendThread : public virtual GenericThread {
|
||||||
public:
|
public:
|
||||||
VoxelSendThread(uint16_t nodeID);
|
VoxelSendThread(uint16_t nodeID, VoxelServer* myServer);
|
||||||
protected:
|
protected:
|
||||||
/// Implements generic processing behavior for this thread.
|
/// Implements generic processing behavior for this thread.
|
||||||
virtual bool process();
|
virtual bool process();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint16_t _nodeID;
|
uint16_t _nodeID;
|
||||||
|
VoxelServer* _myServer;
|
||||||
|
|
||||||
void handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent);
|
void handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent);
|
||||||
void deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nodeData, bool viewFrustumChanged);
|
void deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nodeData, bool viewFrustumChanged);
|
||||||
|
|
|
@ -11,10 +11,13 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
#include <OctalCode.h>
|
#include <OctalCode.h>
|
||||||
#include <NodeList.h>
|
#include <NodeList.h>
|
||||||
#include <NodeTypes.h>
|
#include <NodeTypes.h>
|
||||||
#include <EnvironmentData.h>
|
|
||||||
#include <VoxelTree.h>
|
#include <VoxelTree.h>
|
||||||
#include "VoxelNodeData.h"
|
#include "VoxelNodeData.h"
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
@ -23,11 +26,6 @@
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
#include <JurisdictionSender.h>
|
#include <JurisdictionSender.h>
|
||||||
|
|
||||||
#include "NodeWatcher.h"
|
|
||||||
#include "VoxelPersistThread.h"
|
|
||||||
#include "VoxelSendThread.h"
|
|
||||||
#include "VoxelServerPacketProcessor.h"
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "Syssocket.h"
|
#include "Syssocket.h"
|
||||||
#include "Systime.h"
|
#include "Systime.h"
|
||||||
|
@ -38,34 +36,10 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "VoxelServer.h"
|
#include "VoxelServer.h"
|
||||||
#include "VoxelServerState.h"
|
#include "VoxelServerConsts.h"
|
||||||
|
|
||||||
const char* LOCAL_VOXELS_PERSIST_FILE = "resources/voxels.svo";
|
const char* LOCAL_VOXELS_PERSIST_FILE = "resources/voxels.svo";
|
||||||
const char* VOXELS_PERSIST_FILE = "/etc/highfidelity/voxel-server/resources/voxels.svo";
|
const char* VOXELS_PERSIST_FILE = "/etc/highfidelity/voxel-server/resources/voxels.svo";
|
||||||
char voxelPersistFilename[MAX_FILENAME_LENGTH];
|
|
||||||
int PACKETS_PER_CLIENT_PER_INTERVAL = 10;
|
|
||||||
VoxelTree serverTree(true); // this IS a reaveraging tree
|
|
||||||
bool wantVoxelPersist = true;
|
|
||||||
bool wantLocalDomain = false;
|
|
||||||
bool debugVoxelSending = false;
|
|
||||||
bool shouldShowAnimationDebug = false;
|
|
||||||
bool displayVoxelStats = false;
|
|
||||||
bool debugVoxelReceiving = false;
|
|
||||||
bool sendEnvironments = true;
|
|
||||||
bool sendMinimalEnvironment = false;
|
|
||||||
bool dumpVoxelsOnMove = false;
|
|
||||||
EnvironmentData environmentData[3];
|
|
||||||
int receivedPacketCount = 0;
|
|
||||||
JurisdictionMap* jurisdiction = NULL;
|
|
||||||
JurisdictionSender* jurisdictionSender = NULL;
|
|
||||||
VoxelServerPacketProcessor* voxelServerPacketProcessor = NULL;
|
|
||||||
VoxelPersistThread* voxelPersistThread = NULL;
|
|
||||||
pthread_mutex_t treeLock;
|
|
||||||
NodeWatcher nodeWatcher; // used to cleanup AGENT data when agents are killed
|
|
||||||
|
|
||||||
int VoxelServer::_argc = 0;
|
|
||||||
const char** VoxelServer::_argv = NULL;
|
|
||||||
bool VoxelServer::_dontKillOnMissingDomain = false;
|
|
||||||
|
|
||||||
void attachVoxelNodeDataToNode(Node* newNode) {
|
void attachVoxelNodeDataToNode(Node* newNode) {
|
||||||
if (newNode->getLinkedData() == NULL) {
|
if (newNode->getLinkedData() == NULL) {
|
||||||
|
@ -73,19 +47,134 @@ void attachVoxelNodeDataToNode(Node* newNode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VoxelServer::VoxelServer(Assignment::Command command, Assignment::Location location) :
|
||||||
|
Assignment(command, Assignment::VoxelServerType, location),
|
||||||
|
_serverTree(true) {
|
||||||
|
_argc = 0;
|
||||||
|
_argv = NULL;
|
||||||
|
_dontKillOnMissingDomain = false;
|
||||||
|
|
||||||
|
_packetsPerClientPerInterval = 10;
|
||||||
|
_wantVoxelPersist = true;
|
||||||
|
_wantLocalDomain = false;
|
||||||
|
_debugVoxelSending = false;
|
||||||
|
_shouldShowAnimationDebug = false;
|
||||||
|
_displayVoxelStats = false;
|
||||||
|
_debugVoxelReceiving = false;
|
||||||
|
_sendEnvironments = true;
|
||||||
|
_sendMinimalEnvironment = false;
|
||||||
|
_dumpVoxelsOnMove = false;
|
||||||
|
_jurisdiction = NULL;
|
||||||
|
_jurisdictionSender = NULL;
|
||||||
|
_voxelServerPacketProcessor = NULL;
|
||||||
|
_voxelPersistThread = NULL;
|
||||||
|
_parsedArgV = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
VoxelServer::VoxelServer(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes),
|
||||||
|
_serverTree(true) {
|
||||||
|
_argc = 0;
|
||||||
|
_argv = NULL;
|
||||||
|
_dontKillOnMissingDomain = false;
|
||||||
|
|
||||||
|
_packetsPerClientPerInterval = 10;
|
||||||
|
_wantVoxelPersist = true;
|
||||||
|
_wantLocalDomain = false;
|
||||||
|
_debugVoxelSending = false;
|
||||||
|
_shouldShowAnimationDebug = false;
|
||||||
|
_displayVoxelStats = false;
|
||||||
|
_debugVoxelReceiving = false;
|
||||||
|
_sendEnvironments = true;
|
||||||
|
_sendMinimalEnvironment = false;
|
||||||
|
_dumpVoxelsOnMove = false;
|
||||||
|
_jurisdiction = NULL;
|
||||||
|
_jurisdictionSender = NULL;
|
||||||
|
_voxelServerPacketProcessor = NULL;
|
||||||
|
_voxelPersistThread = NULL;
|
||||||
|
_parsedArgV = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
VoxelServer::~VoxelServer() {
|
||||||
|
if (_parsedArgV) {
|
||||||
|
for (int i = 0; i < _argc; i++) {
|
||||||
|
delete[] _parsedArgV[i];
|
||||||
|
}
|
||||||
|
delete[] _parsedArgV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void VoxelServer::setArguments(int argc, char** argv) {
|
void VoxelServer::setArguments(int argc, char** argv) {
|
||||||
_argc = argc;
|
_argc = argc;
|
||||||
_argv = const_cast<const char**>(argv);
|
_argv = const_cast<const char**>(argv);
|
||||||
|
|
||||||
|
qDebug("VoxelServer::setArguments()\n");
|
||||||
|
for (int i = 0; i < _argc; i++) {
|
||||||
|
qDebug("_argv[%d]=%s\n", i, _argv[i]);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelServer::setupDomainAndPort(const char* domain, int port) {
|
void VoxelServer::parsePayload() {
|
||||||
|
|
||||||
|
if (getNumPayloadBytes() > 0) {
|
||||||
|
QString multiConfig((const char*)getPayload());
|
||||||
|
QStringList multiConfigList = multiConfig.split(";");
|
||||||
|
|
||||||
|
// There there are multiple configs, then this instance will run the first
|
||||||
|
// config, and launch Assignment requests for the additional configs.
|
||||||
|
if (multiConfigList.size() > 1) {
|
||||||
|
qDebug("Voxel Server received assignment for multiple Configs... config count=%d\n", multiConfigList.size());
|
||||||
|
|
||||||
|
// skip 0 - that's the one we'll run
|
||||||
|
for (int i = 1; i < multiConfigList.size(); i++) {
|
||||||
|
QString config = multiConfigList.at(i);
|
||||||
|
|
||||||
|
qDebug(" config[%d]=%s\n", i, config.toLocal8Bit().constData());
|
||||||
|
|
||||||
|
Assignment voxelServerAssignment(Assignment::CreateCommand,
|
||||||
|
Assignment::VoxelServerType,
|
||||||
|
getLocation()); // use same location as we were created in.
|
||||||
|
|
||||||
|
int payloadLength = config.length() + sizeof(char);
|
||||||
|
voxelServerAssignment.setPayload((uchar*)config.toLocal8Bit().constData(), payloadLength);
|
||||||
|
|
||||||
|
qDebug("Requesting additional Voxel Server assignment to handle config %d\n", i);
|
||||||
|
NodeList::getInstance()->sendAssignment(voxelServerAssignment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, parse the first config
|
||||||
|
QString config = multiConfigList.at(0);
|
||||||
|
QStringList configList = config.split(" ");
|
||||||
|
|
||||||
|
int argCount = configList.size() + 1;
|
||||||
|
|
||||||
|
qDebug("VoxelServer::parsePayload()... argCount=%d\n",argCount);
|
||||||
|
|
||||||
|
_parsedArgV = new char*[argCount];
|
||||||
|
const char* dummy = "config-from-payload";
|
||||||
|
_parsedArgV[0] = new char[strlen(dummy) + sizeof(char)];
|
||||||
|
strcpy(_parsedArgV[0], dummy);
|
||||||
|
|
||||||
|
for (int i = 1; i < argCount; i++) {
|
||||||
|
QString configItem = configList.at(i-1);
|
||||||
|
_parsedArgV[i] = new char[configItem.length() + sizeof(char)];
|
||||||
|
strcpy(_parsedArgV[i], configItem.toLocal8Bit().constData());
|
||||||
|
qDebug("VoxelServer::parsePayload()... _parsedArgV[%d]=%s\n", i, _parsedArgV[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
setArguments(argCount, _parsedArgV);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoxelServer::setupStandAlone(const char* domain, int port) {
|
||||||
NodeList::createInstance(NODE_TYPE_VOXEL_SERVER, port);
|
NodeList::createInstance(NODE_TYPE_VOXEL_SERVER, port);
|
||||||
|
|
||||||
// Handle Local Domain testing with the --local command line
|
// Handle Local Domain testing with the --local command line
|
||||||
const char* local = "--local";
|
const char* local = "--local";
|
||||||
::wantLocalDomain = strcmp(domain, local) == 0;
|
_wantLocalDomain = strcmp(domain, local) == 0;
|
||||||
if (::wantLocalDomain) {
|
if (_wantLocalDomain) {
|
||||||
printf("Local Domain MODE!\n");
|
qDebug("Local Domain MODE!\n");
|
||||||
NodeList::getInstance()->setDomainIPToLocalhost();
|
NodeList::getInstance()->setDomainIPToLocalhost();
|
||||||
} else {
|
} else {
|
||||||
if (domain) {
|
if (domain) {
|
||||||
|
@ -99,54 +188,60 @@ void VoxelServer::setupDomainAndPort(const char* domain, int port) {
|
||||||
|
|
||||||
//int main(int argc, const char * argv[]) {
|
//int main(int argc, const char * argv[]) {
|
||||||
void VoxelServer::run() {
|
void VoxelServer::run() {
|
||||||
pthread_mutex_init(&::treeLock, NULL);
|
|
||||||
|
// 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(sharedMessageHandler);
|
qInstallMessageHandler(sharedMessageHandler);
|
||||||
|
|
||||||
const char* JURISDICTION_FILE = "--jurisdictionFile";
|
const char* JURISDICTION_FILE = "--jurisdictionFile";
|
||||||
const char* jurisdictionFile = getCmdOption(_argc, _argv, JURISDICTION_FILE);
|
const char* jurisdictionFile = getCmdOption(_argc, _argv, JURISDICTION_FILE);
|
||||||
if (jurisdictionFile) {
|
if (jurisdictionFile) {
|
||||||
printf("jurisdictionFile=%s\n", jurisdictionFile);
|
qDebug("jurisdictionFile=%s\n", jurisdictionFile);
|
||||||
|
|
||||||
printf("about to readFromFile().... jurisdictionFile=%s\n", jurisdictionFile);
|
qDebug("about to readFromFile().... jurisdictionFile=%s\n", jurisdictionFile);
|
||||||
jurisdiction = new JurisdictionMap(jurisdictionFile);
|
_jurisdiction = new JurisdictionMap(jurisdictionFile);
|
||||||
printf("after readFromFile().... jurisdictionFile=%s\n", jurisdictionFile);
|
qDebug("after readFromFile().... jurisdictionFile=%s\n", jurisdictionFile);
|
||||||
} else {
|
} else {
|
||||||
const char* JURISDICTION_ROOT = "--jurisdictionRoot";
|
const char* JURISDICTION_ROOT = "--jurisdictionRoot";
|
||||||
const char* jurisdictionRoot = getCmdOption(_argc, _argv, JURISDICTION_ROOT);
|
const char* jurisdictionRoot = getCmdOption(_argc, _argv, JURISDICTION_ROOT);
|
||||||
if (jurisdictionRoot) {
|
if (jurisdictionRoot) {
|
||||||
printf("jurisdictionRoot=%s\n", jurisdictionRoot);
|
qDebug("jurisdictionRoot=%s\n", jurisdictionRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* JURISDICTION_ENDNODES = "--jurisdictionEndNodes";
|
const char* JURISDICTION_ENDNODES = "--jurisdictionEndNodes";
|
||||||
const char* jurisdictionEndNodes = getCmdOption(_argc, _argv, JURISDICTION_ENDNODES);
|
const char* jurisdictionEndNodes = getCmdOption(_argc, _argv, JURISDICTION_ENDNODES);
|
||||||
if (jurisdictionEndNodes) {
|
if (jurisdictionEndNodes) {
|
||||||
printf("jurisdictionEndNodes=%s\n", jurisdictionEndNodes);
|
qDebug("jurisdictionEndNodes=%s\n", jurisdictionEndNodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jurisdictionRoot || jurisdictionEndNodes) {
|
if (jurisdictionRoot || jurisdictionEndNodes) {
|
||||||
::jurisdiction = new JurisdictionMap(jurisdictionRoot, jurisdictionEndNodes);
|
_jurisdiction = new JurisdictionMap(jurisdictionRoot, jurisdictionEndNodes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// should we send environments? Default is yes, but this command line suppresses sending
|
// should we send environments? Default is yes, but this command line suppresses sending
|
||||||
const char* DUMP_VOXELS_ON_MOVE = "--dumpVoxelsOnMove";
|
const char* DUMP_VOXELS_ON_MOVE = "--dumpVoxelsOnMove";
|
||||||
::dumpVoxelsOnMove = cmdOptionExists(_argc, _argv, DUMP_VOXELS_ON_MOVE);
|
_dumpVoxelsOnMove = cmdOptionExists(_argc, _argv, DUMP_VOXELS_ON_MOVE);
|
||||||
printf("dumpVoxelsOnMove=%s\n", debug::valueOf(::dumpVoxelsOnMove));
|
qDebug("dumpVoxelsOnMove=%s\n", debug::valueOf(_dumpVoxelsOnMove));
|
||||||
|
|
||||||
// should we send environments? Default is yes, but this command line suppresses sending
|
// should we send environments? Default is yes, but this command line suppresses sending
|
||||||
const char* DONT_SEND_ENVIRONMENTS = "--dontSendEnvironments";
|
const char* DONT_SEND_ENVIRONMENTS = "--dontSendEnvironments";
|
||||||
bool dontSendEnvironments = getCmdOption(_argc, _argv, DONT_SEND_ENVIRONMENTS);
|
bool dontSendEnvironments = getCmdOption(_argc, _argv, DONT_SEND_ENVIRONMENTS);
|
||||||
if (dontSendEnvironments) {
|
if (dontSendEnvironments) {
|
||||||
printf("Sending environments suppressed...\n");
|
qDebug("Sending environments suppressed...\n");
|
||||||
::sendEnvironments = false;
|
_sendEnvironments = false;
|
||||||
} else {
|
} else {
|
||||||
// should we send environments? Default is yes, but this command line suppresses sending
|
// should we send environments? Default is yes, but this command line suppresses sending
|
||||||
const char* MINIMAL_ENVIRONMENT = "--MinimalEnvironment";
|
const char* MINIMAL_ENVIRONMENT = "--MinimalEnvironment";
|
||||||
::sendMinimalEnvironment = getCmdOption(_argc, _argv, MINIMAL_ENVIRONMENT);
|
_sendMinimalEnvironment = getCmdOption(_argc, _argv, MINIMAL_ENVIRONMENT);
|
||||||
printf("Using Minimal Environment=%s\n", debug::valueOf(::sendMinimalEnvironment));
|
qDebug("Using Minimal Environment=%s\n", debug::valueOf(_sendMinimalEnvironment));
|
||||||
}
|
}
|
||||||
printf("Sending environments=%s\n", debug::valueOf(::sendEnvironments));
|
qDebug("Sending environments=%s\n", debug::valueOf(_sendEnvironments));
|
||||||
|
|
||||||
NodeList* nodeList = NodeList::getInstance();
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
nodeList->setOwnerType(NODE_TYPE_VOXEL_SERVER);
|
nodeList->setOwnerType(NODE_TYPE_VOXEL_SERVER);
|
||||||
|
@ -154,72 +249,72 @@ void VoxelServer::run() {
|
||||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||||
|
|
||||||
// tell our NodeList about our desire to get notifications
|
// tell our NodeList about our desire to get notifications
|
||||||
nodeList->addHook(&nodeWatcher);
|
nodeList->addHook(&_nodeWatcher);
|
||||||
nodeList->linkedDataCreateCallback = &attachVoxelNodeDataToNode;
|
nodeList->linkedDataCreateCallback = &attachVoxelNodeDataToNode;
|
||||||
|
|
||||||
nodeList->startSilentNodeRemovalThread();
|
nodeList->startSilentNodeRemovalThread();
|
||||||
srand((unsigned)time(0));
|
srand((unsigned)time(0));
|
||||||
|
|
||||||
const char* DISPLAY_VOXEL_STATS = "--displayVoxelStats";
|
const char* DISPLAY_VOXEL_STATS = "--displayVoxelStats";
|
||||||
::displayVoxelStats = getCmdOption(_argc, _argv, DISPLAY_VOXEL_STATS);
|
_displayVoxelStats = getCmdOption(_argc, _argv, DISPLAY_VOXEL_STATS);
|
||||||
printf("displayVoxelStats=%s\n", debug::valueOf(::displayVoxelStats));
|
qDebug("displayVoxelStats=%s\n", debug::valueOf(_displayVoxelStats));
|
||||||
|
|
||||||
const char* DEBUG_VOXEL_SENDING = "--debugVoxelSending";
|
const char* DEBUG_VOXEL_SENDING = "--debugVoxelSending";
|
||||||
::debugVoxelSending = getCmdOption(_argc, _argv, DEBUG_VOXEL_SENDING);
|
_debugVoxelSending = getCmdOption(_argc, _argv, DEBUG_VOXEL_SENDING);
|
||||||
printf("debugVoxelSending=%s\n", debug::valueOf(::debugVoxelSending));
|
qDebug("debugVoxelSending=%s\n", debug::valueOf(_debugVoxelSending));
|
||||||
|
|
||||||
const char* DEBUG_VOXEL_RECEIVING = "--debugVoxelReceiving";
|
const char* DEBUG_VOXEL_RECEIVING = "--debugVoxelReceiving";
|
||||||
::debugVoxelReceiving = getCmdOption(_argc, _argv, DEBUG_VOXEL_RECEIVING);
|
_debugVoxelReceiving = getCmdOption(_argc, _argv, DEBUG_VOXEL_RECEIVING);
|
||||||
printf("debugVoxelReceiving=%s\n", debug::valueOf(::debugVoxelReceiving));
|
qDebug("debugVoxelReceiving=%s\n", debug::valueOf(_debugVoxelReceiving));
|
||||||
|
|
||||||
const char* WANT_ANIMATION_DEBUG = "--shouldShowAnimationDebug";
|
const char* WANT_ANIMATION_DEBUG = "--shouldShowAnimationDebug";
|
||||||
::shouldShowAnimationDebug = getCmdOption(_argc, _argv, WANT_ANIMATION_DEBUG);
|
_shouldShowAnimationDebug = getCmdOption(_argc, _argv, WANT_ANIMATION_DEBUG);
|
||||||
printf("shouldShowAnimationDebug=%s\n", debug::valueOf(::shouldShowAnimationDebug));
|
qDebug("shouldShowAnimationDebug=%s\n", debug::valueOf(_shouldShowAnimationDebug));
|
||||||
|
|
||||||
// By default we will voxel persist, if you want to disable this, then pass in this parameter
|
// By default we will voxel persist, if you want to disable this, then pass in this parameter
|
||||||
const char* NO_VOXEL_PERSIST = "--NoVoxelPersist";
|
const char* NO_VOXEL_PERSIST = "--NoVoxelPersist";
|
||||||
if ( getCmdOption(_argc, _argv, NO_VOXEL_PERSIST)) {
|
if (getCmdOption(_argc, _argv, NO_VOXEL_PERSIST)) {
|
||||||
::wantVoxelPersist = false;
|
_wantVoxelPersist = false;
|
||||||
}
|
}
|
||||||
printf("wantVoxelPersist=%s\n", debug::valueOf(::wantVoxelPersist));
|
qDebug("wantVoxelPersist=%s\n", debug::valueOf(_wantVoxelPersist));
|
||||||
|
|
||||||
// if we want Voxel Persistence, load the local file now...
|
// if we want Voxel Persistence, load the local file now...
|
||||||
bool persistantFileRead = false;
|
bool persistantFileRead = false;
|
||||||
if (::wantVoxelPersist) {
|
if (_wantVoxelPersist) {
|
||||||
|
|
||||||
// Check to see if the user passed in a command line option for setting packet send rate
|
// 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* VOXELS_PERSIST_FILENAME = "--voxelsPersistFilename";
|
||||||
const char* voxelsPersistFilenameParameter = getCmdOption(_argc, _argv, VOXELS_PERSIST_FILENAME);
|
const char* voxelsPersistFilenameParameter = getCmdOption(_argc, _argv, VOXELS_PERSIST_FILENAME);
|
||||||
if (voxelsPersistFilenameParameter) {
|
if (voxelsPersistFilenameParameter) {
|
||||||
strcpy(voxelPersistFilename, voxelsPersistFilenameParameter);
|
strcpy(_voxelPersistFilename, voxelsPersistFilenameParameter);
|
||||||
} else {
|
} else {
|
||||||
//strcpy(voxelPersistFilename, ::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE);
|
//strcpy(voxelPersistFilename, _wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE);
|
||||||
strcpy(voxelPersistFilename, LOCAL_VOXELS_PERSIST_FILE);
|
strcpy(_voxelPersistFilename, LOCAL_VOXELS_PERSIST_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("loading voxels from file: %s...\n", voxelPersistFilename);
|
qDebug("loading voxels from file: %s...\n", _voxelPersistFilename);
|
||||||
|
|
||||||
persistantFileRead = ::serverTree.readFromSVOFile(::voxelPersistFilename);
|
persistantFileRead = _serverTree.readFromSVOFile(_voxelPersistFilename);
|
||||||
if (persistantFileRead) {
|
if (persistantFileRead) {
|
||||||
PerformanceWarning warn(::shouldShowAnimationDebug,
|
PerformanceWarning warn(_shouldShowAnimationDebug,
|
||||||
"persistVoxelsWhenDirty() - reaverageVoxelColors()", ::shouldShowAnimationDebug);
|
"persistVoxelsWhenDirty() - reaverageVoxelColors()", _shouldShowAnimationDebug);
|
||||||
|
|
||||||
// after done inserting all these voxels, then reaverage colors
|
// after done inserting all these voxels, then reaverage colors
|
||||||
serverTree.reaverageVoxelColors(serverTree.rootNode);
|
_serverTree.reaverageVoxelColors(_serverTree.rootNode);
|
||||||
printf("Voxels reAveraged\n");
|
qDebug("Voxels reAveraged\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
::serverTree.clearDirtyBit(); // the tree is clean since we just loaded it
|
_serverTree.clearDirtyBit(); // the tree is clean since we just loaded it
|
||||||
printf("DONE loading voxels from file... fileRead=%s\n", debug::valueOf(persistantFileRead));
|
qDebug("DONE loading voxels from file... fileRead=%s\n", debug::valueOf(persistantFileRead));
|
||||||
unsigned long nodeCount = ::serverTree.rootNode->getSubTreeNodeCount();
|
unsigned long nodeCount = _serverTree.rootNode->getSubTreeNodeCount();
|
||||||
unsigned long internalNodeCount = ::serverTree.rootNode->getSubTreeInternalNodeCount();
|
unsigned long internalNodeCount = _serverTree.rootNode->getSubTreeInternalNodeCount();
|
||||||
unsigned long leafNodeCount = ::serverTree.rootNode->getSubTreeLeafNodeCount();
|
unsigned long leafNodeCount = _serverTree.rootNode->getSubTreeLeafNodeCount();
|
||||||
printf("Nodes after loading scene %lu nodes %lu internal %lu leaves\n", nodeCount, internalNodeCount, leafNodeCount);
|
qDebug("Nodes after loading scene %lu nodes %lu internal %lu leaves\n", nodeCount, internalNodeCount, leafNodeCount);
|
||||||
|
|
||||||
// now set up VoxelPersistThread
|
// now set up VoxelPersistThread
|
||||||
::voxelPersistThread = new VoxelPersistThread(&::serverTree, ::voxelPersistFilename);
|
_voxelPersistThread = new VoxelPersistThread(&_serverTree, _voxelPersistFilename);
|
||||||
if (::voxelPersistThread) {
|
if (_voxelPersistThread) {
|
||||||
::voxelPersistThread->initialize(true);
|
_voxelPersistThread->initialize(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,52 +323,52 @@ void VoxelServer::run() {
|
||||||
const char* INPUT_FILE = "-i";
|
const char* INPUT_FILE = "-i";
|
||||||
const char* voxelsFilename = getCmdOption(_argc, _argv, INPUT_FILE);
|
const char* voxelsFilename = getCmdOption(_argc, _argv, INPUT_FILE);
|
||||||
if (voxelsFilename) {
|
if (voxelsFilename) {
|
||||||
serverTree.readFromSVOFile(voxelsFilename);
|
_serverTree.readFromSVOFile(voxelsFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check to see if the user passed in a command line option for setting packet send rate
|
// 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* PACKETS_PER_SECOND = "--packetsPerSecond";
|
||||||
const char* packetsPerSecond = getCmdOption(_argc, _argv, PACKETS_PER_SECOND);
|
const char* packetsPerSecond = getCmdOption(_argc, _argv, PACKETS_PER_SECOND);
|
||||||
if (packetsPerSecond) {
|
if (packetsPerSecond) {
|
||||||
PACKETS_PER_CLIENT_PER_INTERVAL = atoi(packetsPerSecond)/INTERVALS_PER_SECOND;
|
_packetsPerClientPerInterval = atoi(packetsPerSecond) / INTERVALS_PER_SECOND;
|
||||||
if (PACKETS_PER_CLIENT_PER_INTERVAL < 1) {
|
if (_packetsPerClientPerInterval < 1) {
|
||||||
PACKETS_PER_CLIENT_PER_INTERVAL = 1;
|
_packetsPerClientPerInterval = 1;
|
||||||
}
|
}
|
||||||
printf("packetsPerSecond=%s PACKETS_PER_CLIENT_PER_INTERVAL=%d\n", packetsPerSecond, PACKETS_PER_CLIENT_PER_INTERVAL);
|
qDebug("packetsPerSecond=%s PACKETS_PER_CLIENT_PER_INTERVAL=%d\n", packetsPerSecond, _packetsPerClientPerInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
// for now, initialize the environments with fixed values
|
// for now, initialize the environments with fixed values
|
||||||
environmentData[1].setID(1);
|
_environmentData[1].setID(1);
|
||||||
environmentData[1].setGravity(1.0f);
|
_environmentData[1].setGravity(1.0f);
|
||||||
environmentData[1].setAtmosphereCenter(glm::vec3(0.5, 0.5, (0.25 - 0.06125)) * (float)TREE_SCALE);
|
_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].setAtmosphereInnerRadius(0.030625f * TREE_SCALE);
|
||||||
environmentData[1].setAtmosphereOuterRadius(0.030625f * TREE_SCALE * 1.05f);
|
_environmentData[1].setAtmosphereOuterRadius(0.030625f * TREE_SCALE * 1.05f);
|
||||||
environmentData[2].setID(2);
|
_environmentData[2].setID(2);
|
||||||
environmentData[2].setGravity(1.0f);
|
_environmentData[2].setGravity(1.0f);
|
||||||
environmentData[2].setAtmosphereCenter(glm::vec3(0.5f, 0.5f, 0.5f) * (float)TREE_SCALE);
|
_environmentData[2].setAtmosphereCenter(glm::vec3(0.5f, 0.5f, 0.5f) * (float)TREE_SCALE);
|
||||||
environmentData[2].setAtmosphereInnerRadius(0.1875f * TREE_SCALE);
|
_environmentData[2].setAtmosphereInnerRadius(0.1875f * TREE_SCALE);
|
||||||
environmentData[2].setAtmosphereOuterRadius(0.1875f * TREE_SCALE * 1.05f);
|
_environmentData[2].setAtmosphereOuterRadius(0.1875f * TREE_SCALE * 1.05f);
|
||||||
environmentData[2].setScatteringWavelengths(glm::vec3(0.475f, 0.570f, 0.650f)); // swaps red and blue
|
_environmentData[2].setScatteringWavelengths(glm::vec3(0.475f, 0.570f, 0.650f)); // swaps red and blue
|
||||||
|
|
||||||
sockaddr senderAddress;
|
sockaddr senderAddress;
|
||||||
|
|
||||||
unsigned char *packetData = new unsigned char[MAX_PACKET_SIZE];
|
unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE];
|
||||||
ssize_t packetLength;
|
ssize_t packetLength;
|
||||||
|
|
||||||
timeval lastDomainServerCheckIn = {};
|
timeval lastDomainServerCheckIn = {};
|
||||||
|
|
||||||
// set up our jurisdiction broadcaster...
|
// set up our jurisdiction broadcaster...
|
||||||
::jurisdictionSender = new JurisdictionSender(::jurisdiction);
|
_jurisdictionSender = new JurisdictionSender(_jurisdiction);
|
||||||
if (::jurisdictionSender) {
|
if (_jurisdictionSender) {
|
||||||
::jurisdictionSender->initialize(true);
|
_jurisdictionSender->initialize(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set up our VoxelServerPacketProcessor
|
// set up our VoxelServerPacketProcessor
|
||||||
::voxelServerPacketProcessor = new VoxelServerPacketProcessor();
|
_voxelServerPacketProcessor = new VoxelServerPacketProcessor(this);
|
||||||
if (::voxelServerPacketProcessor) {
|
if (_voxelServerPacketProcessor) {
|
||||||
::voxelServerPacketProcessor->initialize(true);
|
_voxelServerPacketProcessor->initialize(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// loop to send to nodes requesting data
|
// loop to send to nodes requesting data
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
|
@ -304,46 +399,50 @@ void VoxelServer::run() {
|
||||||
nodeID);
|
nodeID);
|
||||||
|
|
||||||
NodeList::getInstance()->updateNodeWithData(node, packetData, packetLength);
|
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) {
|
} else if (packetData[0] == PACKET_TYPE_PING) {
|
||||||
// If the packet is a ping, let processNodeData handle it.
|
// If the packet is a ping, let processNodeData handle it.
|
||||||
NodeList::getInstance()->processNodeData(&senderAddress, packetData, packetLength);
|
NodeList::getInstance()->processNodeData(&senderAddress, packetData, packetLength);
|
||||||
} else if (packetData[0] == PACKET_TYPE_DOMAIN) {
|
} else if (packetData[0] == PACKET_TYPE_DOMAIN) {
|
||||||
NodeList::getInstance()->processNodeData(&senderAddress, packetData, packetLength);
|
NodeList::getInstance()->processNodeData(&senderAddress, packetData, packetLength);
|
||||||
} else if (packetData[0] == PACKET_TYPE_VOXEL_JURISDICTION_REQUEST) {
|
} else if (packetData[0] == PACKET_TYPE_VOXEL_JURISDICTION_REQUEST) {
|
||||||
if (::jurisdictionSender) {
|
if (_jurisdictionSender) {
|
||||||
::jurisdictionSender->queueReceivedPacket(senderAddress, packetData, packetLength);
|
_jurisdictionSender->queueReceivedPacket(senderAddress, packetData, packetLength);
|
||||||
}
|
}
|
||||||
} else if (::voxelServerPacketProcessor) {
|
} else if (_voxelServerPacketProcessor) {
|
||||||
::voxelServerPacketProcessor->queueReceivedPacket(senderAddress, packetData, packetLength);
|
_voxelServerPacketProcessor->queueReceivedPacket(senderAddress, packetData, packetLength);
|
||||||
} else {
|
} else {
|
||||||
printf("unknown packet ignored... packetData[0]=%c\n", packetData[0]);
|
qDebug("unknown packet ignored... packetData[0]=%c\n", packetData[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (::jurisdiction) {
|
delete _jurisdiction;
|
||||||
delete ::jurisdiction;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (::jurisdictionSender) {
|
if (_jurisdictionSender) {
|
||||||
::jurisdictionSender->terminate();
|
_jurisdictionSender->terminate();
|
||||||
delete ::jurisdictionSender;
|
delete _jurisdictionSender;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (::voxelServerPacketProcessor) {
|
if (_voxelServerPacketProcessor) {
|
||||||
::voxelServerPacketProcessor->terminate();
|
_voxelServerPacketProcessor->terminate();
|
||||||
delete ::voxelServerPacketProcessor;
|
delete _voxelServerPacketProcessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (::voxelPersistThread) {
|
if (_voxelPersistThread) {
|
||||||
::voxelPersistThread->terminate();
|
_voxelPersistThread->terminate();
|
||||||
delete ::voxelPersistThread;
|
delete _voxelPersistThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
// tell our NodeList we're done with notifications
|
// tell our NodeList we're done with notifications
|
||||||
nodeList->removeHook(&nodeWatcher);
|
nodeList->removeHook(&_nodeWatcher);
|
||||||
|
|
||||||
pthread_mutex_destroy(&::treeLock);
|
pthread_mutex_destroy(&_treeLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
//
|
||||||
// VoxelServer.h
|
// VoxelServer.h
|
||||||
// voxel-server
|
// voxel-server
|
||||||
//
|
//
|
||||||
|
@ -9,28 +10,84 @@
|
||||||
#ifndef __voxel_server__VoxelServer__
|
#ifndef __voxel_server__VoxelServer__
|
||||||
#define __voxel_server__VoxelServer__
|
#define __voxel_server__VoxelServer__
|
||||||
|
|
||||||
|
#include <Assignment.h>
|
||||||
|
#include <EnvironmentData.h>
|
||||||
|
|
||||||
|
#include "NodeWatcher.h"
|
||||||
|
#include "VoxelPersistThread.h"
|
||||||
|
#include "VoxelSendThread.h"
|
||||||
|
#include "VoxelServerConsts.h"
|
||||||
|
#include "VoxelServerPacketProcessor.h"
|
||||||
|
|
||||||
/// Handles assignments of type VoxelServer - sending voxels to various clients.
|
/// Handles assignments of type VoxelServer - sending voxels to various clients.
|
||||||
class VoxelServer {
|
class VoxelServer : public Assignment {
|
||||||
public:
|
public:
|
||||||
|
VoxelServer(Assignment::Command command,
|
||||||
|
Assignment::Location location = Assignment::GlobalLocation);
|
||||||
|
|
||||||
|
VoxelServer(const unsigned char* dataBuffer, int numBytes);
|
||||||
|
|
||||||
|
~VoxelServer();
|
||||||
|
|
||||||
/// runs the voxel server assignment
|
/// runs the voxel server assignment
|
||||||
static void run();
|
void run();
|
||||||
|
|
||||||
/// allows setting of run arguments
|
/// allows setting of run arguments
|
||||||
static void setArguments(int argc, char** argv);
|
void setArguments(int argc, char** argv);
|
||||||
|
|
||||||
/// when VoxelServer class is used by voxel-server stand alone executable it calls this to specify the domain
|
/// when VoxelServer class is used by voxel-server stand alone executable it calls this to specify the domain
|
||||||
/// and port it is handling. When called by assignment-client, this is not needed because assignment-client
|
/// and port it is handling. When called by assignment-client, this is not needed because assignment-client
|
||||||
/// handles ports and domains automatically.
|
/// handles ports and domains automatically.
|
||||||
/// \param const char* domain domain name, IP address, or local to specify the domain the voxel server is serving
|
/// \param const char* domain domain name, IP address, or local to specify the domain the voxel server is serving
|
||||||
/// \param int port port the voxel server will listen on
|
/// \param int port port the voxel server will listen on
|
||||||
static void setupDomainAndPort(const char* domain, int port);
|
void setupStandAlone(const char* domain, int port);
|
||||||
|
|
||||||
|
bool wantsDebugVoxelSending() const { return _debugVoxelSending; }
|
||||||
|
bool wantsDebugVoxelReceiving() const { return _debugVoxelReceiving; }
|
||||||
|
bool wantShowAnimationDebug() const { return _shouldShowAnimationDebug; }
|
||||||
|
bool wantSendEnvironments() const { return _sendEnvironments; }
|
||||||
|
bool wantDumpVoxelsOnMove() const { return _dumpVoxelsOnMove; }
|
||||||
|
bool wantDisplayVoxelStats() const { return _displayVoxelStats; }
|
||||||
|
|
||||||
|
VoxelTree& getServerTree() { return _serverTree; }
|
||||||
|
JurisdictionMap* getJurisdiction() { return _jurisdiction; }
|
||||||
|
|
||||||
|
void lockTree() { pthread_mutex_lock(&_treeLock); }
|
||||||
|
void unlockTree() { pthread_mutex_unlock(&_treeLock); }
|
||||||
|
|
||||||
|
int getPacketsPerClientPerInterval() const { return _packetsPerClientPerInterval; }
|
||||||
|
bool getSendMinimalEnvironment() const { return _sendMinimalEnvironment; }
|
||||||
|
EnvironmentData* getEnvironmentData(int i) { return &_environmentData[i]; }
|
||||||
|
int getEnvironmentDataCount() const { return sizeof(_environmentData)/sizeof(EnvironmentData); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static int _argc;
|
int _argc;
|
||||||
static const char** _argv;
|
const char** _argv;
|
||||||
static bool _dontKillOnMissingDomain;
|
char** _parsedArgV;
|
||||||
|
bool _dontKillOnMissingDomain;
|
||||||
|
|
||||||
|
char _voxelPersistFilename[MAX_FILENAME_LENGTH];
|
||||||
|
int _packetsPerClientPerInterval;
|
||||||
|
VoxelTree _serverTree; // this IS a reaveraging tree
|
||||||
|
bool _wantVoxelPersist;
|
||||||
|
bool _wantLocalDomain;
|
||||||
|
bool _debugVoxelSending;
|
||||||
|
bool _shouldShowAnimationDebug;
|
||||||
|
bool _displayVoxelStats;
|
||||||
|
bool _debugVoxelReceiving;
|
||||||
|
bool _sendEnvironments;
|
||||||
|
bool _sendMinimalEnvironment;
|
||||||
|
bool _dumpVoxelsOnMove;
|
||||||
|
JurisdictionMap* _jurisdiction;
|
||||||
|
JurisdictionSender* _jurisdictionSender;
|
||||||
|
VoxelServerPacketProcessor* _voxelServerPacketProcessor;
|
||||||
|
VoxelPersistThread* _voxelPersistThread;
|
||||||
|
pthread_mutex_t _treeLock;
|
||||||
|
EnvironmentData _environmentData[3];
|
||||||
|
|
||||||
|
NodeWatcher _nodeWatcher; // used to cleanup AGENT data when agents are killed
|
||||||
|
|
||||||
|
void parsePayload();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // __voxel_server__VoxelServer__
|
#endif // __voxel_server__VoxelServer__
|
||||||
|
|
31
libraries/voxel-server-library/src/VoxelServerConsts.h
Normal file
31
libraries/voxel-server-library/src/VoxelServerConsts.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
// VoxelServerConsts.h
|
||||||
|
// voxel-server
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 8/21/13
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __voxel_server__VoxelServerConsts__
|
||||||
|
#define __voxel_server__VoxelServerConsts__
|
||||||
|
|
||||||
|
#include <SharedUtil.h>
|
||||||
|
#include <NodeList.h> // for MAX_PACKET_SIZE
|
||||||
|
#include <JurisdictionSender.h>
|
||||||
|
#include <VoxelTree.h>
|
||||||
|
|
||||||
|
#include "VoxelServerPacketProcessor.h"
|
||||||
|
|
||||||
|
|
||||||
|
const int MAX_FILENAME_LENGTH = 1024;
|
||||||
|
const int VOXEL_SIZE_BYTES = 3 + (3 * sizeof(float));
|
||||||
|
const int VOXELS_PER_PACKET = (MAX_PACKET_SIZE - 1) / VOXEL_SIZE_BYTES;
|
||||||
|
const int VOXEL_SEND_INTERVAL_USECS = 17 * 1000; // approximately 60fps
|
||||||
|
const int SENDING_TIME_TO_SPARE = 5 * 1000; // usec of sending interval to spare for calculating voxels
|
||||||
|
const int INTERVALS_PER_SECOND = 1000 * 1000 / VOXEL_SEND_INTERVAL_USECS;
|
||||||
|
const int ENVIRONMENT_SEND_INTERVAL_USECS = 1000000;
|
||||||
|
|
||||||
|
extern const char* LOCAL_VOXELS_PERSIST_FILE;
|
||||||
|
extern const char* VOXELS_PERSIST_FILE;
|
||||||
|
|
||||||
|
#endif // __voxel_server__VoxelServerConsts__
|
|
@ -12,33 +12,39 @@
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
|
|
||||||
#include "VoxelServer.h"
|
#include "VoxelServer.h"
|
||||||
#include "VoxelServerState.h"
|
#include "VoxelServerConsts.h"
|
||||||
#include "VoxelServerPacketProcessor.h"
|
#include "VoxelServerPacketProcessor.h"
|
||||||
|
|
||||||
|
|
||||||
|
VoxelServerPacketProcessor::VoxelServerPacketProcessor(VoxelServer* myServer) :
|
||||||
|
_myServer(myServer),
|
||||||
|
_receivedPacketCount(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) {
|
void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) {
|
||||||
|
|
||||||
int numBytesPacketHeader = numBytesForPacketHeader(packetData);
|
int numBytesPacketHeader = numBytesForPacketHeader(packetData);
|
||||||
|
|
||||||
if (packetData[0] == PACKET_TYPE_SET_VOXEL || packetData[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE) {
|
if (packetData[0] == PACKET_TYPE_SET_VOXEL || packetData[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE) {
|
||||||
bool destructive = (packetData[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE);
|
bool destructive = (packetData[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE);
|
||||||
PerformanceWarning warn(::shouldShowAnimationDebug,
|
PerformanceWarning warn(_myServer->wantShowAnimationDebug(),
|
||||||
destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL",
|
destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL",
|
||||||
::shouldShowAnimationDebug);
|
_myServer->wantShowAnimationDebug());
|
||||||
|
|
||||||
::receivedPacketCount++;
|
_receivedPacketCount++;
|
||||||
|
|
||||||
unsigned short int itemNumber = (*((unsigned short int*)(packetData + numBytesPacketHeader)));
|
unsigned short int itemNumber = (*((unsigned short int*)(packetData + numBytesPacketHeader)));
|
||||||
if (::shouldShowAnimationDebug) {
|
if (_myServer->wantShowAnimationDebug()) {
|
||||||
printf("got %s - command from client receivedBytes=%ld itemNumber=%d\n",
|
printf("got %s - command from client receivedBytes=%ld itemNumber=%d\n",
|
||||||
destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL",
|
destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL",
|
||||||
packetLength, itemNumber);
|
packetLength, itemNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (::debugVoxelReceiving) {
|
if (_myServer->wantsDebugVoxelReceiving()) {
|
||||||
printf("got %s - %d command from client receivedBytes=%ld itemNumber=%d\n",
|
printf("got %s - %d command from client receivedBytes=%ld itemNumber=%d\n",
|
||||||
destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL",
|
destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL",
|
||||||
::receivedPacketCount, packetLength, itemNumber);
|
_receivedPacketCount, packetLength, itemNumber);
|
||||||
}
|
}
|
||||||
int atByte = numBytesPacketHeader + sizeof(itemNumber);
|
int atByte = numBytesPacketHeader + sizeof(itemNumber);
|
||||||
unsigned char* voxelData = (unsigned char*)&packetData[atByte];
|
unsigned char* voxelData = (unsigned char*)&packetData[atByte];
|
||||||
|
@ -48,7 +54,7 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned
|
||||||
int voxelDataSize = bytesRequiredForCodeLength(octets) + COLOR_SIZE_IN_BYTES;
|
int voxelDataSize = bytesRequiredForCodeLength(octets) + COLOR_SIZE_IN_BYTES;
|
||||||
int voxelCodeSize = bytesRequiredForCodeLength(octets);
|
int voxelCodeSize = bytesRequiredForCodeLength(octets);
|
||||||
|
|
||||||
if (::shouldShowAnimationDebug) {
|
if (_myServer->wantShowAnimationDebug()) {
|
||||||
int red = voxelData[voxelCodeSize + 0];
|
int red = voxelData[voxelCodeSize + 0];
|
||||||
int green = voxelData[voxelCodeSize + 1];
|
int green = voxelData[voxelCodeSize + 1];
|
||||||
int blue = voxelData[voxelCodeSize + 2];
|
int blue = voxelData[voxelCodeSize + 2];
|
||||||
|
@ -58,7 +64,7 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned
|
||||||
delete[] vertices;
|
delete[] vertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
serverTree.readCodeColorBufferToTree(voxelData, destructive);
|
_myServer->getServerTree().readCodeColorBufferToTree(voxelData, destructive);
|
||||||
// skip to next
|
// skip to next
|
||||||
voxelData += voxelDataSize;
|
voxelData += voxelDataSize;
|
||||||
atByte += voxelDataSize;
|
atByte += voxelDataSize;
|
||||||
|
@ -73,9 +79,9 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned
|
||||||
} else if (packetData[0] == PACKET_TYPE_ERASE_VOXEL) {
|
} else if (packetData[0] == PACKET_TYPE_ERASE_VOXEL) {
|
||||||
|
|
||||||
// Send these bits off to the VoxelTree class to process them
|
// Send these bits off to the VoxelTree class to process them
|
||||||
pthread_mutex_lock(&::treeLock);
|
_myServer->lockTree();
|
||||||
::serverTree.processRemoveVoxelBitstream((unsigned char*)packetData, packetLength);
|
_myServer->getServerTree().processRemoveVoxelBitstream((unsigned char*)packetData, packetLength);
|
||||||
pthread_mutex_unlock(&::treeLock);
|
_myServer->unlockTree();
|
||||||
|
|
||||||
// Make sure our Node and NodeList knows we've heard from this node.
|
// Make sure our Node and NodeList knows we've heard from this node.
|
||||||
Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress);
|
Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress);
|
||||||
|
|
|
@ -12,11 +12,20 @@
|
||||||
#define __voxel_server__VoxelServerPacketProcessor__
|
#define __voxel_server__VoxelServerPacketProcessor__
|
||||||
|
|
||||||
#include <ReceivedPacketProcessor.h>
|
#include <ReceivedPacketProcessor.h>
|
||||||
|
class VoxelServer;
|
||||||
|
|
||||||
/// Handles processing of incoming network packets for the voxel-server. As with other ReceivedPacketProcessor classes
|
/// Handles processing of incoming network packets for the voxel-server. As with other ReceivedPacketProcessor classes
|
||||||
/// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket()
|
/// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket()
|
||||||
class VoxelServerPacketProcessor : public ReceivedPacketProcessor {
|
class VoxelServerPacketProcessor : public ReceivedPacketProcessor {
|
||||||
|
|
||||||
|
public:
|
||||||
|
VoxelServerPacketProcessor(VoxelServer* myServer);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength);
|
virtual void processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength);
|
||||||
|
|
||||||
|
private:
|
||||||
|
VoxelServer* _myServer;
|
||||||
|
int _receivedPacketCount;
|
||||||
};
|
};
|
||||||
#endif // __voxel_server__VoxelServerPacketProcessor__
|
#endif // __voxel_server__VoxelServerPacketProcessor__
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
// VoxelServer.h
|
|
||||||
// voxel-server
|
|
||||||
//
|
|
||||||
// Created by Brad Hefta-Gaub on 8/21/13
|
|
||||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
|
||||||
//
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef __voxel_server__VoxelServerState__
|
|
||||||
#define __voxel_server__VoxelServerState__
|
|
||||||
|
|
||||||
#include <SharedUtil.h>
|
|
||||||
#include <NodeList.h> // for MAX_PACKET_SIZE
|
|
||||||
#include <JurisdictionSender.h>
|
|
||||||
#include <VoxelTree.h>
|
|
||||||
|
|
||||||
#include "VoxelServerPacketProcessor.h"
|
|
||||||
|
|
||||||
|
|
||||||
const int MAX_FILENAME_LENGTH = 1024;
|
|
||||||
const int VOXEL_SIZE_BYTES = 3 + (3 * sizeof(float));
|
|
||||||
const int VOXELS_PER_PACKET = (MAX_PACKET_SIZE - 1) / VOXEL_SIZE_BYTES;
|
|
||||||
const int MIN_BRIGHTNESS = 64;
|
|
||||||
const float DEATH_STAR_RADIUS = 4.0;
|
|
||||||
const float MAX_CUBE = 0.05f;
|
|
||||||
const int VOXEL_SEND_INTERVAL_USECS = 17 * 1000; // approximately 60fps
|
|
||||||
const int SENDING_TIME_TO_SPARE = 5 * 1000; // usec of sending interval to spare for calculating voxels
|
|
||||||
const int INTERVALS_PER_SECOND = 1000 * 1000 / VOXEL_SEND_INTERVAL_USECS;
|
|
||||||
const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4;
|
|
||||||
const int ENVIRONMENT_SEND_INTERVAL_USECS = 1000000;
|
|
||||||
|
|
||||||
extern const char* LOCAL_VOXELS_PERSIST_FILE;
|
|
||||||
extern const char* VOXELS_PERSIST_FILE;
|
|
||||||
extern char voxelPersistFilename[MAX_FILENAME_LENGTH];
|
|
||||||
extern int PACKETS_PER_CLIENT_PER_INTERVAL;
|
|
||||||
|
|
||||||
extern VoxelTree serverTree; // this IS a reaveraging tree
|
|
||||||
extern bool wantVoxelPersist;
|
|
||||||
extern bool wantLocalDomain;
|
|
||||||
extern bool debugVoxelSending;
|
|
||||||
extern bool shouldShowAnimationDebug;
|
|
||||||
extern bool displayVoxelStats;
|
|
||||||
extern bool debugVoxelReceiving;
|
|
||||||
extern bool sendEnvironments;
|
|
||||||
extern bool sendMinimalEnvironment;
|
|
||||||
extern bool dumpVoxelsOnMove;
|
|
||||||
extern int receivedPacketCount;
|
|
||||||
extern JurisdictionMap* jurisdiction;
|
|
||||||
extern JurisdictionSender* jurisdictionSender;
|
|
||||||
extern VoxelServerPacketProcessor* voxelServerPacketProcessor;
|
|
||||||
extern pthread_mutex_t treeLock;
|
|
||||||
|
|
||||||
#endif // __voxel_server__VoxelServerState__
|
|
|
@ -29,17 +29,19 @@ int main(int argc, const char * argv[]) {
|
||||||
}
|
}
|
||||||
printf("portParameter=%s listenPort=%d\n", portParameter, listenPort);
|
printf("portParameter=%s listenPort=%d\n", portParameter, listenPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VoxelServer ourVoxelServer(Assignment::CreateCommand);
|
||||||
|
|
||||||
if (wantLocalDomain) {
|
if (wantLocalDomain) {
|
||||||
VoxelServer::setupDomainAndPort(local, listenPort);
|
ourVoxelServer.setupStandAlone(local, listenPort);
|
||||||
} else {
|
} else {
|
||||||
if (domainIP) {
|
if (domainIP) {
|
||||||
VoxelServer::setupDomainAndPort(domainIP, listenPort);
|
ourVoxelServer.setupStandAlone(domainIP, listenPort);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VoxelServer::setArguments(argc, const_cast<char**>(argv));
|
ourVoxelServer.setArguments(argc, const_cast<char**>(argv));
|
||||||
VoxelServer::run();
|
ourVoxelServer.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue