Esempio n. 1
0
void MDNetworkParticipant::network_datagram(Datagram &dg)
{
	DatagramIterator dgi(dg);
	unsigned short channels = dgi.read_uint8();
	if(channels == 1 && dgi.read_uint64() == CONTROL_MESSAGE)
	{
		unsigned short msg_type = dgi.read_uint16();
		switch(msg_type)
		{
			case CONTROL_ADD_CHANNEL:
			{
				subscribe_channel(dgi.read_uint64());
			}
			break;
			case CONTROL_REMOVE_CHANNEL:
			{
				unsubscribe_channel(dgi.read_uint64());
			}
			break;
			case CONTROL_ADD_RANGE:
			{
				channel_t lo = dgi.read_uint64();
				channel_t hi = dgi.read_uint64();
				subscribe_range(lo, hi);
			}
			break;
			case CONTROL_REMOVE_RANGE:
			{
				channel_t lo = dgi.read_uint64();
				channel_t hi = dgi.read_uint64();
				unsubscribe_range(lo, hi);
			}
			break;
			case CONTROL_ADD_POST_REMOVE:
			{
				add_post_remove(dgi.read_string());
			}
			break;
			case CONTROL_CLEAR_POST_REMOVE:
			{
				clear_post_removes();
			}
			break;
			default:
				logger().error() << "MDNetworkParticipant got unknown control message, type : " << msg_type << std::endl;
		}
		return;
	}
	send(dg);
}
Esempio n. 2
0
void ChannelMap::unsubscribe_all(ChannelSubscriber* p)
{
    std::lock_guard<std::recursive_mutex> guard(m_lock);

    // Unsubscribe from indivually subscribed channels
    auto channels = std::set<channel_t>(p->channels());
    for(auto it = channels.begin(); it != channels.end(); ++it) {
        channel_t channel = *it;
        unsubscribe_channel(p, channel);
    }

    // Unsubscribe from subscribed channel ranges
    auto ranges = boost::icl::interval_set<channel_t>(p->ranges());
    for(auto it = ranges.begin(); it != ranges.end(); ++it) {
        channel_t lower;
        channel_t upper;
        get_closed_bounds(*it, lower, upper);
        unsubscribe_range(p, lower, upper);
    }
}
Esempio n. 3
0
void Client::close_zones(uint32_t parent, const std::unordered_set<uint32_t> &killed_zones)
{
	// Kill off all objects that are in the matched parent/zones:

	std::list<uint32_t> to_remove;
	for(auto it = m_dist_objs.begin(); it != m_dist_objs.end(); ++it)
	{
		if(it->second.parent != parent)
		{
			// Object does not belong to the parent in question; ignore.
			continue;
		}

		if(killed_zones.find(it->second.zone) != killed_zones.end())
		{
			if(m_owned_objects.find(it->second.id) != m_owned_objects.end())
			{
				// Owned objects are always zone-visible. I think.
				// TODO: Is this assumption correct?
				continue;
			}

			handle_remove_object(it->second.id);

			m_seen_objects.erase(it->second.id);
			m_id_history.insert(it->second.id);
			to_remove.push_back(it->second.id);
		}
	}

	for(auto it = to_remove.begin(); it != to_remove.end(); ++it)
	{
		m_dist_objs.erase(*it);
	}

	// Close all of the channels:
	for(auto it = killed_zones.begin(); it != killed_zones.end(); ++it)
	{
		unsubscribe_channel(LOCATION2CHANNEL(parent, *it));
	}
}
Esempio n. 4
0
void MDNetworkParticipant::receive_datagram(DatagramHandle dg)
{
	DatagramIterator dgi(dg);
	uint16_t channels = dgi.read_uint8();
	if(channels == 1 && dgi.read_channel() == CONTROL_MESSAGE)
	{
		uint16_t msg_type = dgi.read_uint16();
		switch(msg_type)
		{
			case CONTROL_ADD_CHANNEL:
			{
				subscribe_channel(dgi.read_channel());
				break;
			}
			case CONTROL_REMOVE_CHANNEL:
			{
				unsubscribe_channel(dgi.read_channel());
				break;
			}
			case CONTROL_ADD_RANGE:
			{
				channel_t lo = dgi.read_channel();
				channel_t hi = dgi.read_channel();
				subscribe_range(lo, hi);
				break;
			}
			case CONTROL_REMOVE_RANGE:
			{
				channel_t lo = dgi.read_channel();
				channel_t hi = dgi.read_channel();
				unsubscribe_range(lo, hi);
				break;
			}
			case CONTROL_ADD_POST_REMOVE:
			{
				add_post_remove(dgi.read_datagram());
				break;
			}
			case CONTROL_CLEAR_POST_REMOVE:
			{
				clear_post_removes();
				break;
			}
			case CONTROL_SET_CON_NAME:
			{
				set_con_name(dgi.read_string());
				break;
			}
			case CONTROL_SET_CON_URL:
			{
				set_con_url(dgi.read_string());
				break;
			}
			default:
				logger().error() << "MDNetworkParticipant got unknown control message, type : "
				                 << msg_type << std::endl;
		}
		return;
	}
	route_datagram(dg);
}
Esempio n. 5
0
// handle_datagram is the handler for datagrams received from the Astron cluster
void Client::handle_datagram(Datagram &dg, DatagramIterator &dgi)
{
	channel_t sender = dgi.read_uint64();
	uint16_t msgtype = dgi.read_uint16();
	switch(msgtype)
	{
		case CLIENTAGENT_EJECT:
		{
			uint16_t reason = dgi.read_uint16();
			std::string error_string = dgi.read_string();
			send_disconnect(reason, error_string);
			return;
		}
		break;
		case CLIENTAGENT_DROP:
		{
			handle_drop();
			return;
		}
		break;
		case CLIENTAGENT_SET_STATE:
		{
			m_state = (ClientState)dgi.read_uint16();
		}
		break;
		case STATESERVER_OBJECT_SET_FIELD:
		{
			uint32_t do_id = dgi.read_uint32();
			if(!lookup_object(do_id))
			{
				m_log->warning() << "Received server-side field update for unknown object " << do_id << std::endl;
				return;
			}
			if(sender != m_channel)
			{
				uint16_t field_id = dgi.read_uint16();
				handle_set_field(do_id, field_id, dgi);
			}
		}
		break;
		case STATESERVER_OBJECT_DELETE_RAM:
		{
			uint32_t do_id = dgi.read_uint32();
			if(!lookup_object(do_id))
			{
				m_log->warning() << "Received server-side object delete for unknown object " << do_id << std::endl;
				return;
			}

			if(m_seen_objects.find(do_id) != m_seen_objects.end())
			{
				m_seen_objects.erase(do_id);
				m_id_history.insert(do_id);
				handle_remove_object(do_id);
			}

			if(m_owned_objects.find(do_id) != m_owned_objects.end())
			{
				m_owned_objects.erase(do_id);
				handle_remove_ownership(do_id);
			}

			m_dist_objs.erase(do_id);
		}
		break;
		case STATESERVER_OBJECT_ENTER_OWNER_WITH_REQUIRED_OTHER:
        case STATESERVER_OBJECT_ENTER_OWNER_WITH_REQUIRED:
		{
			uint32_t do_id = dgi.read_uint32();
			uint32_t parent = dgi.read_uint32();
			uint32_t zone = dgi.read_uint32();
			uint16_t dc_id = dgi.read_uint16();
			m_owned_objects.insert(do_id);

			if(m_dist_objs.find(do_id) == m_dist_objs.end())
			{
				VisibleObject obj;
				obj.id = do_id;
				obj.parent = parent;
				obj.zone = zone;
				obj.dcc = g_dcf->get_class(dc_id);
				m_dist_objs[do_id] = obj;
			}

			handle_add_ownership(do_id, parent, zone, dc_id, dgi, true);
		}
		break;
		case CLIENTAGENT_SET_CLIENT_ID:
		{
			if(m_channel != m_allocated_channel)
			{
				unsubscribe_channel(m_channel);
			}

			m_channel = dgi.read_uint64();
			subscribe_channel(m_channel);
		}
		break;
		case CLIENTAGENT_SEND_DATAGRAM:
		{
			Datagram forward;
			forward.add_data(dgi.read_string());
			send_datagram(forward);
		}
		break;
		case CLIENTAGENT_OPEN_CHANNEL:
		{
			subscribe_channel(dgi.read_uint64());
		}
		break;
		case CLIENTAGENT_CLOSE_CHANNEL:
		{
			unsubscribe_channel(dgi.read_uint64());
		}
		break;
		case CLIENTAGENT_ADD_POST_REMOVE:
		{
			add_post_remove(dgi.read_string());
		}
		break;
		case CLIENTAGENT_CLEAR_POST_REMOVES:
		{
			clear_post_removes();
		}
		break;
		case STATESERVER_OBJECT_ENTER_LOCATION_WITH_REQUIRED:
		case STATESERVER_OBJECT_ENTER_LOCATION_WITH_REQUIRED_OTHER:
		{
			uint32_t do_id = dgi.read_uint32();
			uint32_t parent = dgi.read_uint32();
			uint32_t zone = dgi.read_uint32();
			uint16_t dc_id = dgi.read_uint16();
			if(m_owned_objects.find(do_id) != m_owned_objects.end() ||
			        m_seen_objects.find(do_id) != m_seen_objects.end())
			{
				return;
			}
			if(m_dist_objs.find(do_id) == m_dist_objs.end())
			{
				VisibleObject obj;
				obj.id = do_id;
				obj.dcc = g_dcf->get_class(dc_id);
				obj.parent = parent;
				obj.zone = zone;
				m_dist_objs[do_id] = obj;
			}
			m_seen_objects.insert(do_id);

			handle_add_object(do_id, parent, zone, dc_id, dgi,
			                  msgtype == STATESERVER_OBJECT_ENTER_LOCATION_WITH_REQUIRED_OTHER);

			// TODO: This is a tad inefficient as it checks every pending interest.
			// In practice, there shouldn't be many add-interest operations active
			// at once, however.
			std::list<uint32_t> deferred_deletes;
			for(auto it = m_pending_interests.begin(); it != m_pending_interests.end(); ++it)
			{
				if(it->second->is_ready(m_dist_objs))
				{
					handle_interest_done(it->second->m_interest_id, it->second->m_client_context);
					deferred_deletes.push_back(it->first);
				}
			}
			for(auto it = deferred_deletes.begin(); it != deferred_deletes.end(); ++it)
			{
				m_pending_interests.erase(*it);
			}
		}
		break;
		case STATESERVER_OBJECT_GET_ZONES_COUNT_RESP:
		{
			uint32_t context = dgi.read_uint32();
			uint32_t count = dgi.read_uint32();

			if(m_pending_interests.find(context) == m_pending_interests.end())
			{
				m_log->error() << "Received GET_ZONES_COUNT_RESP for unknown context "
				               << context << std::endl;
				return;
			}

			m_pending_interests[context]->store_total(count);

			if(m_pending_interests[context]->is_ready(m_dist_objs))
			{
				handle_interest_done(m_pending_interests[context]->m_interest_id,
				                     m_pending_interests[context]->m_client_context);
				m_pending_interests.erase(context);
			}
		}
		break;
		case STATESERVER_OBJECT_CHANGING_LOCATION:
		{
			uint32_t do_id = dgi.read_uint32();
			uint32_t n_parent = dgi.read_uint32();
			uint32_t n_zone = dgi.read_uint32();
			dgi.read_uint32(); // Old parent; we don't care about this.
			dgi.read_uint32(); // Old zone; we don't care about this.
			bool disable = true;
			for(auto it = m_interests.begin(); it != m_interests.end(); ++it)
			{
				Interest &i = it->second;
				for(auto it2 = i.zones.begin(); it2 != i.zones.end(); ++it2)
				{
					if(*it2 == n_zone)
					{
						disable = false;
						break;
					}
				}
			}

			if(m_dist_objs.find(do_id) != m_dist_objs.end())
			{
				m_dist_objs[do_id].parent = n_parent;
				m_dist_objs[do_id].zone = n_zone;
			}

			if(disable && m_owned_objects.find(do_id) == m_owned_objects.end())
			{
				handle_remove_object(do_id);
				m_seen_objects.erase(do_id);
				m_dist_objs.erase(do_id);
			}
			else
			{
				handle_change_location(do_id, n_parent, n_zone);
			}
		}
		break;
		default:
			m_log->error() << "Recv'd unk server msgtype " << msgtype << std::endl;
	}
}