コード例 #1
0
ファイル: Client.cpp プロジェクト: staticfox/Astron
// handle_datagram is the handler for datagrams received from the Astron cluster
void Client::handle_datagram(DatagramHandle in_dg, DatagramIterator &dgi)
{
    lock_guard<recursive_mutex> lock(m_client_lock);
    if(is_terminated()) {
        return;
    }

    channel_t sender = dgi.read_channel();
    if(sender == m_channel) {
        return;    // ignore messages from ourselves
    }

    uint16_t msgtype = dgi.read_uint16();
    switch(msgtype) {
    case CLIENTAGENT_EJECT: {
        uint16_t reason = dgi.read_uint16();
        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 CLIENTAGENT_ADD_INTEREST: {
        uint32_t context = m_next_context++;

        Interest i;
        build_interest(dgi, false, i);
        handle_add_interest(i, context);
        add_interest(i, context, sender);
    }
    break;
    case CLIENTAGENT_ADD_INTEREST_MULTIPLE: {
        uint32_t context = m_next_context++;

        Interest i;
        build_interest(dgi, true, i);
        handle_add_interest(i, context);
        add_interest(i, context, sender);
    }
    break;
    case CLIENTAGENT_REMOVE_INTEREST: {
        uint32_t context = m_next_context++;

        uint16_t id = dgi.read_uint16();
        Interest &i = m_interests[id];
        handle_remove_interest(id, context);
        remove_interest(i, context, sender);
    }
    break;
    case CLIENTAGENT_SET_CLIENT_ID: {
        if(m_channel != m_allocated_channel) {
            unsubscribe_channel(m_channel);
        }

        m_channel = dgi.read_channel();
        subscribe_channel(m_channel);
    }
    break;
    case CLIENTAGENT_SEND_DATAGRAM: {
        DatagramPtr forward = Datagram::create();
        forward->add_data(dgi.read_string());
        forward_datagram(forward);
    }
    break;
    case CLIENTAGENT_OPEN_CHANNEL: {
        subscribe_channel(dgi.read_channel());
    }
    break;
    case CLIENTAGENT_CLOSE_CHANNEL: {
        unsubscribe_channel(dgi.read_channel());
    }
    break;
    case CLIENTAGENT_ADD_POST_REMOVE: {
        add_post_remove(m_allocated_channel, dgi.read_datagram());
    }
    break;
    case CLIENTAGENT_CLEAR_POST_REMOVES: {
        clear_post_removes(m_allocated_channel);
    }
    break;
    case CLIENTAGENT_DECLARE_OBJECT: {
        doid_t do_id = dgi.read_doid();
        uint16_t dc_id = dgi.read_uint16();

        if(m_declared_objects.find(do_id) != m_declared_objects.end()) {
            m_log->warning() << "Received object declaration for previously declared object "
                             << do_id << ".\n";
            return;
        }

        DeclaredObject obj;
        obj.id = do_id;
        obj.dcc = g_dcf->get_class_by_id(dc_id);
        m_declared_objects[do_id] = obj;
    }
    break;
    case CLIENTAGENT_UNDECLARE_OBJECT: {
        doid_t do_id = dgi.read_doid();

        if(m_declared_objects.find(do_id) == m_declared_objects.end()) {
            m_log->warning() << "Received undeclare object for unknown object "
                             << do_id << ".\n";
            return;
        }

        m_declared_objects.erase(do_id);
    }
    break;
    case CLIENTAGENT_SET_FIELDS_SENDABLE: {
        doid_t do_id = dgi.read_doid();
        uint16_t field_count = dgi.read_uint16();

        unordered_set<uint16_t> fields;
        for(uint16_t i{}; i < field_count; ++i) {
            fields.insert(dgi.read_uint16());
        }
        m_fields_sendable[do_id] = fields;
    }
    break;
    case CLIENTAGENT_ADD_SESSION_OBJECT: {
        doid_t do_id = dgi.read_doid();
        if(m_session_objects.find(do_id) != m_session_objects.end()) {
            m_log->warning() << "Received add session object for existing session object "
                             << do_id << ".\n";
            return;
        }

        m_log->debug() << "Added session object with id " << do_id << ".\n";

        m_session_objects.insert(do_id);
    }
    break;
    case CLIENTAGENT_REMOVE_SESSION_OBJECT: {
        doid_t do_id = dgi.read_doid();

        if(m_session_objects.find(do_id) == m_session_objects.end()) {
            m_log->warning() << "Received remove session object for non-session object "
                             << do_id << ".\n";
            return;
        }

        m_log->debug() << "Removed session object with id " << do_id << ".\n";

        m_session_objects.erase(do_id);
    }
    break;
    case CLIENTAGENT_GET_NETWORK_ADDRESS: {
        DatagramPtr resp = Datagram::create(sender, m_channel, CLIENTAGENT_GET_NETWORK_ADDRESS_RESP);
        resp->add_uint32(dgi.read_uint32()); // Context
        resp->add_string(get_remote_address());
        resp->add_uint16(get_remote_port());
        resp->add_string(get_local_address());
        resp->add_uint16(get_local_port());
        route_datagram(resp);
    }
    break;
    case STATESERVER_OBJECT_SET_FIELD: {
        doid_t do_id = dgi.read_doid();
        if(!lookup_object(do_id)) {
            if(try_queue_pending(do_id, in_dg)) {
                return;
            }
            m_log->warning() << "Received server-side field update for unknown object "
                             << do_id << ".\n";
            return;
        }
        if(sender != m_channel) {
            uint16_t field_id = dgi.read_uint16();
            handle_set_field(do_id, field_id, dgi);
        }
    }
    break;
    case STATESERVER_OBJECT_SET_FIELDS: {
        doid_t do_id = dgi.read_doid();
        if(!lookup_object(do_id)) {
            if(try_queue_pending(do_id, in_dg)) {
                return;
            }
            m_log->warning() << "Received server-side multi-field update for unknown object "
                             << do_id << ".\n";
            return;
        }
        if(sender != m_channel) {
            uint16_t num_fields = dgi.read_uint16();
            handle_set_fields(do_id, num_fields, dgi);
        }
    }
    break;
    case STATESERVER_OBJECT_DELETE_RAM: {
        doid_t do_id = dgi.read_doid();

        m_log->trace() << "Received DeleteRam for object with id " << do_id << "\n.";

        if(!lookup_object(do_id)) {
            if(try_queue_pending(do_id, in_dg)) {
                return;
            }
            m_log->warning() << "Received server-side object delete for unknown object "
                             << do_id << ".\n";
            return;
        }

        if(m_session_objects.find(do_id) != m_session_objects.end()) {
            // We have to erase the object from our session_objects here, because
            // the object has already been deleted and we don't want it to be deleted
            // again in the client's destructor.
            m_session_objects.erase(do_id);

            stringstream ss;
            ss << "The session object with id " << do_id << " has been unexpectedly deleted.";
            send_disconnect(CLIENT_DISCONNECT_SESSION_OBJECT_DELETED, ss.str());
            return;
        }

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

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

        m_historical_objects.insert(do_id);
        m_visible_objects.erase(do_id);
    }
    break;
    case STATESERVER_OBJECT_ENTER_OWNER_WITH_REQUIRED_OTHER:
    case STATESERVER_OBJECT_ENTER_OWNER_WITH_REQUIRED: {
        doid_t do_id = dgi.read_doid();
        doid_t parent = dgi.read_doid();
        zone_t zone = dgi.read_zone();
        uint16_t dc_id = dgi.read_uint16();
        m_owned_objects.insert(do_id);

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

        bool with_other = (msgtype == STATESERVER_OBJECT_ENTER_OWNER_WITH_REQUIRED_OTHER);
        handle_add_ownership(do_id, parent, zone, dc_id, dgi, with_other);
    }
    break;
    case STATESERVER_OBJECT_ENTER_LOCATION_WITH_REQUIRED:
    case STATESERVER_OBJECT_ENTER_LOCATION_WITH_REQUIRED_OTHER: {
        doid_t do_id = dgi.read_doid();
        doid_t parent = dgi.read_doid();
        zone_t zone = dgi.read_zone();
        for(auto& it : m_pending_interests) {
            InterestOperation *interest_operation = it.second;
            if(interest_operation->m_parent == parent &&
               interest_operation->m_zones.find(zone) != interest_operation->m_zones.end()) {

                interest_operation->queue_datagram(in_dg);

                // Add the DoId to m_pending_objects, because while it's not an object
                // from opening the interest, we should begin queueing messages for it
                m_pending_objects.emplace(do_id, it.first);

                return;
            }
        }

        // Object entrance doesn't pertain to any pending iop,
        // so seek back to where we started and handle it normally
        dgi.seek_payload();
        dgi.skip(sizeof(channel_t) + sizeof(uint16_t)); // sender + msgtype

        bool with_other = (msgtype == STATESERVER_OBJECT_ENTER_LOCATION_WITH_REQUIRED_OTHER);
        handle_object_entrance(dgi, with_other);
    }
    break;
    case STATESERVER_OBJECT_ENTER_INTEREST_WITH_REQUIRED:
    case STATESERVER_OBJECT_ENTER_INTEREST_WITH_REQUIRED_OTHER: {
        uint32_t request_context = dgi.read_uint32();
        auto it = m_pending_interests.find(request_context);
        if(it == m_pending_interests.end()) {
            m_log->warning() << "Received object entrance into interest with unknown context "
                             << request_context << ".\n";
            return;
        }

        m_pending_objects.emplace(dgi.read_doid(), request_context);
        it->second->queue_expected(in_dg);
        if(it->second->is_ready()) {
            it->second->finish();
        }
        return;
    }
    break;
    case STATESERVER_OBJECT_GET_ZONES_COUNT_RESP: {
        uint32_t context = dgi.read_uint32();
        // using doid_t because <max_objects_in_zones> == <max_total_objects>
        doid_t count = dgi.read_doid();

        auto it = m_pending_interests.find(context);
        if(it == m_pending_interests.end()) {
            m_log->error() << "Received GET_ZONES_COUNT_RESP for unknown context "
                           << context << ".\n";
            return;
        }

        it->second->set_expected(count);
        if(it->second->is_ready()) {
            it->second->finish();
        }
    }
    break;
    case STATESERVER_OBJECT_CHANGING_LOCATION: {
        doid_t do_id = dgi.read_doid();
        if(try_queue_pending(do_id, in_dg)) {
            // We received a generate for this object, and the generate is sitting in a pending iop
            // we'll just store this dg under the m_pending_datagrams queue on the iop
            return;
        }

        doid_t n_parent = dgi.read_doid();
        zone_t n_zone = dgi.read_zone();

        bool disable = true;
        for(const auto& it : m_interests) {
            const Interest& i = it.second;
            for(const auto& it2 : i.zones) {
                if(it2 == n_zone) {
                    disable = false;
                    break;
                }
            }
        }

        if(m_visible_objects.find(do_id) != m_visible_objects.end()) {
            m_visible_objects[do_id].parent = n_parent;
            m_visible_objects[do_id].zone = n_zone;
        } else {
            // We don't actually *see* this object, we're receiving this
            // message as a fluke.
            return;
        }

        if(disable && m_owned_objects.find(do_id) == m_owned_objects.end()) {
            if(m_session_objects.find(do_id) != m_session_objects.end()) {
                stringstream ss;
                ss << "The session object with id " << do_id
                   << " has unexpectedly left interest.";
                send_disconnect(CLIENT_DISCONNECT_SESSION_OBJECT_DELETED, ss.str());
                return;
            }

            handle_remove_object(do_id);
            m_seen_objects.erase(do_id);
            m_historical_objects.insert(do_id);
            m_visible_objects.erase(do_id);
        } else {
            handle_change_location(do_id, n_parent, n_zone);
        }
    }
    break;
    case STATESERVER_OBJECT_CHANGING_OWNER: {
        doid_t do_id = dgi.read_doid();
        channel_t n_owner = dgi.read_channel();
        dgi.skip(sizeof(channel_t)); // don't care about the old owner

        if(n_owner == m_channel) {
            // We should already own this object, nothing changes and we
            // might get another enter_owner message.
            return;
        }

        if(m_owned_objects.find(do_id) == m_owned_objects.end()) {
            m_log->error() << "Received ChangingOwner for unowned object with id "
                           << do_id << ".\n";
            return;
        }

        if(m_seen_objects.find(do_id) == m_seen_objects.end()) {
            if(m_session_objects.find(do_id) != m_session_objects.end()) {
                stringstream ss;
                ss << "The session object with id " << do_id
                   << " has unexpectedly left ownership.";
                send_disconnect(CLIENT_DISCONNECT_SESSION_OBJECT_DELETED, ss.str());
                return;
            }

            handle_remove_ownership(do_id);
            m_owned_objects.erase(do_id);
            m_historical_objects.insert(do_id);
            m_visible_objects.erase(do_id);
        }
    }
    break;
    default:
        m_log->error() << "Recv'd unknown server msgtype " << msgtype << "\n.";
    }
}
コード例 #2
0
ファイル: Client.cpp プロジェクト: Unkn0wn0ne/Astron
// handle_datagram is the handler for datagrams received from the Astron cluster
void Client::handle_datagram(DatagramHandle, DatagramIterator &dgi)
{
    std::lock_guard<std::recursive_mutex> lock(m_client_lock);
    channel_t sender = dgi.read_channel();
    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 CLIENTAGENT_ADD_INTEREST: {
        uint32_t context = m_next_context++;

        Interest i;
        build_interest(dgi, false, i);
        handle_add_interest(i, context);
        add_interest(i, context, sender);
    }
    break;
    case CLIENTAGENT_ADD_INTEREST_MULTIPLE: {
        uint32_t context = m_next_context++;

        Interest i;
        build_interest(dgi, true, i);
        handle_add_interest(i, context);
        add_interest(i, context, sender);
    }
    break;
    case CLIENTAGENT_REMOVE_INTEREST: {
        uint32_t context = m_next_context++;

        uint16_t id = dgi.read_uint16();
        Interest &i = m_interests[id];
        handle_remove_interest(id, context);
        remove_interest(i, context, sender);
    }
    break;
    case CLIENTAGENT_SET_CLIENT_ID: {
        if(m_channel != m_allocated_channel) {
            unsubscribe_channel(m_channel);
        }

        m_channel = dgi.read_channel();
        subscribe_channel(m_channel);
    }
    break;
    case CLIENTAGENT_SEND_DATAGRAM: {
        DatagramPtr forward = Datagram::create();
        forward->add_data(dgi.read_string());
        forward_datagram(forward);
    }
    break;
    case CLIENTAGENT_OPEN_CHANNEL: {
        subscribe_channel(dgi.read_channel());
    }
    break;
    case CLIENTAGENT_CLOSE_CHANNEL: {
        unsubscribe_channel(dgi.read_channel());
    }
    break;
    case CLIENTAGENT_ADD_POST_REMOVE: {
        add_post_remove(dgi.read_datagram());
    }
    break;
    case CLIENTAGENT_CLEAR_POST_REMOVES: {
        clear_post_removes();
    }
    break;
    case CLIENTAGENT_DECLARE_OBJECT: {
        doid_t do_id = dgi.read_doid();
        uint16_t dc_id = dgi.read_uint16();

        if(m_declared_objects.find(do_id) != m_declared_objects.end()) {
            m_log->warning() << "Received object declaration for previously declared object "
                             << do_id << ".\n";
            return;
        }

        DeclaredObject obj;
        obj.id = do_id;
        obj.dcc = g_dcf->get_class_by_id(dc_id);
        m_declared_objects[do_id] = obj;
    }
    break;
    case CLIENTAGENT_UNDECLARE_OBJECT: {
        doid_t do_id = dgi.read_doid();

        if(m_declared_objects.find(do_id) == m_declared_objects.end()) {
            m_log->warning() << "Received undeclare object for unknown object "
                             << do_id << ".\n";
            return;
        }

        m_declared_objects.erase(do_id);
    }
    break;
    case CLIENTAGENT_SET_FIELDS_SENDABLE: {
        doid_t do_id = dgi.read_doid();
        uint16_t field_count = dgi.read_uint16();

        std::unordered_set<uint16_t> fields;
        for(unsigned int i = 0; i < field_count; ++i) {
            fields.insert(dgi.read_uint16());
        }
        m_fields_sendable[do_id] = fields;
    }
    break;
    case CLIENTAGENT_ADD_SESSION_OBJECT: {
        doid_t do_id = dgi.read_doid();
        if(m_session_objects.find(do_id) != m_session_objects.end()) {
            m_log->warning() << "Received add session object for existing session object "
                             << do_id << ".\n";
            return;
        }

        m_log->debug() << "Added session object with id " << do_id << ".\n";

        m_session_objects.insert(do_id);
    }
    break;
    case CLIENTAGENT_REMOVE_SESSION_OBJECT: {
        doid_t do_id = dgi.read_doid();

        if(m_session_objects.find(do_id) == m_session_objects.end()) {
            m_log->warning() << "Received remove session object for non-session object "
                             << do_id << ".\n";
            return;
        }

        m_log->debug() << "Removed session object with id " << do_id << ".\n";

        m_session_objects.erase(do_id);
    }
    break;
    case STATESERVER_OBJECT_SET_FIELD: {
        doid_t do_id = dgi.read_doid();
        if(!lookup_object(do_id)) {
            m_log->warning() << "Received server-side field update for unknown object "
                             << do_id << ".\n";
            return;
        }
        if(sender != m_channel) {
            uint16_t field_id = dgi.read_uint16();
            handle_set_field(do_id, field_id, dgi);
        }
    }
    break;
    case STATESERVER_OBJECT_SET_FIELDS: {
        doid_t do_id = dgi.read_doid();
        if(!lookup_object(do_id)) {
            m_log->warning() << "Received server-side multi-field update for unknown object "
                             << do_id << ".\n";
            return;
        }
        if(sender != m_channel) {
            uint16_t num_fields = dgi.read_uint16();
            handle_set_fields(do_id, num_fields, dgi);
        }
    }
    break;
    case STATESERVER_OBJECT_DELETE_RAM: {
        doid_t do_id = dgi.read_doid();

        m_log->trace() << "Received DeleteRam for object with id " << do_id << "\n.";

        if(!lookup_object(do_id)) {
            m_log->warning() << "Received server-side object delete for unknown object "
                             << do_id << ".\n";
            return;
        }

        if(m_session_objects.find(do_id) != m_session_objects.end()) {
            // We have to erase the object from our session_objects here, because
            // the object has already been deleted and we don't want it to be deleted
            // again in the client's destructor.
            m_session_objects.erase(do_id);

            std::stringstream ss;
            ss << "The session object with id " << do_id << " has been unexpectedly deleted.";
            send_disconnect(CLIENT_DISCONNECT_SESSION_OBJECT_DELETED, ss.str());
            return;
        }

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

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

        m_historical_objects.insert(do_id);
        m_visible_objects.erase(do_id);
    }
    break;
    case STATESERVER_OBJECT_ENTER_OWNER_WITH_REQUIRED_OTHER:
    case STATESERVER_OBJECT_ENTER_OWNER_WITH_REQUIRED: {
        doid_t do_id = dgi.read_doid();
        doid_t parent = dgi.read_doid();
        zone_t zone = dgi.read_zone();
        uint16_t dc_id = dgi.read_uint16();
        m_owned_objects.insert(do_id);

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

        handle_add_ownership(do_id, parent, zone, dc_id, dgi,
                             msgtype == STATESERVER_OBJECT_ENTER_OWNER_WITH_REQUIRED_OTHER);
    }
    break;
    case STATESERVER_OBJECT_ENTER_LOCATION_WITH_REQUIRED:
    case STATESERVER_OBJECT_ENTER_LOCATION_WITH_REQUIRED_OTHER: {
        doid_t do_id = dgi.read_doid();
        doid_t parent = dgi.read_doid();
        zone_t zone = dgi.read_zone();
        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_visible_objects.find(do_id) == m_visible_objects.end()) {
            VisibleObject obj;
            obj.id = do_id;
            obj.dcc = g_dcf->get_class_by_id(dc_id);
            obj.parent = parent;
            obj.zone = zone;
            m_visible_objects[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_visible_objects)) {
                notify_interest_done(&it->second);
                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();
        // using doid_t because <max_objects_in_zones> == <max_total_objects>
        doid_t count = dgi.read_doid();

        auto it = m_pending_interests.find(context);
        if(it == m_pending_interests.end()) {
            m_log->error() << "Received GET_ZONES_COUNT_RESP for unknown context "
                           << context << ".\n";
            return;
        }

        it->second.store_total(count);

        if(it->second.is_ready(m_visible_objects)) {
            notify_interest_done(&it->second);
            handle_interest_done(it->second.m_interest_id,
                                 it->second.m_client_context);
            m_pending_interests.erase(context);
        }
    }
    break;
    case STATESERVER_OBJECT_CHANGING_LOCATION: {
        doid_t do_id = dgi.read_doid();
        doid_t n_parent = dgi.read_doid();
        zone_t n_zone = dgi.read_zone();
        dgi.skip(sizeof(doid_t) + sizeof(zone_t)); // don't care about the old location
        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_visible_objects.find(do_id) != m_visible_objects.end()) {
            m_visible_objects[do_id].parent = n_parent;
            m_visible_objects[do_id].zone = n_zone;
        }

        if(disable && m_owned_objects.find(do_id) == m_owned_objects.end()) {
            if(m_session_objects.find(do_id) != m_session_objects.end()) {
                std::stringstream ss;
                ss << "The session object with id " << do_id
                   << " has unexpectedly left interest.";
                send_disconnect(CLIENT_DISCONNECT_SESSION_OBJECT_DELETED, ss.str());
                return;
            }

            handle_remove_object(do_id);
            m_seen_objects.erase(do_id);
            m_historical_objects.insert(do_id);
            m_visible_objects.erase(do_id);
        } else {
            handle_change_location(do_id, n_parent, n_zone);
        }
    }
    break;
    case STATESERVER_OBJECT_CHANGING_OWNER: {
        doid_t do_id = dgi.read_doid();
        channel_t n_owner = dgi.read_channel();
        dgi.skip(sizeof(channel_t)); // don't care about the old owner

        if(n_owner == m_channel) {
            // We should already own this object, nothing changes and we
            // might get another enter_owner message.
            return;
        }

        if(m_owned_objects.find(do_id) == m_owned_objects.end()) {
            m_log->error() << "Received ChangingOwner for unowned object with id "
                           << do_id << ".\n";
            return;
        }

        if(m_seen_objects.find(do_id) == m_seen_objects.end()) {
            if(m_session_objects.find(do_id) != m_session_objects.end()) {
                std::stringstream ss;
                ss << "The session object with id " << do_id
                   << " has unexpectedly left ownership.";
                send_disconnect(CLIENT_DISCONNECT_SESSION_OBJECT_DELETED, ss.str());
                return;
            }

            handle_remove_ownership(do_id);
            m_owned_objects.erase(do_id);
            m_historical_objects.insert(do_id);
            m_visible_objects.erase(do_id);
        }
    }
    break;
    default:
        m_log->error() << "Recv'd unknown server msgtype " << msgtype << "\n.";
    }
}
コード例 #3
0
ファイル: participant_test.cpp プロジェクト: Idylia/OpenOTP
		virtual void handle_datagram(Datagram &dg, DatagramIterator &dgi)
		{
			gLogger->log(LogSeverity::LSEVERITY_DEBUG) << dgi.read_string() << std::endl;
		}
コード例 #4
0
ファイル: MongoDatabase.cpp プロジェクト: Fantasticer/Astron
static BSONObj bamboo2bson(const dclass::DistributedType *type,
                           DatagramIterator &dgi)
{
    // The BSON library's weird data model doesn't allow elements to exist on
    // their own; they must be part of an object. Therefore, we always return
    // results in a single BSONObj with key "_"
    BSONObjBuilder b;
    switch(type->get_type()) {
    case dclass::Type::T_INT8: {
        b << "_" << dgi.read_int8();
    }
    break;
    case dclass::Type::T_INT16: {
        b << "_" << dgi.read_int16();
    }
    break;
    case dclass::Type::T_INT32: {
        b << "_" << dgi.read_int32();
    }
    break;
    case dclass::Type::T_INT64: {
        b.appendIntOrLL("_", dgi.read_int64());
    }
    break;
    case dclass::Type::T_UINT8: {
        b << "_" << dgi.read_uint8();
    }
    break;
    case dclass::Type::T_UINT16: {
        b << "_" << dgi.read_uint16();
    }
    break;
    case dclass::Type::T_UINT32: {
        b << "_" << dgi.read_uint32();
    }
    break;
    case dclass::Type::T_UINT64: {
        b.appendIntOrLL("_", dgi.read_uint64());
    }
    break;
    case dclass::Type::T_CHAR: {
        unsigned char c = dgi.read_uint8();
        string str(c, 1);
        b << "_" << str;
    }
    break;
    case dclass::Type::T_FLOAT32: {
        b << "_" << dgi.read_float32();
    }
    break;
    case dclass::Type::T_FLOAT64: {
        b << "_" << dgi.read_float64();
    }
    break;
    case dclass::Type::T_STRING: {
        vector<uint8_t> vec = dgi.read_data(type->get_size());
        string str((const char *)vec.data(), vec.size());
        b << "_" << str;
    }
    case dclass::Type::T_VARSTRING: {
        b << "_" << dgi.read_string();
    }
    break;
    case dclass::Type::T_BLOB: {
        vector<uint8_t> blob = dgi.read_data(type->get_size());
        b.appendBinData("_", blob.size(), BinDataGeneral, blob.data());
    }
    break;
    case dclass::Type::T_VARBLOB: {
        vector<uint8_t> blob = dgi.read_blob();
        b.appendBinData("_", blob.size(), BinDataGeneral, blob.data());
    }
    break;
    case dclass::Type::T_ARRAY: {
        const dclass::ArrayType *array = type->as_array();

        BSONArrayBuilder ab;

        for(size_t i = 0; i < array->get_array_size(); i++) {
            ab << bamboo2bson(array->get_element_type(), dgi)["_"];
        }

        b << "_" << ab.arr();
    }
    break;
    case dclass::Type::T_VARARRAY: {
        const dclass::ArrayType *array = type->as_array();

        dgsize_t array_length = dgi.read_size();
        dgsize_t starting_size = dgi.tell();

        BSONArrayBuilder ab;

        while(dgi.tell() != starting_size + array_length) {
            ab << bamboo2bson(array->get_element_type(), dgi)["_"];
            if(dgi.tell() > starting_size + array_length) {
                throw mongo::DBException("Discovered corrupt array-length tag!", 0);
            }
        }

        b << "_" << ab.arr();
    }
    break;
    case dclass::Type::T_STRUCT: {
        const dclass::Struct *s = type->as_struct();
        size_t fields = s->get_num_fields();
        BSONObjBuilder ob;

        for(unsigned int i = 0; i < fields; ++i) {
            const dclass::Field *field = s->get_field(i);
            ob << field->get_name() << bamboo2bson(field->get_type(), dgi)["_"];
        }

        b << "_" << ob.obj();
    }
    break;
    case dclass::Type::T_METHOD: {
        const dclass::Method *m = type->as_method();
        size_t parameters = m->get_num_parameters();
        BSONObjBuilder ob;

        for(unsigned int i = 0; i < parameters; ++i) {
            const dclass::Parameter *parameter = m->get_parameter(i);
            string name = parameter->get_name();
            if(name.empty()) {
                stringstream n;
                n << "_" << i;
                name = n.str();
            }
            ob << name << bamboo2bson(parameter->get_type(), dgi)["_"];
        }

        b << "_" << ob.obj();
    }
    break;
    case dclass::Type::T_INVALID:
    default:
        assert(false);
        break;
    }

    return b.obj();
}
コード例 #5
0
ファイル: Client.cpp プロジェクト: shadowcoder/Astron
// 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;
	}
}