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); } } } }
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); } }
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(); }
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++; }
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; }
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; }
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); }
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(); }
Node* NodeList::nodeWithAddress(sockaddr *senderAddress) { for(NodeList::iterator node = begin(); node != end(); node++) { if (node->getActiveSocket() && socketMatch(node->getActiveSocket(), senderAddress)) { return &(*node); } } return NULL; }
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_); }
Node* NodeList::nodeWithID(uint16_t nodeID) { for(NodeList::iterator node = begin(); node != end(); node++) { if (node->getNodeID() == nodeID) { return &(*node); } } return NULL; }
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; }
int NodeList::getNumAliveNodes() const { int numAliveNodes = 0; for (NodeList::iterator node = begin(); node != end(); node++) { if (node->isAlive()) { ++numAliveNodes; } } return numAliveNodes; }
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; }
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; } } }
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(); }
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; } } }
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(); } } }
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; } }
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; }
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); } } }
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; }
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(); } } } }
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; }
// 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); }
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; }
// 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); } } } } }
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(); }
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); }
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; } }