Esempio n. 1
0
async def _send_udp_message_with_retry(
    message: str,
    transport: asyncio.DatagramTransport,
    response_future: asyncio.Future,
    ip: str,
    port: int,
) -> None:
    """Send a UDP message multiple times until we reach the maximum or a response is recieved."""
    data = message.encode("utf-8")
    send_wait = FIRST_SEND_INTERVAL
    total_waited = 0.0
    for send in range(MAX_SEND_DATAGRAMS):
        if transport.is_closing() or response_future.done():
            return
        attempt = send + 1
        _LOGGER.debug(
            "%s: >> %s (%s/%s) backoff=%s",
            ip,
            data,
            attempt,
            MAX_SEND_DATAGRAMS,
            total_waited,
        )
        transport.sendto(data, (ip, port))
        await asyncio.sleep(send_wait)
        total_waited += send_wait
        send_wait = min(send_wait * 2, MAX_BACKOFF)
Esempio n. 2
0
 def connection_made(self, transport: asyncio.DatagramTransport) -> None:
     """Send SSDP request when connection was made."""
     # Prepare SSDP and send broadcast message
     for ssdp_st in SSDP_ST_LIST:
         request = ssdp_request(ssdp_st)
         transport.sendto(request, SSDP_TARGET)
         _LOGGER.debug("SSDP request sent %s", request)
Esempio n. 3
0
 def send_audio_ack(self, transport: asyncio.DatagramTransport):
     if not self.m_retrans:
         return
     sn_list = []
     lost_list = []
     for sn, rt in self.m_retrans.items():
         if rt.packet is None:
             send_ack = False
             # Loop until the packet's next retransmission time is after now.
             while rt.start < self.m_now:
                 send_ack = True
                 if not rt.next():
                     # timed-out
                     lost_list.append(rt.sn)
                     send_ack = False
                     break
             if send_ack:
                 sn_list.append(rt.sn)
     for sn in lost_list:
         del self.m_retrans[sn]
         self.lost_packtes += 1
         if self.m_log_enabled:
             self.logi('*** {}: packet {} is timed-out\n'.format(
                 self.id, rt.sn))
     if sn_list:
         pkt = self.get_audio_parser().build_audio_ack(
             self.id, sn_list, crc_off=self.m_audio_crc_off)
         transport.sendto(pkt, self.device_addr)
         self.outgoing_acks += 1
         if self.m_log_enabled:
             self.logi('*** {}: ACK {}\n'.format(self.id, sn_list))
Esempio n. 4
0
    def __call__(self, transport: DatagramTransport, message, gateway_address):
        gm = GwmpMessage.from_gateway_message(message)

        if gm.type == GwmpMessageType.PUSH_DATA:
            self.logger.info("PUSH_DATA received")
            transport.sendto(gm.get_ack(), gateway_address)  # send PUSH_ACK
            payload = json.loads(gm.payload)

            for message in payload.get("rxpk", []):
                lorawan_message = LorawanMessage.deserialize(message["data"])

                if isinstance(lorawan_message, LorawanDataMessage):
                    self.handle_lorawan_message(lorawan_message)
                else:
                    raise TypeError("LoRaWAN message type unknown")

        elif gm.type == GwmpMessageType.PULL_DATA:
            self.logger.info("PULL_DATA received")
            transport.sendto(gm.get_ack(), gateway_address)  # send PULL_ACK
            self.gateways[
                gm.gateway] = gateway_address  # save address for PULL_RESP

        elif gm.type == GwmpMessageType.TX_ACK:
            self.logger.info("TX_ACK received")
        else:
            raise TypeError("GWMP message type unknown")
Esempio n. 5
0
 def send_audio_ack(self, transport: asyncio.DatagramTransport):
     if not self.m_retrans:
         return
     sn_list = []
     lost_list = []
     for sn, rt in self.m_retrans.items():
         if rt.packet is None:
             send_ack = False
             while rt.start < self.m_now:
                 send_ack = True
                 if not rt.next():
                     lost_list.append(rt.sn)
                     # timed-out
                     if self.m_log_enabled:
                         self.logi('*** {}: packet {} is timed-out\n'.format(self.id, rt.sn))
                     break
             if send_ack:
                 sn_list.append(rt.sn)
     for sn in lost_list:
         del self.m_retrans[sn]
     if sn_list:
         pkt = self.get_audio_parser().build_audio_ack(self.id, sn_list, crc_off=self.m_audio_crc_off)
         transport.sendto(pkt, self.device_addr)
         if self.m_log_enabled:
             self.logi('*** {}: ACK {}\n'.format(self.id, sn_list))
Esempio n. 6
0
 async def _async_run_scan(
     self,
     transport: asyncio.DatagramTransport,
     destination: tuple[str, int],
     timeout: int,
     found_all_future: "asyncio.Future[bool]",
 ) -> None:
     """Send the scans."""
     _LOGGER.debug("discover: %s => %s", destination, self.DISCOVER_MESSAGE)
     transport.sendto(self.DISCOVER_MESSAGE, destination)
     quit_time = time.monotonic() + timeout
     remain_time = float(timeout)
     while True:
         time_out = min(remain_time, timeout / self.BROADCAST_FREQUENCY)
         if time_out <= 0:
             return
         try:
             await asyncio.wait_for(asyncio.shield(found_all_future),
                                    timeout=time_out)
         except asyncio.TimeoutError:
             if time.monotonic() >= quit_time:
                 return
             # No response, send broadcast again in cast it got lost
             _LOGGER.debug("discover: %s => %s", destination,
                           self.DISCOVER_MESSAGE)
             transport.sendto(self.DISCOVER_MESSAGE, destination)
         else:
             return  # found_all
         remain_time = quit_time - time.monotonic()
Esempio n. 7
0
    def connection_made(self,
                        transport: DatagramTransport) -> None:  # type: ignore
        if self._closing:
            transport.close()
            return
        assert not self._transport, "Another connection made"

        self._transport = transport
        self.create_task(self._scan_loop())
Esempio n. 8
0
    def connection_made(self, transport: asyncio.DatagramTransport) -> None:
        sock = transport.get_extra_info('socket')
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)

        for adapter in self.ifaddr.get_adapters():
            for ip in adapter.ips:
                if ip.is_IPv4:
                    net = IPv4Network("{}/{}".format(ip.ip, ip.network_prefix), strict=False)
                    if not net.is_link_local and not net.is_loopback:
                        transport.sendto(b'whoareyou?', (str(net.broadcast_address), 60010))
Esempio n. 9
0
def test_broadcast():
    """test_broadcast"""
    mock_transport = DatagramTransport()
    mock_transport.sendto = MagicMock()
    mock_protocol = protocol.AqaraProtocol()
    mock_protocol.transport = mock_transport
    test_data = {"cmd": "read"}

    mock_protocol.broadcast(test_data)

    test_data_encoded = json.dumps(test_data).encode('utf-8')
    mock_transport.sendto.assert_called_with(test_data_encoded, (MCAST_ADDR, MCAST_PORT))
Esempio n. 10
0
def test_unicast():
    """test_unicast"""
    mock_transport = DatagramTransport()
    mock_transport.sendto = MagicMock()
    mock_protocol = protocol.AqaraProtocol()
    mock_protocol.transport = mock_transport
    test_data = {"cmd": "read"}
    test_addr = "10.10.10.10"

    mock_protocol.unicast(test_addr, test_data)

    test_data_encoded = json.dumps(test_data).encode('utf-8')
    mock_transport.sendto.assert_called_with(test_data_encoded, (test_addr, GATEWAY_PORT))
Esempio n. 11
0
    def test_multicast(self):
        _ttl = None
        mock_socket = mock.MagicMock(spec=socket.socket)

        def getsockopt(*_):
            return _ttl

        def setsockopt(a, b, ttl: bytes):
            nonlocal _ttl
            _ttl, = struct.unpack('b', ttl)

        mock_socket.getsockopt = getsockopt
        mock_socket.setsockopt = setsockopt

        protocol = MulticastProtocol('1.2.3.4', '1.2.3.4')
        transport = DatagramTransport()
        transport._extra = {'socket': mock_socket}
        self.assertEqual(None, protocol.set_ttl(1))
        self.assertEqual(0, protocol.get_ttl())
        protocol.connection_made(transport)
        self.assertEqual(None, protocol.set_ttl(1))
        self.assertEqual(1, protocol.get_ttl())
Esempio n. 12
0
def async_send_with_transport(
        log_debug: bool,
        transport: asyncio.DatagramTransport,
        packet: bytes,
        packet_num: int,
        out: DNSOutgoing,
        addr: Optional[str],
        port: int,
        v6_flow_scope: Union[Tuple[()], Tuple[int, int]] = (),
) -> None:
    s = transport.get_extra_info('socket')
    ipv6_socket = s.family == socket.AF_INET6
    if addr is None:
        real_addr = _MDNS_ADDR6 if ipv6_socket else _MDNS_ADDR
    else:
        real_addr = addr
        if not can_send_to(ipv6_socket, real_addr):
            return
    if log_debug:
        log.debug(
            'Sending to (%s, %d) via [socket %s (%s)] (%d bytes #%d) %r as %r...',
            real_addr,
            port or _MDNS_PORT,
            s.fileno(),
            transport.get_extra_info('sockname'),
            len(packet),
            packet_num + 1,
            out,
            packet,
        )
    # Get flowinfo and scopeid for the IPV6 socket to create a complete IPv6
    # address tuple: https://docs.python.org/3.6/library/socket.html#socket-families
    if ipv6_socket and not v6_flow_scope:
        _, _, sock_flowinfo, sock_scopeid = s.getsockname()
        v6_flow_scope = (sock_flowinfo, sock_scopeid)
    transport.sendto(packet, (real_addr, port or _MDNS_PORT, *v6_flow_scope))
Esempio n. 13
0
 def connection_made(self, transport: asyncio.DatagramTransport):
     local_addr, port = transport.get_extra_info('sockname')
     response = self.get_response(local_addr)
     transport.sendto(response)
Esempio n. 14
0
 async def on_connect(transport: DatagramTransport) -> None:
     """Handle connection made."""
     packet = build_ssdp_search_packet(SSDP_TARGET, timeout, service_type)
     transport.sendto(packet, SSDP_TARGET)
Esempio n. 15
0
 async def on_connect(transport: DatagramTransport) -> None:
     """Handle connection made."""
     packet = build_ssdp_search_packet(target_data, timeout, service_type)
     _LOGGER.debug("Sending M-SEARCH packet")
     _LOGGER_TRAFFIC_SSDP.debug("Sending M-SEARCH packet: %s", packet)
     transport.sendto(packet, target)
Esempio n. 16
0
 def connection_made(
         self,
         transport: asyncio.DatagramTransport) -> None:  # type: ignore
     transport.sendto(self.message.raw)