def __init__(self, message_handler=None, settings=None, message_template=None, message_xml=None): self.context = None self.unpacker = DataUnpacker() self.current_template = None self.current_block = None self.template_dict = TemplateDictionary( message_template=message_template) # allow the settings to be passed in # otherwise, grab the defaults if settings != None: self.settings = settings else: self.settings = Settings() if not message_xml: self.message_xml = MessageDotXML() else: self.message_xml = message_xml # we can skip parsing all the data in a packet if we know it's not being handled # allow the packet_handler to be passed in # otherwise, grab the defaults if message_handler != None: self.message_handler = message_handler elif self.settings.HANDLE_PACKETS: self.message_handler = MessageHandler()
def __init__(self, udp_client = None, settings = None, message_handler = None, message_template = None, message_xml = None): #holds the details of the message, or how the messages should be sent, #built, and read self.packets_in = 0 self.packets_out = 0 self.circuit_manager = CircuitManager() self.data_unpacker = DataUnpacker() #the ID of the packet we most recently received self.receive_packet_id = -1 if udp_client == None: self.udp_client = NetUDPClient() else: self.udp_client = udp_client self.udp_client.start_udp_connection() # allow the settings to be passed in # otherwise, grab the defaults if settings != None: self.settings = settings else: self.settings = Settings() # allow the passing in of message_template.xml as a file handle if not message_template: self.message_template = None else: if isinstance(message_template, file): self.message_template = message_template else: log.warning("%s parameter is expected to be a filehandle, it is a %s. \ Using the embedded message_template.msg" % (message_template, type(message_template))) self.message_template = None if not message_xml: self.message_xml = MessageDotXML() else: self.message_xml = message_xml self.helpers = Helpers() # allow the packet_handler to be passed in # otherwise, grab the defaults if message_handler != None: self.message_handler = message_handler elif self.settings.HANDLE_PACKETS: from pyogp.lib.base.message.message_handler import MessageHandler self.message_handler = MessageHandler() # set up our parsers self.udp_deserializer = UDPMessageDeserializer(self.message_handler, self.settings, message_template = self.message_template) self.udp_serializer = UDPMessageSerializer(message_template = self.message_template)
def enable_callbacks(self): """enable the callback handlers for this ParcelManager""" if self.message_handler == None: self.message_handler = MessageHandler() self.onParcelOverlay_received = self.message_handler.register('ParcelOverlay') self.onParcelOverlay_received.subscribe(self.onParcelOverlay) self.onParcelProperties_received = self.message_handler.register('ParcelProperties') self.onParcelProperties_received.subscribe(self.onParcelProperties) self.onParcelPropertiesUpdate_received = self.message_handler.register('ParcelPropertiesUpdate') self.onParcelPropertiesUpdate_received.subscribe(self.onParcelPropertiesUpdate) self.onParcelInfoReply_received = self.message_handler.register('ParcelInfoReply') self.onParcelInfoReply_received.subscribe(self.onParcelInfoReply)
def setUp(self): self.settings = Settings() self.settings.ENABLE_DEFERRED_PACKET_PARSING = False self.deserializer = UDPMessageDeserializer(settings=self.settings) self.region = Region() self.region.SimName = 'TestMe' self.object_store = ObjectManager(region=self.region, settings=self.settings, message_handler=MessageHandler()) self.object_store.enable_callbacks() self.data = []
def __init__(self, capability = None, settings = None, \ message_handler = None, host = None): """ set up the event queue attributes """ # allow the settings to be passed in # otherwise, grab the defaults if settings != None: self.settings = settings else: from pyogp.lib.base.settings import Settings self.settings = Settings() # allow the packet_handler to be passed in # otherwise, grab the defaults # otherwise, let's just use our own if message_handler != None: self.message_handler = message_handler else: self.message_handler = MessageHandler() self.host = host self.cap = capability #self.type = eq_type # specify 'agentdomain' or 'region' self.type = 'typeNotSpecified' self._running = False # this class controls this value self.stopped = False # client can pause the event queue self.last_id = -1 # if applicable, initialize data to post to the event queue self.data = {} # stores the result of the post to the event queue capability self.result = None # enables proper packet parsing in event queue responses self.template_dict = TemplateDictionary() self.current_template = None
class ParcelManager(DataManager): """ a parcel manager, generally used as an attribute of a region """ def __init__(self, agent = None, region = None, settings = None, message_handler = None, events_handler = None): """ initialize the parcel manager """ super(ParcelManager, self).__init__(agent, settings) self.region = region self.message_handler = message_handler # otherwise, let's just use our own # unused atm #if events_handler != None: # self.events_handler = events_handler #else: # self.events_handler = AppEventsHandler() self.helpers = Helpers() # initialize the parcel storage container self.parcels = [] # initialize the parcel overlay storage container self.parcel_overlay = {} # initialize map (x, y) with 0; filled in as parcel properties are received self.parcel_map = [[0 for _ in range(64)] for _ in range(64)] self.parcel_map_full = False if self.settings.LOG_VERBOSE: logger.debug("Initializing the parcel manager in region %s." % (self.region.SimName)) def enable_callbacks(self): """enable the callback handlers for this ParcelManager""" if self.message_handler == None: self.message_handler = MessageHandler() self.onParcelOverlay_received = self.message_handler.register('ParcelOverlay') self.onParcelOverlay_received.subscribe(self.onParcelOverlay) self.onParcelProperties_received = self.message_handler.register('ParcelProperties') self.onParcelProperties_received.subscribe(self.onParcelProperties) self.onParcelPropertiesUpdate_received = self.message_handler.register('ParcelPropertiesUpdate') self.onParcelPropertiesUpdate_received.subscribe(self.onParcelPropertiesUpdate) self.onParcelInfoReply_received = self.message_handler.register('ParcelInfoReply') self.onParcelInfoReply_received.subscribe(self.onParcelInfoReply) def onParcelOverlay(self, packet): """ parse and handle an incoming ParcelOverlay packet Currently, we store this data in the ParcelManager.packet_overlay dictionary as parcel_overlay[sequence_id] = data (unparsed binary) """ # unpack the data sequence_id = packet['ParcelData'][0]['SequenceID'] data = packet['ParcelData'][0]['Data'] # store the data # ToDo: make sense of the binary blob in data self.parcel_overlay[sequence_id] = data def onParcelProperties(self, packet): """ parse and handle an incoming ParcelProperties packet. Parse and serialize the info into a Parcel() representation, then store it (or replace the stored version) """ parcel_info = {} parcel_info['RequestResult'] = packet['ParcelData'][0]['RequestResult'] parcel_info['SequenceID'] = packet['ParcelData'][0]['SequenceID'] parcel_info['SnapSelection'] = packet['ParcelData'][0]['SnapSelection'] parcel_info['SelfCount'] = packet['ParcelData'][0]['SelfCount'] parcel_info['OtherCount'] = packet['ParcelData'][0]['OtherCount'] parcel_info['PublicCount'] = packet['ParcelData'][0]['PublicCount'] parcel_info['LocalID'] = packet['ParcelData'][0]['LocalID'] parcel_info['OwnerID'] = packet['ParcelData'][0]['OwnerID'] parcel_info['IsGroupOwned'] = packet['ParcelData'][0]['IsGroupOwned'] parcel_info['AuctionID'] = packet['ParcelData'][0]['AuctionID'] parcel_info['ClaimDate'] = packet['ParcelData'][0]['ClaimDate'] parcel_info['ClaimPrice'] = packet['ParcelData'][0]['ClaimPrice'] parcel_info['RentPrice'] = packet['ParcelData'][0]['RentPrice'] parcel_info['AABBMin'] = packet['ParcelData'][0]['AABBMin'] parcel_info['AABBMax'] = packet['ParcelData'][0]['AABBMax'] parcel_info['Bitmap'] = packet['ParcelData'][0]['Bitmap'] parcel_info['Area'] = packet['ParcelData'][0]['Area'] parcel_info['Status'] = packet['ParcelData'][0]['Status'] parcel_info['SimWideMaxPrims'] = packet['ParcelData'][0]['SimWideMaxPrims'] parcel_info['SimWideTotalPrims'] = packet['ParcelData'][0]['SimWideTotalPrims'] parcel_info['MaxPrims'] = packet['ParcelData'][0]['MaxPrims'] parcel_info['TotalPrims'] = packet['ParcelData'][0]['TotalPrims'] parcel_info['OwnerPrims'] = packet['ParcelData'][0]['OwnerPrims'] parcel_info['GroupPrims'] = packet['ParcelData'][0]['GroupPrims'] parcel_info['OtherPrims'] = packet['ParcelData'][0]['OtherPrims'] parcel_info['SelectedPrims'] = packet['ParcelData'][0]['SelectedPrims'] parcel_info['ParcelPrimBonus'] = packet['ParcelData'][0]['ParcelPrimBonus'] parcel_info['OtherCleanTime'] = packet['ParcelData'][0]['OtherCleanTime'] parcel_info['ParcelFlags'] = packet['ParcelData'][0]['ParcelFlags'] parcel_info['SalePrice'] = packet['ParcelData'][0]['SalePrice'] parcel_info['Name'] = packet['ParcelData'][0]['Name'] parcel_info['Desc'] = packet['ParcelData'][0]['Desc'] parcel_info['MusicURL'] = packet['ParcelData'][0]['MusicURL'] parcel_info['MediaURL'] = packet['ParcelData'][0]['MediaURL'] parcel_info['MediaID'] = packet['ParcelData'][0]['MediaID'] parcel_info['MediaAutoScale'] = packet['ParcelData'][0]['MediaAutoScale'] parcel_info['GroupID'] = packet['ParcelData'][0]['GroupID'] parcel_info['PassPrice'] = packet['ParcelData'][0]['PassPrice'] parcel_info['PassHours'] = packet['ParcelData'][0]['PassHours'] parcel_info['Category'] = packet['ParcelData'][0]['Category'] parcel_info['AuthBuyerID'] = packet['ParcelData'][0]['AuthBuyerID'] parcel_info['SnapshotID'] = packet['ParcelData'][0]['SnapshotID'] parcel_info['UserLocation'] = packet['ParcelData'][0]['UserLocation'] parcel_info['UserLookAt'] = packet['ParcelData'][0]['UserLookAt'] parcel_info['LandingType'] = packet['ParcelData'][0]['LandingType'] parcel_info['RegionPushOverride'] = packet['ParcelData'][0]['RegionPushOverride'] parcel_info['RegionDenyAnonymous'] = packet['ParcelData'][0]['RegionDenyAnonymous'] parcel_info['RegionDenyIdentified'] = packet['ParcelData'][0]['RegionDenyIdentified'] parcel_info['RegionDenyTransacted'] = packet['ParcelData'][0]['RegionDenyTransacted'] parcel_info['RegionDenyAgeUnverified'] = packet['AgeVerificationBlock'][0]['RegionDenyAgeUnverified'] self._store_parcel_properties(parcel_info) def onParcelPropertiesUpdate(self, packet): """ parse and handle an incoming ParcelPropertiesUpdate packet. parse the data into a dictionary and pass the blob to the Parcel() instance for self handling """ parcel_update = {} parcel_update['LocalID'] = packet['ParcelData'][0]['LocalID'] parcel_update['Flags'] = packet['ParcelData'][0]['Flags'] parcel_update['ParcelFlags'] = packet['ParcelData'][0]['ParcelFlags'] parcel_update['SalePrice'] = packet['ParcelData'][0]['SalePrice'] parcel_update['Name'] = packet['ParcelData'][0]['Name'] parcel_update['Desc'] = packet['ParcelData'][0]['Desc'] parcel_update['MusicURL'] = packet['ParcelData'][0]['MusicURL'] parcel_update['MediaURL'] = packet['ParcelData'][0]['MediaURL'] parcel_update['MediaID'] = packet['ParcelData'][0]['MediaID'] parcel_update['MediaAutoScale'] = packet['ParcelData'][0]['MediaAutoScale'] parcel_update['GroupID'] = packet['ParcelData'][0]['GroupID'] parcel_update['PassPrice'] = packet['ParcelData'][0]['PassPrice'] parcel_update['PassHours'] = packet['ParcelData'][0]['PassHours'] parcel_update['Category'] = packet['ParcelData'][0]['Category'] parcel_update['AuthBuyerID'] = packet['ParcelData'][0]['AuthBuyerID'] parcel_update['SnapshotID'] = packet['ParcelData'][0]['SnapshotID'] parcel_update['UserLocation'] = packet['ParcelData'][0]['UserLocation'] parcel_update['UserLookAt'] = packet['ParcelData'][0]['UserLookAt'] parcel_update['LandingType'] = packet['ParcelData'][0]['LandingType'] self._update_parcel_properties(parcel_update) def _store_parcel_properties(self, parcel_info): """ store a representation of a parcel """ # update the attributes of an existing parcel list member, else, append index = [self.parcels.index(parcel) for parcel in self.parcels if parcel.LocalID == parcel_info['LocalID']] if index != []: self._update_parcel_properties(parcel_info) if self.settings.LOG_VERBOSE: logger.debug('Updating a stored parcel: %s in region \'%s\'' % (parcel_info['LocalID'], self.region.SimName)) else: new_parcel = Parcel(self.region, self.agent, RequestResult = parcel_info['RequestResult'], SequenceID = parcel_info['SequenceID'], SnapSelection = parcel_info['SnapSelection'], SelfCount = parcel_info['SelfCount'], OtherCount = parcel_info['OtherCount'], PublicCount = parcel_info['PublicCount'], LocalID = parcel_info['LocalID'], OwnerID = parcel_info['OwnerID'], IsGroupOwned = parcel_info['IsGroupOwned'], AuctionID = parcel_info['AuctionID'], ClaimDate = parcel_info['ClaimDate'], ClaimPrice = parcel_info['ClaimPrice'], RentPrice = parcel_info['RentPrice'], AABBMin = parcel_info['AABBMin'], AABBMax = parcel_info['AABBMax'], Bitmap = parcel_info['Bitmap'], Area = parcel_info['Area'], Status = parcel_info['Status'], SimWideMaxPrims = parcel_info['SimWideMaxPrims'], SimWideTotalPrims = parcel_info['SimWideTotalPrims'], MaxPrims = parcel_info['MaxPrims'], TotalPrims = parcel_info['TotalPrims'], OwnerPrims = parcel_info['OwnerPrims'], GroupPrims = parcel_info['GroupPrims'], OtherPrims = parcel_info['OtherPrims'], SelectedPrims = parcel_info['SelectedPrims'], ParcelPrimBonus = parcel_info['ParcelPrimBonus'], OtherCleanTime = parcel_info['OtherCleanTime'], ParcelFlags = parcel_info['ParcelFlags'], SalePrice = parcel_info['SalePrice'], Name = parcel_info['Name'], Desc = parcel_info['Desc'], MusicURL = parcel_info['MusicURL'], MediaURL = parcel_info['MediaURL'], MediaID = parcel_info['MediaID'], MediaAutoScale = parcel_info['MediaAutoScale'], GroupID = parcel_info['GroupID'], PassPrice = parcel_info['PassPrice'], PassHours = parcel_info['PassHours'], Category = parcel_info['Category'], AuthBuyerID = parcel_info['AuthBuyerID'], SnapshotID = parcel_info['SnapshotID'], UserLocation = parcel_info['UserLocation'], UserLookAt = parcel_info['UserLookAt'], LandingType = parcel_info['LandingType'], RegionPushOverride = parcel_info['RegionPushOverride'], RegionDenyAnonymous = parcel_info['RegionDenyAnonymous'], RegionDenyIdentified = parcel_info['RegionDenyIdentified'], RegionDenyTransacted = parcel_info['RegionDenyTransacted'], RegionDenyAgeUnverified = parcel_info['RegionDenyAgeUnverified'], settings = self.settings) self.parcels.append(new_parcel) self._update_parcel_map(new_parcel) if self.settings.LOG_VERBOSE: logger.debug('Stored a new parcel: %s in region \'%s\'' % (new_parcel.LocalID, self.region.SimName)) def _update_parcel_properties(self, parcel_properties): """ update a stored parcel's properties. finds the stored parcel and passes it a dictionary to process """ parcels_found = [] if parcel_properties.has_key('LocalID'): LocalID = parcel_properties['LocalID'] parcels_found = [parcel for parcel in self.parcels if str(parcel.LocalID) == str(LocalID)] if len(parcels_found) == 0: logger.info("Received ParcelPropertiesUpdate for parcel we do not know about yet. Storing a partial representation.") new_parcel = Parcel(self.region, self.agent, LocalID = parcel_properties['LocalID'], Flags = parcel_properties['Flags'], ParcelFlags = parcel_properties['ParcelFlags'], SalePrice = parcel_properties['SalePrice'], Name = parcel_properties['Name'], Desc = parcel_properties['Desc'], MusicURL = parcel_properties['MusicURL'], MediaURL = parcel_properties['MediaURL'], MediaID = parcel_properties['MediaID'], MediaAutoScale = parcel_properties['MediaAutoScale'], GroupID = parcel_properties['GroupID'], PassPrice = parcel_properties['PassPrice'], PassHours = parcel_properties['PassHours'], Category = parcel_properties['Category'], AuthBuyerID = parcel_properties['AuthBuyerID'], SnapshotID = parcel_properties['SnapshotID'], UserLocation = parcel_properties['UserLocation'], UserLookAt = parcel_properties['UserLookAt'], LandingType = parcel_properties['LandingType'], settings = self.settings) self._store_parcel(new_parcel) elif len(parcels_found) == 1: parcel = parcels_found[0] parcel._update_properties(parcel_properties) elif parcel_properties.has_key('ParcelID'): ParcelID = parcel_properties['ParcelID'] parcels_found = [parcel for parcel in self.parcels if str(parcel.ParcelID) == str(ParcelID)] if len(parcels_found) == 0: logger.info("Received ParcelPropertiesUpdate for parcel we do not know about yet. Storing a partial representation.") new_parcel = Parcel(self.region, self.agent, LocalID = parcel_properties['LocalID'], Flags = parcel_properties['Flags'], ParcelFlags = parcel_properties['ParcelFlags'], SalePrice = parcel_properties['SalePrice'], Name = parcel_properties['Name'], Desc = parcel_properties['Desc'], MusicURL = parcel_properties['MusicURL'], MediaURL = parcel_properties['MediaURL'], MediaID = parcel_properties['MediaID'], MediaAutoScale = parcel_properties['MediaAutoScale'], GroupID = parcel_properties['GroupID'], PassPrice = parcel_properties['PassPrice'], PassHours = parcel_properties['PassHours'], Category = parcel_properties['Category'], AuthBuyerID = parcel_properties['AuthBuyerID'], SnapshotID = parcel_properties['SnapshotID'], UserLocation = parcel_properties['UserLocation'], UserLookAt = parcel_properties['UserLookAt'], LandingType = parcel_properties['LandingType'], settings = self.settings) self._store_parcel(new_parcel) elif len(parcels_found) == 1: parcel = parcels_found[0] parcel._update_properties(parcel_properties) def _update_parcel_map(self, parcel): """Use the parcel's bitmap to update the manager's (x,y) to LocalID mapping""" full = True for x in range(64): for y in range(64): index = x + (64 * y) byte = index >> 3 mask = 1 << (index % 8) # *TODO: Bitmap should be stored as a byte array, not a string if ord(parcel.Bitmap[byte]) & mask: self.parcel_map[x][y] = parcel.LocalID full = full and (self.parcel_map[x][y] != 0) self.parcel_map_full = full def get_parcel_by_id(self, local_id): """Returns a parcel if info has been received, None otherwise.""" for parcel in self.parcels: if parcel.LocalID == local_id: return parcel return None def get_parcel_id_by_location(self, local_x, local_y): """Returns a parcel's local id if info has been received, 0 otherwise.""" return self.parcel_map[ int(local_x)/4 ][ int(local_y)/4 ] def get_parcel_by_location(self, local_x, local_y): """Returns a parcel if info has been received, None otherwise.""" return self.get_parcel_by_id( self.get_parcel_id_by_location(local_x, local_y) ) def get_current_parcel(self): """Returns the agent's current parcel if info has been received, None otherwise.""" return self.get_parcel_by_location( self.agent.Position.X, self.agent.Position.Y ) def request_estate_covenant(self, ): """ request the estate covenant (for the current estate)""" self.onEstateCovenantReply_received = self.message_handler.register('EstateCovenantReply') self.onEstateCovenantReply_received.subscribe(self.onEstateCovenantReply) self.sendEstateCovenantRequest(self.agent.agent_id, self.agent.session_id) def sendEstateCovenantRequest(self, agent_id, session_id): """ send an EstateCovenantRequest message to the host simulator """ packet = Message('EstateCovenantRequest', Block('AgentData', AgentID = agent_id, SessionID = session_id)) self.region.enqueue_message(packet) def onEstateCovenantReply(self, packet): """ parse and handle an EstateCovenantReply packet """ try: self.onEstateCovenantReply_received.unsubscribe(self.onEstateCovenantReply) except AttributeError: pass CovenantID = packet['Data'][0]['CovenantID'] CovenantTimestamp = packet['Data'][0]['CovenantTimestamp'] EstateName = packet['Data'][0]['EstateName'] EstateOwnerID = packet['Data'][0]['EstateOwnerID'] logger.info("Received EstateCovenantReply for estate name %s with a CovenantID of %s." % (EstateName, CovenantID)) # storing this data as a dict in the parcel manager until we have something better to do with it self.estatecovenantreply = {'CovenantID': CovenantID, 'CovenantTimestamp': CovenantTimestamp, 'EstateName': EstateName, 'EstateOwnerID': EstateOwnerID} def sendParcelPropertiesRequest(self, agent_id, session_id, SequenceID, West, South, East, North, SnapSelection): """ sends a ParcelPropertiesRequest message to the host simulator """ packet = Message('ParcelPropertiesRequest', Block('AgentData', AgentID = agent_id, SessionID = session_id), Block('ParcelData', SequenceID = SequenceID, West = West, South = South, East = East, North = North, SnapSelection = SnapSelection)) self.region.enqueue_message(packet) def sendParcelPropertiesRequestByID(self, agent_id, session_id, SequenceID, LocalID): """ sends a ParcelPropertiesRequestByID packet """ packet = Message('ParcelPropertiesRequestByID', Block('AgentData', AgentID = agent_id, SessionID = session_id), Block('ParcelData', SequenceID = SequenceID, LocalID = LocalID)) self.region.enqueue_message(packet) def request_parcel_info(self, parcel_id): """ request information for a parcel by id """ if type(parcel_id) == str: try: parcel_id = UUID(parcel_id) except ValueError: logger.warning('Parcel_id passed to request_parcel_info must but a valid UUID or string representation of a uuid. %s was passed in' % (parcel_id)) return elif not isinstance(parcel_id, UUID): logger.warning('Parcel_id passed to request_parcel_info must but a valid UUID or string representation of a uuid. %s was passed in' % (parcel_id)) return self.sendParcelInfoRequest(self.agent.agent_id, self.agent.session_id, parcel_id) def sendParcelInfoRequest(self, agent_id, session_id, parcel_id): """ send a ParcelInfoRequest packet for the specified parcel_id """ packet = Message('ParcelInfoRequest', Block('AgentData', AgentID = agent_id, SessionID = session_id), Block('Data', ParcelID = parcel_id)) self.region.enqueue_message(packet) def onParcelInfoReply(self, packet): """ parse and handle a ParcelInfoReply packet """ parcel_info = {} parcel_info['ParcelID'] = packet['Data'][0]['ParcelID'] parcel_info['OwnerID'] = packet['Data'][0]['OwnerID'] parcel_info['Name'] = packet['Data'][0]['Name'] parcel_info['Desc'] = packet['Data'][0]['Desc'] parcel_info['ActualArea'] = packet['Data'][0]['ActualArea'] parcel_info['BillableArea'] = packet['Data'][0]['BillableArea'] parcel_info['Flags'] = packet['Data'][0]['Flags'] parcel_info['GlobalX'] = packet['Data'][0]['GlobalX'] parcel_info['GlobalY'] = packet['Data'][0]['GlobalY'] parcel_info['GlobalZ'] = packet['Data'][0]['GlobalZ'] parcel_info['SimName'] = packet['Data'][0]['SimName'] parcel_info['SnapshotID'] = packet['Data'][0]['SnapshotID'] parcel_info['Dwell'] = packet['Data'][0]['Dwell'] parcel_info['SalePrice'] = packet['Data'][0]['SalePrice'] parcel_info['AuctionID'] = packet['Data'][0]['AuctionID'] self._update_parcel_properties(parcel_info) def request_current_parcel_properties(self, refresh = False): """ request the properties of the parcel the agent currently inhabits """ x = self.agent.Position.X y = self.agent.Position.Y if refresh or self.get_parcel_id_by_location(x, y) == 0: self.sendParcelPropertiesRequest(self.agent.agent_id, self.agent.session_id, -50000, x, y, x, y, False) def request_all_parcel_properties(self, delay = 0.5, refresh = False): """ request the properties of all of the parcels on the current region. The delay parameter is a sleep between the send of each packet request; if refresh, current data will be discarded before requesting. If refresh is not True, data will not be re-requested for region locations already queried. """ # spawn a coroutine so this is non blocking eventlet.spawn(self.__request_all_parcel_properties, delay, refresh) def __request_all_parcel_properties(self, delay = 1, refresh = False): """ request the properties of all of the parcels on the current region """ if refresh: self.parcel_map = [[0 for _ in range(64)] for _ in range(64)] self.parcel_map_full = False # minimum parcel size is 4x4m (16sq) # ugh this is a wretched way to request parcel info, but it is what it is for y in range(64): for x in range(64): if self.parcel_map[x][y] == 0: # Target: center of 4m by 4m parcel tx = x * 4 + 2 ty = y * 4 + 2 self.sendParcelPropertiesRequest(self.agent.agent_id, self.agent.session_id, -50000, tx, ty, tx, ty, False) eventlet.sleep(delay) def return_parcel_objects(self, ): """ return the specified objects for the specified parcel """ pass ''' // ParcelReturnObjects // viewer -> sim // reliable { ParcelReturnObjects Low 199 NotTrusted Zerocoded { AgentData Single { AgentID LLUUID } { SessionID LLUUID } } { ParcelData Single { LocalID S32 } { ReturnType U32 } } { TaskIDs Variable { TaskID LLUUID } } { OwnerIDs Variable { OwnerID LLUUID } } } ''' def disable_objects(self, ): """ set objects nonphysical and disable scripts for the specified parcel """ pass ''' // Disable makes objects nonphysical and turns off their scripts. // ParcelDisableObjects // viewer -> sim // reliable { ParcelDisableObjects Low 201 NotTrusted Zerocoded { AgentData Single { AgentID LLUUID } { SessionID LLUUID } } { ParcelData Single { LocalID S32 } { ReturnType U32 } } { TaskIDs Variable { TaskID LLUUID } } { OwnerIDs Variable { OwnerID LLUUID } } } ''' def sendParcelDisableObjects(self, ): """ send a ParcelDisableObjects packet """ pass ''' // Disable makes objects nonphysical and turns off their scripts. // ParcelDisableObjects // viewer -> sim // reliable { ParcelDisableObjects Low 201 NotTrusted Zerocoded { AgentData Single { AgentID LLUUID } { SessionID LLUUID } } { ParcelData Single { LocalID S32 } { ReturnType U32 } } { TaskIDs Variable { TaskID LLUUID } } { OwnerIDs Variable { OwnerID LLUUID } } } ''' def join_parcels(self, ): """ joins the specified parcels """ pass ''' // ParcelJoin - Take all parcels which are owned by agent and inside // rectangle, and make them 1 parcel if they all are leased. // viewer -> sim // reliable { ParcelJoin Low 210 NotTrusted Unencoded { AgentData Single { AgentID LLUUID } { SessionID LLUUID } } { ParcelData Single { West F32 } { South F32 } { East F32 } { North F32 } } } ''' def sendParcelJoin(self, ): """ send a ParcelJoin packet """ pass ''' // ParcelJoin - Take all parcels which are owned by agent and inside // rectangle, and make them 1 parcel if they all are leased. // viewer -> sim // reliable { ParcelJoin Low 210 NotTrusted Unencoded { AgentData Single { AgentID LLUUID } { SessionID LLUUID } } { ParcelData Single { West F32 } { South F32 } { East F32 } { North F32 } } } ''' def divide_parcel(self, ): """ divide the selection into a new parcel """ pass ''' // ParcelDivide // If the selection is a subsection of exactly one parcel, // chop out that section and make a new parcel of it. // viewer -> sim // reliable { ParcelDivide Low 211 NotTrusted Unencoded { AgentData Single { AgentID LLUUID } { SessionID LLUUID } } { ParcelData Single { West F32 } { South F32 } { East F32 } { North F32 } } } ''' def sendParcelDivide(self, ): """ send a ParcelDivide packet """ pass ''' // ParcelDivide // If the selection is a subsection of exactly one parcel, // chop out that section and make a new parcel of it. // viewer -> sim // reliable { ParcelDivide Low 211 NotTrusted Unencoded { AgentData Single { AgentID LLUUID } { SessionID LLUUID } } { ParcelData Single { West F32 } { South F32 } { East F32 } { North F32 } } } ''' def request_parcel_access_list(self, LocalID, Flags): """ request an access list for the specified parcel, while enabling a callback handler for the response """ self.onParcelAccessListReply_received = self.message_handler.register('ParcelAccessListReply') self.onParcelAccessListReply_received.subscribe(self.onParcelAccessListReply, LocalID = LocalID) self.sendParcelAccessListRequest(self.agent.agent_id, self.agent.session_id, LocalID, Flags) def sendParcelAccessListRequest(self, agent_id, session_id, LocalID, Flags, SequenceID = -5150): """ send a ParcelAccessListRequest packet to the host simulator """ packet = Message('ParcelAccessListRequest', Block('AgentData', AgentID = agent_id, SessionID = session_id), Block('Data', SequenceID = SequenceID, Flags = Flags, LocalID = LocalID)) self.region.enqueue_message(packet) def onParcelAccessListReply(self, packet): """ parse and handle a ParcelAccessListReply packet """ #self.onParcelAccessListReply_received.unsubscribe(self.onParcelAccessListReply, LocalID = LocalID) raise NotImplemented("sendFetchInventoryDescendentsRequest") ''' // sim -> viewer // ParcelAccessListReply { ParcelAccessListReply Low 216 Trusted Zerocoded { Data Single { AgentID LLUUID } { SequenceID S32 } { Flags U32 } { LocalID S32 } } { List Variable { ID LLUUID } { Time S32 } // time_t { Flags U32 } } } ''' def request_parcel_dwell(self, LocalID): """ request dwell for the specified parcel, while enabling a callback handler for the response """ self.onParcelDwellReply_received = self.message_handler.register('ParcelDwellReply') self.onParcelDwellReply_received.subscribe(self.onParcelDwellReply, LocalID = LocalID) self.sendParcelDwellRequest(self.agent.agent_id, self.agent.session_id, LocalID) def sendParcelDwellRequest(self, agent_id, session_id, LocalID): """ send a ParcelDwellRequest packet """ packet = Message('ParcelDwellRequest', Block('AgentData', AgentID = agent_id, SessionID = session_id), Block('Data', LocalID = LocalID, ParcelID = UUID())) self.region.enqueue_message(packet, True) def onParcelDwellReply(self, packet, LocalID = None): """ parse and handle a ParcelDwellReply packet""" AgentID = packet['AgentData'][0]['AgentID'] # log receipt of a packet that was intended to be sent to another agent # ToDo: should we raise an event in this case? yes.... later if str(AgentID) != str(self.agent.agent_id): logger.warning("%s received a packet for the wrong agent_id. Expected: %s Received: %s" % (self.agent.Name(), self.agent.agent_id, AgentID)) # get the body of the message parcel_info = {} parcel_info['LocalID'] = packet['Data'][0]['LocalID'] parcel_info['ParcelID'] = packet['Data'][0]['ParcelID'] parcel_info['Dwell'] = packet['Data'][0]['Dwell'] if LocalID == parcel_info['LocalID']: self.onParcelDwellReply_received.unsubscribe(self.onParcelDwellReply, LocalID = LocalID) self._update_parcel_properties(parcel_info)
class UDPMessageDeserializer(object): def __init__(self, message_handler=None, settings=None, message_template=None, message_xml=None): self.context = None self.unpacker = DataUnpacker() self.current_template = None self.current_block = None self.template_dict = TemplateDictionary( message_template=message_template) # allow the settings to be passed in # otherwise, grab the defaults if settings != None: self.settings = settings else: self.settings = Settings() if not message_xml: self.message_xml = MessageDotXML() else: self.message_xml = message_xml # we can skip parsing all the data in a packet if we know it's not being handled # allow the packet_handler to be passed in # otherwise, grab the defaults if message_handler != None: self.message_handler = message_handler elif self.settings.HANDLE_PACKETS: self.message_handler = MessageHandler() def deserialize(self, context): self.context = context #Must first strip off acks if present, and zero-decode, #if needed, in order to determine proper template #once we can test again, do the commented out part below for the offset temp_acks = [] msg_buff = self.context msg_len = len(msg_buff) if ord(msg_buff[0]) & PackFlags.LL_ACK_FLAG: num_acks = ord(msg_buff[msg_len - 1]) #logger.debug("Decoding packet with acks: %d", num_acks) ack_length = 1 + sizeof(MsgType.MVT_U32) * num_acks temp_acks = msg_buff[-ack_length:] msg_buff = msg_buff[:-ack_length] #Now zero decode the entire msg except the acks, in order to get the correct evaluation of the template if ord(msg_buff[0]) & PackFlags.LL_ZERO_CODE_FLAG: ''' #offset = ord(msg_buff[5]) #header = msg_buff[:6+offset] #offset will be zero unless the header has extra data header = msg_buff[:6] #inputbuf = msg_buff[6+offset:] #not yet implemented because we can't test right now inputbuf = msg_buff[6:] input_len = len(inputbuf) msg_buff = self.zero_code_expand(inputbuf, input_len) ''' offset = ord(msg_buff[5]) header = msg_buff[:6 + offset] #disregard#offset will be zero unless the header has extra data #header = msg_buff[:6] inputbuf = msg_buff[ 6 + offset:] #disregard#not yet implemented because we can't test right now #inputbuf = msg_buff[6:] # debugger code commented out #''.join( [ "%02X " % ord( x ) for x in byteStr ] ).strip() #print "just did zerodecode " + ''.join( [ "%02X " % ord( x ) for x in header ] ).strip() + ' ' \ #+ ''.join( [ "%02X " % ord( x ) for x in msg_buff[:12] ] ).strip() input_len = len(inputbuf) msg_buff = self.zero_code_expand(inputbuf, input_len) msg_buff = header + msg_buff if self.__validate_message(msg_buff) == True: # go ahead an merge the acks back in in order for the decode to work # or to get the send_flags for acks msg_buff = msg_buff + ''.join(temp_acks) # validate whether we are allowed to receive this message over udp if not self.message_xml.validate_udp_msg( self.current_template.name): logger.warning( "Received '%s' over UDP, when it should come over the event queue. Discarding." % (self.current_template.name)) return None # if the packet is being handled, or if have have disabled deferred packet parsing, handle it! if self.message_handler.is_message_handled( self.current_template.name ) or not self.settings.ENABLE_DEFERRED_PACKET_PARSING: try: return self.__decode_data(msg_buff) except exc.DataUnpackingError, error: #logger.warning("Error parsing packet due to: %s" % (error)) raise exc.MessageDeserializationError( self.current_template.name, error) return None else: if self.settings.LOG_VERBOSE \ and self.settings.ENABLE_UDP_LOGGING \ and self.settings.LOG_SKIPPED_PACKETS \ and not self.settings.PROXY_LOGGING: logger.debug('Received packet : %s (Skipping)' % (self.current_template.name)) return None
class UDPDispatcher(object): #implements(IUDPDispatcher) def __init__(self, udp_client = None, settings = None, message_handler = None, message_template = None, message_xml = None): #holds the details of the message, or how the messages should be sent, #built, and read self.packets_in = 0 self.packets_out = 0 self.circuit_manager = CircuitManager() self.data_unpacker = DataUnpacker() #the ID of the packet we most recently received self.receive_packet_id = -1 if udp_client == None: self.udp_client = NetUDPClient() else: self.udp_client = udp_client self.udp_client.start_udp_connection() # allow the settings to be passed in # otherwise, grab the defaults if settings != None: self.settings = settings else: self.settings = Settings() # allow the passing in of message_template.xml as a file handle if not message_template: self.message_template = None else: if isinstance(message_template, file): self.message_template = message_template else: log.warning("%s parameter is expected to be a filehandle, it is a %s. \ Using the embedded message_template.msg" % (message_template, type(message_template))) self.message_template = None if not message_xml: self.message_xml = MessageDotXML() else: self.message_xml = message_xml self.helpers = Helpers() # allow the packet_handler to be passed in # otherwise, grab the defaults if message_handler != None: self.message_handler = message_handler elif self.settings.HANDLE_PACKETS: from pyogp.lib.base.message.message_handler import MessageHandler self.message_handler = MessageHandler() # set up our parsers self.udp_deserializer = UDPMessageDeserializer(self.message_handler, self.settings, message_template = self.message_template) self.udp_serializer = UDPMessageSerializer(message_template = self.message_template) def find_circuit(self, host): circuit = self.circuit_manager.get_circuit(host) if circuit == None: #there is a case where we want to return None, #when the last packet was protected circuit = self.circuit_manager.add_circuit(host, self.receive_packet_id) return circuit def receive_check(self, host, msg_buf, msg_size): #determine if we have any messages that can be received through UDP #also, check and decode the message we have received recv_packet = None #msg_buf, msg_size = self.udp_client.receive_packet(self.socket) #we have a message if msg_size > 0: #determine sender #host = self.udp_client.get_sender() circuit = self.find_circuit(host) if circuit == None: raise exc.CircuitNotFound(host, 'preparing to check for packets') self.packets_in += 1 recv_packet = self.udp_deserializer.deserialize(msg_buf) #couldn't deserialize if recv_packet == None: # if its sent as reliable, we should ack it even if we aren't going to parse it # since we can skip parsing the packet in self.udp_deserializer # this indicate reliable send_flags = ord(msg_buf[0]) packet_id = self.data_unpacker.unpack_data(msg_buf, MsgType.MVT_U32, 1, endian_type=EndianType.BIG) # queue the ack up circuit.collect_ack(packet_id) return None #Case - trusted packets can only come in over trusted circuits if circuit.is_trusted and \ recv_packet.trusted == False: return None circuit.handle_packet(recv_packet) if self.settings.ENABLE_UDP_LOGGING: if self.settings.ENABLE_BYTES_TO_HEX_LOGGING: hex_string = '<=>' + self.helpers.bytes_to_hex(msg_buf) else: hex_string = '' if self.settings.ENABLE_HOST_LOGGING: host_string = ' (%s)' % (host) else: host_string = '' if not self.settings.PROXY_LOGGING: logger.debug('Received packet%s : %s (%s)%s' % (host_string, recv_packet.name, recv_packet.packet_id, hex_string)) if self.settings.HANDLE_PACKETS: self.message_handler.handle(recv_packet) return recv_packet def send_reliable(self, message, host, retries): """ Wants to be acked """ #sets up the message so send_message will add the RELIABLE flag to #the message return self.__send_message(message, host, reliable=True, retries=retries) def send_retry(self, message, host): """ This is a retry because we didn't get acked """ #sets up the message so send_message will add the RETRY flag to it return self.__send_message(host, message, retrying=True) def send_message(self, message, host): return self.__send_message(message, host) def __send_message(self, message, host, reliable=False, retries=0, retrying=False): """ Sends the message that is currently built to the desired host """ #make sure host is OK (ip and address aren't null) if host.is_ok() == False: return if isinstance(message,Message): packet = message else: packet = message() # enable monitoring of outgoing packets if self.settings.HANDLE_OUTGOING_PACKETS: self.message_handler.handle(packet) #use circuit manager to get the circuit to send on circuit = self.find_circuit(host) if reliable == True: circuit.prepare_packet(packet, PackFlags.LL_RELIABLE_FLAG, retries) if circuit.unack_packet_count <= 0: self.circuit_manager.unacked_circuits[host] = circuit elif retrying == True: circuit.prepare_packet(packet, PackFlags.LL_RESENT_FLAG) else: circuit.prepare_packet(packet) try: send_buffer = self.udp_serializer.serialize(packet) if self.settings.ENABLE_UDP_LOGGING: if packet.name in self.settings.UDP_SPAMMERS and self.settings.DISABLE_SPAMMERS: pass else: if self.settings.ENABLE_BYTES_TO_HEX_LOGGING: hex_string = '<=>' + self.helpers.bytes_to_hex(send_buffer) else: hex_string = '' if self.settings.ENABLE_HOST_LOGGING: host_string = ' (%s)' % (host) else: host_string = '' logger.debug('Sent packet %s : %s (%s)%s' % (host_string, packet.name, packet.packet_id, hex_string)) #TODO: remove this when testing a network self.udp_client.send_packet(send_buffer, host) self.packets_out += 1 return send_buffer except AssertionError: pass except Exception, error: logger.warning("Error trying to serialize the following packet: %s" % (packet)) traceback.print_exc() return