def is_stun_message(self, data): try: channel, len = struct.unpack('!HH', data[:4]) if 0x4000 <= channel <= 0x7FFF: return True else: method, length, magic, tx_id = STUNMessage.parse_header(data[:20]) return magic == STUN_MAGIC_COOKIE except: return False
def is_stun_message(self, data): try: channel, len = struct.unpack('!HH', data[:4]) if 0x4000 <= channel <= 0x7FFF: return True else: method, length, magic, tx_id = STUNMessage.parse_header( data[:20]) return magic == STUN_MAGIC_COOKIE except: return False
def send_to(self, data, addr): if isinstance(addr, int): msg = struct.pack('!HH', addr, len(data)) self._write(msg + data) elif addr in self.bindings: header = TURNSession._channeldata_format.pack( self.bindings[addr], len(data)) self._write(header + data) else: self._write( STUNMessage('Send', [('XOR-PEER-ADDRESS', addr), ('DATA', data)]).to_bytes())
def bind(self, addr): if addr in self.bindings or addr in [ addr for (_, addr, _) in self._pending_bindings ]: return self.permit(addr) self.logger.info("Requesting channel bind for {}:{}".format( self._next_channel, addr)) msg = STUNMessage('ChannelBind', [('CHANNEL-NUMBER', self._next_channel), ('XOR-PEER-ADDRESS', addr)]) self._send(msg) self._pending_bindings.append( (msg.transaction_id, addr, self._next_channel)) self._next_channel += 1
def permit(self, addr): self.logger.info("Permitting sends from {}".format(addr)) msg = STUNMessage('CreatePermission', [('XOR-PEER-ADDRESS', addr)]) self._send(msg)
""" Write directly to the TURN relay :param data: :return: """ self.writeDatagram(data, self.turn_address, self.turn_port) def sendto(self, data, address): if address in self.bindings.values(): self._logger.debug("Sending to {} through relay".format(address)) self._session.send_to(data, address) else: host, port = address self._logger.debug("Sending to {} directly".format(address)) self.writeDatagram(data, QHostAddress(host), port) def handle_data(self, (host, port), data): self._logger.debug("{}:{}/UDP<<".format(host, port)) if self._session and self._session.is_stun_message(data): self._logger.debug("Handling using turn session") response = STUNMessage.from_bytes(data) self._session.handle_response(response) else: self._logger.debug("Emitting data, len: {}".format(len(data))) self._data_cb((host, port), data) def _readyRead(self): while self.hasPendingDatagrams(): data, host, port = self.readDatagram(self.pendingDatagramSize()) self.handle_data((host.toString(), int(port)), data)