def poll_datagram(self): """Reads a datagram from the socket and returns it. If a datagram can't be read completely, it's readable data will be cached and None will be returned. If the connection has been closed, EOFError will be raised.""" self.read() # Did we just finish reading the message length? if (not self.reading_message) and (self.remaining_length == 0): length = struct.unpack('<H', self.partial_data)[0] self.partial_data = '' self.remaining_length = length self.reading_message = True self.read() # If either the initial read or the read at the end of the # block above finished reading a message body, then this # happens: if self.reading_message and (self.remaining_length == 0): dg = Datagram() dg.add_data(self.partial_data) self.partial_data = '' self.remaining_length = DATAGRAM_HEADER_SIZE self.reading_message = False return dg # So we did not actually finish reading a message at all. :( return
def recv_datagram(self): """Wait for the next datagram and return it.""" length = struct.unpack('<H', self._read(2))[0] data = self._read(length) dg = Datagram() dg.add_data(data) return dg
def send_CONTROL_ADD_CHANNEL(self, channel): # CONTROL messages don't have sender fields dg = Datagram() dg.add_uint8(1) # Number of recipients dg.add_uint64(1) # Recipient (control channel) dg.add_uint16(servermsg.CONTROL_ADD_CHANNEL) dg.add_uint64(channel) self.send_datagram(dg)
def send_CLIENT_REMOVE_INTEREST(self, interest_id, context_id): # FIXME: Should something be done about callbacks here? dg = Datagram() dg.add_uint16(clientmsg.CLIENT_REMOVE_INTEREST) dg.add_uint32(context_id) dg.add_uint16(interest_id) self.send_datagram(dg)
def create_message_stub(self, sender, *recipients): dg = Datagram() dg.add_uint8(len(recipients)) for recipient in recipients: dg.add_uint64(recipient) dg.add_uint64(sender) return dg
def poll_datagram(self): self.socket.setblocking(0) try: length = struct.unpack('<H', self._read(2))[0] except socket.error as err: if err.errno is errno.EWOULDBLOCK: return None else: raise err self.socket.setblocking(1) data = self._read(length) dg = Datagram() dg.add_data(data) return dg
def send_CLIENT_HELLO(self): dg = Datagram() dg.add_uint16(clientmsg.CLIENT_HELLO) dg.add_uint32(traits.legacy_hash(self.mod)) dg.add_string(self.version_string) self.send_datagram(dg)
def send_CLIENT_ADD_INTEREST_MULTIPLE(self, parent_id, zone_ids, interest_id=0, callback=False, callback_args=[], callback_kwargs={}): zone_count = len(zone_ids) # FIXME: interest_id (uint16), parent_id (uint32), zone_id (uint32) should # be asserted. if not (interest_id in self.interest_counters.keys()): self.interest_counters[interest_id] = -1 # FIXME: This needs to be protected against uint32 roll-overs. I'll probably # need to have a set of freed context_ids. But what if there are no more # usable context_ids? Raise an Exception? self.interest_counters[ interest_id] = self.interest_counters[interest_id] + 1 context_id = self.interest_counters[interest_id] dg = Datagram() dg.add_uint16(clientmsg.CLIENT_ADD_INTEREST_MULTIPLE) dg.add_uint32(context_id) dg.add_uint16(interest_id) dg.add_uint32(parent_id) dg.add_uint16(zone_count) for zone_id in zone_ids: dg.add_uint32(zone_id) self.send_datagram(dg) if callback != False: self.interest_callback_map[(interest_id, context_id)] = (callback, callback_args, callback_kwargs) return context_id
def send_CLIENT_DISCONNECT(self): dg = Datagram() dg.add_uint16(clientmsg.CLIENT_DISCONNECT) self.send_datagram(dg)
def create_message_stub(self): dg = Datagram() return dg
def send_CLIENT_ADD_INTEREST_MULTIPLE(self, parent_id, zone_ids, interest_id = 0, callback = False, callback_args = [], callback_kwargs = {}): zone_count = len(zone_ids) # FIXME: interest_id (uint16), parent_id (uint32), zone_id (uint32) should # be asserted. if not (interest_id in self.interest_counters.keys()): self.interest_counters[interest_id] = -1 # FIXME: This needs to be protected against uint32 roll-overs. I'll probably # need to have a set of freed context_ids. But what if there are no more # usable context_ids? Raise an Exception? self.interest_counters[interest_id] = self.interest_counters[interest_id] + 1 context_id = self.interest_counters[interest_id] dg = Datagram() dg.add_uint16(clientmsg.CLIENT_ADD_INTEREST_MULTIPLE) dg.add_uint32(context_id) dg.add_uint16(interest_id) dg.add_uint32(parent_id) dg.add_uint16(zone_count) for zone_id in zone_ids: dg.add_uint32(zone_id) self.send_datagram(dg) if callback != False: self.interest_callback_map[(interest_id, context_id)] = (callback, callback_args, callback_kwargs) return context_id