コード例 #1
0
void VoxelEditPacketSender::queuePacketToNodes(unsigned char* buffer, ssize_t length) {
    if (!_shouldSend) {
        return; // bail early
    }
    
    assert(voxelServersExist()); // we must have jurisdictions to be here!!

    int headerBytes = numBytesForPacketHeader(buffer) + sizeof(short) + sizeof(uint64_t);
    unsigned char* octCode = buffer + headerBytes; // skip the packet header to get to the octcode
    
    // We want to filter out edit messages for voxel servers based on the server's Jurisdiction
    // But we can't really do that with a packed message, since each edit message could be destined 
    // for a different voxel server... So we need to actually manage multiple queued packets... one
    // for each voxel server
    NodeList* nodeList = NodeList::getInstance();
    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
        // only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
        if (node->getActiveSocket() != NULL && node->getType() == NODE_TYPE_VOXEL_SERVER) {
            QUuid nodeUUID = node->getUUID();
            bool isMyJurisdiction = true;
            // we need to get the jurisdiction for this 
            // here we need to get the "pending packet" for this server
            const JurisdictionMap& map = (*_voxelServerJurisdictions)[nodeUUID];
            isMyJurisdiction = (map.isMyJurisdiction(octCode, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN);
            if (isMyJurisdiction) {
                queuePacketToNode(nodeUUID, buffer, length);
            }
        }
    }
}
コード例 #2
0
void AbstractObject::preparedObjectData(std::vector<std::string> &avecItems, std::string & astrParent)	{
	ref_ptr<AbstractObject> pAbstractObject = dynamic_cast<AbstractObject*>(this);

	vector<string> * pvecItems = &avecItems;

	int nI=1;

	string strClassName = pAbstractObject->className();
	const string * pstrObjectName = &pAbstractObject->getName();
	string strItem = (string(2*nI,' ') + strClassName + ";" + *pstrObjectName + ";" + pAbstractObject->prepareRowData(astrParent));
	pvecItems->push_back(strItem);

	nI += 1;	//enlarge indent by 1 unit

	NodeList::iterator it;
	for (it = pAbstractObject->_children.begin(); it != pAbstractObject->_children.end(); it++)	{
		ref_ptr<AbstractObject> pChild = dynamic_cast<AbstractObject*>(it->get());

		if(pChild == NULL)	{
			break;
		}

		strClassName = pChild->className();
		pstrObjectName = &pChild->getName();
		strItem = (strClassName + ";" + *pstrObjectName + ";" + pChild->prepareRowData(pAbstractObject->getName()));

		pvecItems->push_back(string(2*nI,' ') + strItem);
	}
}
コード例 #3
0
ファイル: JurisdictionListener.cpp プロジェクト: heracek/hifi
bool JurisdictionListener::queueJurisdictionRequest() {
    static unsigned char buffer[MAX_PACKET_SIZE];
    unsigned char* bufferOut = &buffer[0];
    ssize_t sizeOut = populateTypeAndVersion(bufferOut, PACKET_TYPE_VOXEL_JURISDICTION_REQUEST);
    int nodeCount = 0;

    NodeList* nodeList = NodeList::getInstance();
    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {

        // only send to the NodeTypes that are interested in our jurisdiction details
        const int numNodeTypes = 1; 
        const NODE_TYPE nodeTypes[numNodeTypes] = { NODE_TYPE_VOXEL_SERVER };
        if (node->getActiveSocket() != NULL && memchr(nodeTypes, node->getType(), numNodeTypes)) {
            sockaddr* nodeAddress = node->getActiveSocket();
            PacketSender::queuePacketForSending(*nodeAddress, bufferOut, sizeOut);
            nodeCount++;
        }
    }

    // set our packets per second to be the number of nodes
    setPacketsPerSecond(nodeCount);
    
    // keep going if still running
    return isStillRunning();
}
コード例 #4
0
ファイル: VRScene.cpp プロジェクト: octaviansoldea/VRShop
void Scene::print()	{

	string strFileName = getLogFile();
	ofstream output(strFileName, ios::app);
	output << "========================================================Begin Scene" << endl;

	int nI;

	output << "SCENE at iteration " << m_nIteration << endl;

	output << "Scene objects by name: " << endl;
	NodeList::iterator it;
	for (it = _children.begin(); it != _children.end(); it++)	{
		output << "Parent: " << it->get()->getParent(0)->getName()
			<< "; Class Name:" << it->get()->className() << "; Object Name: " <<it->get()->getName() << endl;
	}

	
	for (it = _children.begin(); it != _children.end(); it++)	{
		nI = it - _children.begin();
		ref_ptr<VR::AbstractObject> pObject = dynamic_cast<VR::AbstractObject*>(this->getChild(nI));
		if (!pObject.valid())
			continue;
		else
			pObject->print(output);
	}
	output << "========================================================End Scene" << endl;

	output.close();
	m_nIteration++;
	
}
コード例 #5
0
bool CurveDragPoint::clicked(GdkEventButton *event)
{
    // This check is probably redundant
    if (!first || event->button != 1) return false;
    // the next iterator can be invalid if we click very near the end of path
    NodeList::iterator second = first.next();
    if (!second) return false;

    // insert nodes on Ctrl+Alt+click
    if (held_control(*event) && held_alt(*event)) {
        _insertNode(false);
        return true;
    }

    if (held_shift(*event)) {
        // if both nodes of the segment are selected, deselect;
        // otherwise add to selection
        if (first->selected() && second->selected())  {
            _pm._selection.erase(first.ptr());
            _pm._selection.erase(second.ptr());
        } else {
            _pm._selection.insert(first.ptr());
            _pm._selection.insert(second.ptr());
        }
    } else {
        // without Shift, take selection
        _pm._selection.clear();
        _pm._selection.insert(first.ptr());
        _pm._selection.insert(second.ptr());
    }
    return true;
}
コード例 #6
0
ファイル: NodeList.cpp プロジェクト: problem/hifi
void* removeSilentNodes(void *args) {
    NodeList* nodeList = (NodeList*) args;
    uint64_t checkTimeUSecs;
    int sleepTime;
    
    while (!silentNodeThreadStopFlag) {
        checkTimeUSecs = usecTimestampNow();
        
        for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); ++node) {
            
            if ((checkTimeUSecs - node->getLastHeardMicrostamp()) > NODE_SILENCE_THRESHOLD_USECS) {
            
                qDebug() << "Killed " << *node << "\n";
                
                nodeList->notifyHooksOfKilledNode(&*node);
                
                node->setAlive(false);
            }
        }
        
        sleepTime = NODE_SILENCE_THRESHOLD_USECS - (usecTimestampNow() - checkTimeUSecs);
        #ifdef _WIN32
        Sleep( static_cast<int>(1000.0f*sleepTime) );
        #else
        usleep(sleepTime);
        #endif
    }
    
    pthread_exit(0);
    return NULL;
}
コード例 #7
0
bool VoxelEditPacketSender::voxelServersExist() const {
    bool hasVoxelServers = false;
    bool atLeastOnJurisdictionMissing = false; // assume the best
    NodeList* nodeList = NodeList::getInstance();
    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
        // only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
        if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
            if (nodeList->getNodeActiveSocketOrPing(&(*node))) {
                QUuid nodeUUID = node->getUUID();
                // If we've got Jurisdictions set, then check to see if we know the jurisdiction for this server
                if (_voxelServerJurisdictions) {
                    // lookup our nodeUUID in the jurisdiction map, if it's missing then we're 
                    // missing at least one jurisdiction
                    if ((*_voxelServerJurisdictions).find(nodeUUID) == (*_voxelServerJurisdictions).end()) {
                        atLeastOnJurisdictionMissing = true;
                    }
                }
                hasVoxelServers = true;
            }
        }
        if (atLeastOnJurisdictionMissing) {
            break; // no point in looking further...
        }
    }
    return (hasVoxelServers && !atLeastOnJurisdictionMissing);
}
コード例 #8
0
bool JurisdictionListener::queueJurisdictionRequest() {
    //qDebug() << "JurisdictionListener::queueJurisdictionRequest()\n";

    static unsigned char buffer[MAX_PACKET_SIZE];
    unsigned char* bufferOut = &buffer[0];
    ssize_t sizeOut = populateTypeAndVersion(bufferOut, PACKET_TYPE_JURISDICTION_REQUEST);
    int nodeCount = 0;

    NodeList* nodeList = NodeList::getInstance();
    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
        if (nodeList->getNodeActiveSocketOrPing(&(*node)) &&
                node->getType() == getNodeType()) {
            const HifiSockAddr* nodeAddress = node->getActiveSocket();
            PacketSender::queuePacketForSending(*nodeAddress, bufferOut, sizeOut);
            nodeCount++;
        }
    }

    if (nodeCount > 0) {
        setPacketsPerSecond(nodeCount);
    } else {
        setPacketsPerSecond(NO_SERVER_CHECK_RATE);
    }

    // keep going if still running
    return isStillRunning();
}
コード例 #9
0
ファイル: NodeList.cpp プロジェクト: problem/hifi
Node* NodeList::nodeWithAddress(sockaddr *senderAddress) {
    for(NodeList::iterator node = begin(); node != end(); node++) {
        if (node->getActiveSocket() && socketMatch(node->getActiveSocket(), senderAddress)) {
            return &(*node);
        }
    }
    
    return NULL;
}
コード例 #10
0
Node::~Node()
{
    for (NodeList::iterator i = adjacentNodes_.begin(); i != adjacentNodes_.end(); ++i)
    {
        i->reset();
    }

    printf("%sN%08x: deleted %c at (%d,%d)\n", indent(), this, color_ + 'A', x_, y_);
}
コード例 #11
0
ファイル: NodeList.cpp プロジェクト: problem/hifi
Node* NodeList::nodeWithID(uint16_t nodeID) {
    for(NodeList::iterator node = begin(); node != end(); node++) {
        if (node->getNodeID() == nodeID) {
            return &(*node);
        }
    }

    return NULL;
}
コード例 #12
0
ファイル: NodeList.cpp プロジェクト: problem/hifi
Node* NodeList::soloNodeOfType(char nodeType) {
    if (memchr(SOLO_NODE_TYPES, nodeType, sizeof(SOLO_NODE_TYPES)) != NULL) {
        for(NodeList::iterator node = begin(); node != end(); node++) {
            if (node->getType() == nodeType) {
                return &(*node);
            }
        }
    }
    
    return NULL;
}
コード例 #13
0
ファイル: NodeList.cpp プロジェクト: problem/hifi
int NodeList::getNumAliveNodes() const {
    int numAliveNodes = 0;
    
    for (NodeList::iterator node = begin(); node != end(); node++) {
        if (node->isAlive()) {
            ++numAliveNodes;
        }
    }
    
    return numAliveNodes;
}
コード例 #14
0
ファイル: NodeList.cpp プロジェクト: problem/hifi
unsigned NodeList::broadcastToNodes(unsigned char* broadcastData, size_t dataBytes, const char* nodeTypes, int numNodeTypes) {
    unsigned n = 0;
    for(NodeList::iterator node = begin(); node != end(); node++) {
        // only send to the NodeTypes we are asked to send to.
        if (node->getActiveSocket() != NULL && memchr(nodeTypes, node->getType(), numNodeTypes)) {
            // we know which socket is good for this node, send there
            _nodeSocket.send(node->getActiveSocket(), broadcastData, dataBytes);
            ++n;
        }
    }
    return n;
}
コード例 #15
0
ファイル: NodeList.cpp プロジェクト: problem/hifi
void NodeList::timePingReply(sockaddr *nodeAddress, unsigned char *packetData) {
    for(NodeList::iterator node = begin(); node != end(); node++) {
        if (socketMatch(node->getPublicSocket(), nodeAddress) || 
            socketMatch(node->getLocalSocket(), nodeAddress)) {     

            int pingTime = usecTimestampNow() - *(uint64_t*)(packetData + numBytesForPacketHeader(packetData));
            
            node->setPingMs(pingTime / 1000);
            break;
        }
    }
}
コード例 #16
0
void CurveDragPoint::dragged(Geom::Point &new_pos, GdkEventMotion *event)
{
    NodeList::iterator second = first.next();

    // special cancel handling - retract handles when if the segment was degenerate
    if (_is_drag_cancelled(event) && _segment_was_degenerate) {
        first->front()->retract();
        second->back()->retract();
        _pm.update();
        return;
    }

    if (_drag_initiated && !(event->state & GDK_SHIFT_MASK)) {
        SnapManager &m = _desktop->namedview->snap_manager;
        SPItem *path = static_cast<SPItem *>(_pm._path);
        m.setup(_desktop, true, path); // We will not try to snap to "path" itself
        Inkscape::SnapCandidatePoint scp(new_pos, Inkscape::SNAPSOURCE_OTHER_HANDLE);
        Inkscape::SnappedPoint sp = m.freeSnap(scp, Geom::OptRect(), false);
        new_pos = sp.getPoint();
        m.unSetup();
    }

    // Magic Bezier Drag Equations follow!
    // "weight" describes how the influence of the drag should be distributed
    // among the handles; 0 = front handle only, 1 = back handle only.
    double weight, t = _t;
    if (t <= 1.0 / 6.0) weight = 0;
    else if (t <= 0.5) weight = (pow((6 * t - 1) / 2.0, 3)) / 2;
    else if (t <= 5.0 / 6.0) weight = (1 - pow((6 * (1-t) - 1) / 2.0, 3)) / 2 + 0.5;
    else weight = 1;

    Geom::Point delta = new_pos - position();
    Geom::Point offset0 = ((1-weight)/(3*t*(1-t)*(1-t))) * delta;
    Geom::Point offset1 = (weight/(3*t*t*(1-t))) * delta;

    //modified so that, if the trace is bspline, it only acts if the SHIFT key is pressed
    if(!_pm._isBSpline()){
        first->front()->move(first->front()->position() + offset0);
        second->back()->move(second->back()->position() + offset1);
    }else if(weight>=0.8){
        if(held_shift(*event)){
            second->back()->move(new_pos);
        } else {
            second->move(second->position() + delta);
        }
    }else if(weight<=0.2){
        if(held_shift(*event)){
            first->back()->move(new_pos);
        } else {
            first->move(first->position() + delta);
        }
    }else{
        first->move(first->position() + delta);
        second->move(second->position() + delta);
    }
    _pm.update();
}
コード例 #17
0
ファイル: NodeList.cpp プロジェクト: problem/hifi
void NodeList::handlePingReply(sockaddr *nodeAddress) {
    for(NodeList::iterator node = begin(); node != end(); node++) {
        // check both the public and local addresses for each node to see if we find a match
        // prioritize the private address so that we prune erroneous local matches
        if (socketMatch(node->getPublicSocket(), nodeAddress)) {
            node->activatePublicSocket();
            break;
        } else if (socketMatch(node->getLocalSocket(), nodeAddress)) {
            node->activateLocalSocket();
            break;
        }
    }
}
コード例 #18
0
ファイル: main.cpp プロジェクト: evilbinary/hifi
void eraseVoxelTreeAndCleanupNodeVisitData() {

    // As our tree to erase all it's voxels
    ::serverTree.eraseAllVoxels();
    // enumerate the nodes clean up their marker nodes
    for (NodeList::iterator node = NodeList::getInstance()->begin(); node != NodeList::getInstance()->end(); node++) {
        VoxelNodeData* nodeData = (VoxelNodeData*) node->getLinkedData();
        if (nodeData) {
            // clean up the node visit data
            nodeData->nodeBag.deleteAll();
        }
    }
}
コード例 #19
0
ファイル: NodeList.cpp プロジェクト: problem/hifi
Node* NodeList::addOrUpdateNode(sockaddr* publicSocket, sockaddr* localSocket, char nodeType, uint16_t nodeId) {
    NodeList::iterator node = end();
    
    if (publicSocket) {
        for (node = begin(); node != end(); node++) {
            if (node->matches(publicSocket, localSocket, nodeType)) {
                // we already have this node, stop checking
                break;
            }
        }
    }
    
    if (node == end()) {
        // if we already had this node AND it's a solo type then bust out of here
        if (soloNodeOfType(nodeType)) {
            return NULL;
        }
        
        // we didn't have this node, so add them
        Node* newNode = new Node(publicSocket, localSocket, nodeType, nodeId);
        
        if (socketMatch(publicSocket, localSocket)) {
            // likely debugging scenario with two nodes on local network
            // set the node active right away
            newNode->activatePublicSocket();
        }
   
        if (newNode->getType() == NODE_TYPE_VOXEL_SERVER ||
            newNode->getType() == NODE_TYPE_AVATAR_MIXER ||
            newNode->getType() == NODE_TYPE_AUDIO_MIXER) {
            // this is currently the cheat we use to talk directly to our test servers on EC2
            // to be removed when we have a proper identification strategy
            newNode->activatePublicSocket();
        }
        
        addNodeToList(newNode);
        
        return newNode;
    } else {
        
        if (node->getType() == NODE_TYPE_AUDIO_MIXER ||
            node->getType() == NODE_TYPE_VOXEL_SERVER) {
            // until the Audio class also uses our nodeList, we need to update
            // the lastRecvTimeUsecs for the audio mixer so it doesn't get killed and re-added continously
            node->setLastHeardMicrostamp(usecTimestampNow());
        }
        
        // we had this node already, do nothing for now
        return &*node;
    }    
}
コード例 #20
0
ファイル: VRScene.cpp プロジェクト: octaviansoldea/VRShop
Node * Scene::getChild(const string & astrChildName)	{
	if (astrChildName.empty())	{
		return 0;
	}

	NodeList::iterator it = _children.begin();
	for (it; it != _children.end(); it++)	{
		const string strChild = it->get()->getName();
		if (strChild == astrChildName)	{
			Node * pChild = dynamic_cast<Node*>(it->get());

			return pChild;
		}
	}
	return 0;
}
コード例 #21
0
void AbstractObject::writeObjectHierarchy(vector<string> &avecstrHierarchy)	{
	//Object name
	avecstrHierarchy.push_back(getName());
	
	ref_ptr<AbstractObject> pAO = dynamic_cast<AbstractObject*>(this);

	NodeList::iterator it = pAO->_children.begin();
	for (it; it != pAO->_children.end(); it++)	{
		string strName = it->get()->getName();
		if (strName.empty())	{
			break;
		} else {
			strName = string(2,' ') + strName;
			avecstrHierarchy.push_back(strName);
		}
	}
}
コード例 #22
0
ファイル: DomainServer.cpp プロジェクト: jtwigg/hifi
bool DomainServer::checkInWithUUIDMatchesExistingNode(sockaddr* nodePublicSocket,
                                                      sockaddr* nodeLocalSocket,
                                                      const QUuid& checkInUUID) {
    NodeList* nodeList = NodeList::getInstance();
    
    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
        if (node->getLinkedData()
            && socketMatch(node->getPublicSocket(), nodePublicSocket)
            && socketMatch(node->getLocalSocket(), nodeLocalSocket)
            && node->getUUID() == checkInUUID) {
            // this is a matching existing node if the public socket, local socket, and UUID match
            return true;
        }
    }
    
    return false;
}
コード例 #23
0
ファイル: DomainServer.cpp プロジェクト: jtwigg/hifi
void DomainServer::possiblyAddStaticAssignmentsBackToQueueAfterRestart(timeval* startTime) {
    // if the domain-server has just restarted,
    // check if there are static assignments in the file that we need to
    // throw into the assignment queue
    const uint64_t RESTART_HOLD_TIME_USECS = 5 * 1000 * 1000;
    
    if (!_hasCompletedRestartHold && usecTimestampNow() - usecTimestamp(startTime) > RESTART_HOLD_TIME_USECS) {
        _hasCompletedRestartHold = true;
        
        // pull anything in the static assignment file that isn't spoken for and add to the assignment queue
        for (int i = 0; i < MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS; i++) {
            if (_staticAssignments[i].getUUID().isNull()) {
                // reached the end of static assignments, bail
                break;
            }
            
            bool foundMatchingAssignment = false;
            
            NodeList* nodeList = NodeList::getInstance();
            
            // enumerate the nodes and check if there is one with an attached assignment with matching UUID
            for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
                if (node->getLinkedData()) {
                    Assignment* linkedAssignment = (Assignment*) node->getLinkedData();
                    if (linkedAssignment->getUUID() == _staticAssignments[i].getUUID()) {
                        foundMatchingAssignment = true;
                        break;
                    }
                }
            }
            
            if (!foundMatchingAssignment) {
                // this assignment has not been fulfilled - reset the UUID and add it to the assignment queue
                _staticAssignments[i].resetUUID();
                
                qDebug() << "Adding static assignment to queue -" << _staticAssignments[i] << "\n";
                
                _assignmentQueueMutex.lock();
                _assignmentQueue.push_back(&_staticAssignments[i]);
                _assignmentQueueMutex.unlock();
            }
        }
    }
}
コード例 #24
0
bool CurveDragPoint::grabbed(GdkEventMotion */*event*/)
{
    _pm._selection.hideTransformHandles();
    NodeList::iterator second = first.next();

    // move the handles to 1/3 the length of the segment for line segments
    if (first->front()->isDegenerate() && second->back()->isDegenerate()) {
        _segment_was_degenerate = true;

        // delta is a vector equal 1/3 of distance from first to second
        Geom::Point delta = (second->position() - first->position()) / 3.0;
        // only update the nodes if the mode is bspline
        if(!_pm._isBSpline()){
            first->front()->move(first->front()->position() + delta);
            second->back()->move(second->back()->position() - delta);
        }
        _pm.update();
    } else {
        _segment_was_degenerate = false;
    }
    return false;
}
コード例 #25
0
ファイル: main.cpp プロジェクト: evilbinary/hifi
// NOTE: some additional optimizations to consider.
//    1) use the view frustum to cull those avatars that are out of view. Since avatar data doesn't need to be present
//       if the avatar is not in view or in the keyhole.
//    2) after culling for view frustum, sort order the avatars by distance, send the closest ones first.
//    3) if we need to rate limit the amount of data we send, we can use a distance weighted "semi-random" function to 
//       determine which avatars are included in the packet stream
//    4) we should optimize the avatar data format to be more compact (100 bytes is pretty wasteful).
void broadcastAvatarData(NodeList* nodeList, sockaddr* nodeAddress) {
    static unsigned char broadcastPacketBuffer[MAX_PACKET_SIZE];
    static unsigned char avatarDataBuffer[MAX_PACKET_SIZE];
    unsigned char* broadcastPacket = (unsigned char*)&broadcastPacketBuffer[0];
    int numHeaderBytes = populateTypeAndVersion(broadcastPacket, PACKET_TYPE_BULK_AVATAR_DATA);
    unsigned char* currentBufferPosition = broadcastPacket + numHeaderBytes;
    int packetLength = currentBufferPosition - broadcastPacket;
    int packetsSent = 0;

    // send back a packet with other active node data to this node
    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
        if (node->getLinkedData() && !socketMatch(nodeAddress, node->getActiveSocket())) {
            unsigned char* avatarDataEndpoint = addNodeToBroadcastPacket((unsigned char*)&avatarDataBuffer[0], &*node);
            int avatarDataLength = avatarDataEndpoint - (unsigned char*)&avatarDataBuffer;

            if (avatarDataLength + packetLength <= MAX_PACKET_SIZE) {
                memcpy(currentBufferPosition, &avatarDataBuffer[0], avatarDataLength);
                packetLength += avatarDataLength;
                currentBufferPosition += avatarDataLength;
            } else {
                packetsSent++;
                //printf("packetsSent=%d packetLength=%d\n", packetsSent, packetLength);
                nodeList->getNodeSocket()->send(nodeAddress, broadcastPacket, currentBufferPosition - broadcastPacket);
                
                // reset the packet
                currentBufferPosition = broadcastPacket + numHeaderBytes;
                packetLength = currentBufferPosition - broadcastPacket;
                
                // copy the avatar that didn't fit into the next packet
                memcpy(currentBufferPosition, &avatarDataBuffer[0], avatarDataLength);
                packetLength += avatarDataLength;
                currentBufferPosition += avatarDataLength;
            }
        }
    }
    packetsSent++;
    //printf("packetsSent=%d packetLength=%d\n", packetsSent, packetLength);
    nodeList->getNodeSocket()->send(nodeAddress, broadcastPacket, currentBufferPosition - broadcastPacket);
}
コード例 #26
0
ファイル: DomainServer.cpp プロジェクト: heracek/hifi
bool DomainServer::checkInWithUUIDMatchesExistingNode(sockaddr* nodePublicSocket,
                                                      sockaddr* nodeLocalSocket,
                                                      const uchar* checkInData) {
    // pull the UUID passed with the check in
    QUuid checkInUUID = QUuid::fromRfc4122(QByteArray((const char*) checkInData + numBytesForPacketHeader(checkInData) +
                                                      sizeof(NODE_TYPE),
                                                      NUM_BYTES_RFC4122_UUID));
    
    NodeList* nodeList = NodeList::getInstance();
    
    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
        if (node->getLinkedData()
            && socketMatch(node->getPublicSocket(), nodePublicSocket)
            && socketMatch(node->getLocalSocket(), nodeLocalSocket)
            && ((Assignment*) node->getLinkedData())->getUUID() == checkInUUID) {
            // this is a matching existing node if the public socket, local socket, and UUID match
            return true;
        }
    }
    
    return false;
}
コード例 #27
0
// This method is called when the edit packet layer has determined that it has a fully formed packet destined for
// a known nodeID. However, we also want to handle the case where the 
void VoxelEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned char* buffer, ssize_t length) {
    NodeList* nodeList = NodeList::getInstance();
    for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
        // only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
        if (node->getType() == NODE_TYPE_VOXEL_SERVER &&
            ((node->getUUID() == nodeUUID) || (nodeUUID.isNull()))) {
            if (nodeList->getNodeActiveSocketOrPing(&(*node))) {
                sockaddr* nodeAddress = node->getActiveSocket();
                queuePacketForSending(*nodeAddress, buffer, length);
                
                // debugging output...
                bool wantDebugging = false;
                if (wantDebugging) {
                    int numBytesPacketHeader = numBytesForPacketHeader(buffer);
                    unsigned short int sequence = (*((unsigned short int*)(buffer + numBytesPacketHeader)));
                    uint64_t createdAt = (*((uint64_t*)(buffer + numBytesPacketHeader + sizeof(sequence))));
                    uint64_t queuedAt = usecTimestampNow();
                    uint64_t transitTime = queuedAt - createdAt;

                    const char* messageName;
                    switch (buffer[0]) {
                        case PACKET_TYPE_SET_VOXEL: 
                            messageName = "PACKET_TYPE_SET_VOXEL"; 
                            break;
                        case PACKET_TYPE_SET_VOXEL_DESTRUCTIVE: 
                            messageName = "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE"; 
                            break;
                        case PACKET_TYPE_ERASE_VOXEL: 
                            messageName = "PACKET_TYPE_ERASE_VOXEL"; 
                            break;
                    }
                    printf("VoxelEditPacketSender::queuePacketToNode() queued %s - command to node bytes=%ld sequence=%d transitTimeSoFar=%llu usecs\n",
                        messageName, length, sequence, transitTime);
                }                
            }
        }
    }
}
コード例 #28
0
ファイル: main.cpp プロジェクト: evilbinary/hifi
void handlePacketSend(NodeList* nodeList, 
                      NodeList::iterator& node,
                      VoxelNodeData* nodeData, 
                      int& trueBytesSent, int& truePacketsSent) {
    // If we've got a stats message ready to send, then see if we can piggyback them together
    if (nodeData->stats.isReadyToSend()) {
        // Send the stats message to the client
        unsigned char* statsMessage = nodeData->stats.getStatsMessage();
        int statsMessageLength = nodeData->stats.getStatsMessageLength();

        // If the size of the stats message and the voxel message will fit in a packet, then piggyback them
        if (nodeData->getPacketLength() + statsMessageLength < MAX_PACKET_SIZE) {

            // copy voxel message to back of stats message
            memcpy(statsMessage + statsMessageLength, nodeData->getPacket(), nodeData->getPacketLength());
            statsMessageLength += nodeData->getPacketLength();

            // actually send it
            nodeList->getNodeSocket()->send(node->getActiveSocket(), statsMessage, statsMessageLength);
        } else {
            // not enough room in the packet, send two packets
            nodeList->getNodeSocket()->send(node->getActiveSocket(), statsMessage, statsMessageLength);
            nodeList->getNodeSocket()->send(node->getActiveSocket(),
                                            nodeData->getPacket(), nodeData->getPacketLength());
        }
    } else {
        // just send the voxel packet
        nodeList->getNodeSocket()->send(node->getActiveSocket(),
                                        nodeData->getPacket(), nodeData->getPacketLength());
    }
    // remember to track our stats
    nodeData->stats.packetSent(nodeData->getPacketLength());
    trueBytesSent += nodeData->getPacketLength();
    truePacketsSent++;
    nodeData->resetVoxelPacket();
}
コード例 #29
0
ファイル: main.cpp プロジェクト: evilbinary/hifi
void *distributeVoxelsToListeners(void *args) {
    
    NodeList* nodeList = NodeList::getInstance();
    timeval lastSendTime;
    
    while (true) {
        gettimeofday(&lastSendTime, NULL);
        
        // enumerate the nodes to send 3 packets to each
        for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
            VoxelNodeData* nodeData = (VoxelNodeData*) node->getLinkedData();

            // Sometimes the node data has not yet been linked, in which case we can't really do anything
            if (nodeData) {
                bool viewFrustumChanged = nodeData->updateCurrentViewFrustum();
                if (::debugVoxelSending) {
                    printf("nodeData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged));
                }
                deepestLevelVoxelDistributor(nodeList, node, nodeData, viewFrustumChanged);
            }
        }
        
        // dynamically sleep until we need to fire off the next set of voxels
        int usecToSleep =  VOXEL_SEND_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&lastSendTime));
        
        if (usecToSleep > 0) {
            usleep(usecToSleep);
        } else {
            if (::debugVoxelSending) {
                std::cout << "Last send took too much time, not sleeping!\n";
            }
        }
    }
    
    pthread_exit(0);
}
コード例 #30
0
ファイル: DomainServer.cpp プロジェクト: jtwigg/hifi
int DomainServer::civetwebRequestHandler(struct mg_connection *connection) {
    const struct mg_request_info* ri = mg_get_request_info(connection);
    
    const char RESPONSE_200[] = "HTTP/1.0 200 OK\r\n\r\n";
    const char RESPONSE_400[] = "HTTP/1.0 400 Bad Request\r\n\r\n";
    
    const char URI_ASSIGNMENT[] = "/assignment";
    const char URI_NODE[] = "/node";
    
    if (strcmp(ri->request_method, "GET") == 0) {
        if (strcmp(ri->uri, "/assignments.json") == 0) {
            // user is asking for json list of assignments
            
            // start with a 200 response
            mg_printf(connection, "%s", RESPONSE_200);
            
            // setup the JSON
            QJsonObject assignmentJSON;
            QJsonObject assignedNodesJSON;
            
            // enumerate the NodeList to find the assigned nodes
            NodeList* nodeList = NodeList::getInstance();
            
            for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
                if (node->getLinkedData()) {
                    // add the node using the UUID as the key
                    QString uuidString = uuidStringWithoutCurlyBraces(node->getUUID());
                    assignedNodesJSON[uuidString] = jsonObjectForNode(&(*node));
                }
            }
            
            assignmentJSON["fulfilled"] = assignedNodesJSON;
            
            QJsonObject queuedAssignmentsJSON;
            
            // add the queued but unfilled assignments to the json
            std::deque<Assignment*>::iterator assignment = domainServerInstance->_assignmentQueue.begin();
            
            while (assignment != domainServerInstance->_assignmentQueue.end()) {
                QJsonObject queuedAssignmentJSON;
                
                QString uuidString = uuidStringWithoutCurlyBraces((*assignment)->getUUID());
                queuedAssignmentJSON[JSON_KEY_TYPE] = QString((*assignment)->getTypeName());
                
                // if the assignment has a pool, add it
                if ((*assignment)->hasPool()) {
                    queuedAssignmentJSON[JSON_KEY_POOL] = QString((*assignment)->getPool());
                }
                
                // add this queued assignment to the JSON
                queuedAssignmentsJSON[uuidString] = queuedAssignmentJSON;
                
                // push forward the iterator to check the next assignment
                assignment++;
            }
            
            assignmentJSON["queued"] = queuedAssignmentsJSON;
            
            // print out the created JSON
            QJsonDocument assignmentDocument(assignmentJSON);
            mg_printf(connection, "%s", assignmentDocument.toJson().constData());
            
            // we've processed this request
            return 1;
        } else if (strcmp(ri->uri, "/nodes.json") == 0) {
            // start with a 200 response
            mg_printf(connection, "%s", RESPONSE_200);
            
            // setup the JSON
            QJsonObject rootJSON;
            QJsonObject nodesJSON;
            
            // enumerate the NodeList to find the assigned nodes
            NodeList* nodeList = NodeList::getInstance();
            
            for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
                // add the node using the UUID as the key
                QString uuidString = uuidStringWithoutCurlyBraces(node->getUUID());
                nodesJSON[uuidString] = jsonObjectForNode(&(*node));
            }
            
            rootJSON["nodes"] = nodesJSON;
            
            // print out the created JSON
            QJsonDocument nodesDocument(rootJSON);
            mg_printf(connection, "%s", nodesDocument.toJson().constData());
            
            // we've processed this request
            return 1;
        }
        
        // not processed, pass to document root
        return 0;
    } else if (strcmp(ri->request_method, "POST") == 0) {
        if (strcmp(ri->uri, URI_ASSIGNMENT) == 0) {
            // return a 200
            mg_printf(connection, "%s", RESPONSE_200);
            // upload the file
            mg_upload(connection, "/tmp");
            
            return 1;
        }
        
        return 0;
    } else if (strcmp(ri->request_method, "DELETE") == 0) {
        // this is a DELETE request
        
        // check if it is for an assignment
        if (memcmp(ri->uri, URI_NODE, strlen(URI_NODE)) == 0) {
            // pull the UUID from the url
            QUuid deleteUUID = QUuid(QString(ri->uri + strlen(URI_NODE) + sizeof('/')));
            
            if (!deleteUUID.isNull()) {
                Node *nodeToKill = NodeList::getInstance()->nodeWithUUID(deleteUUID);
                
                if (nodeToKill) {
                    // start with a 200 response
                    mg_printf(connection, "%s", RESPONSE_200);
                    
                    // we have a valid UUID and node - kill the node that has this assignment
                    NodeList::getInstance()->killNode(nodeToKill);
                    
                    // successfully processed request
                    return 1;
                }
            }
        }
        
        // request not processed - bad request
        mg_printf(connection, "%s", RESPONSE_400);
        
        // this was processed by civetweb
        return 1;
    } else {
        // have mongoose process this request from the document_root
        return 0;
    }
}