Skip to content

Commit

Permalink
add changes from aiortc#63
Browse files Browse the repository at this point in the history
  • Loading branch information
ksadov committed Feb 15, 2024
1 parent fe817e6 commit a9bd8ad
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 6 deletions.
12 changes: 7 additions & 5 deletions src/aioice/ice.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
import socket
import threading
from itertools import count
from typing import Dict, List, Optional, Set, Text, Tuple, Union, cast
from typing import Dict, Iterable, List, Optional, Set, Text, Tuple, Union, cast

import ifaddr

from . import mdns, stun, turn
from .candidate import Candidate, candidate_foundation, candidate_priority
from .utils import random_string
from .utils import create_datagram_endpoint, random_string

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -295,6 +295,7 @@ class Connection:
:param use_ipv4: Whether to use IPv4 candidates.
:param use_ipv6: Whether to use IPv6 candidates.
:param transport_policy: Transport policy.
:param ephemeral_ports: Set of allowed ephemeral local ports to bind to.
"""

def __init__(
Expand All @@ -310,6 +311,7 @@ def __init__(
use_ipv4: bool = True,
use_ipv6: bool = True,
transport_policy: TransportPolicy = TransportPolicy.ALL,
ephemeral_ports: Optional[Iterable[int]] = None,
) -> None:
self.ice_controlling = ice_controlling
#: Local username, automatically set to a random value.
Expand Down Expand Up @@ -355,6 +357,7 @@ def __init__(
self._tie_breaker = secrets.randbits(64)
self._use_ipv4 = use_ipv4
self._use_ipv6 = use_ipv6
self._ephemeral_ports = ephemeral_ports

if (
stun_server is None
Expand Down Expand Up @@ -888,9 +891,8 @@ async def get_component_candidates(
for address in addresses:
# create transport
try:
transport, protocol = await loop.create_datagram_endpoint(
lambda: StunProtocol(self), local_addr=(address, 0)
)
transport, protocol = await create_datagram_endpoint(
lambda: StunProtocol(self), local_address=address, local_ports=self._ephemeral_ports)
sock = transport.get_extra_info("socket")
if sock is not None:
sock.setsockopt(
Expand Down
35 changes: 34 additions & 1 deletion src/aioice/utils.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,45 @@
import asyncio
import os
import random
import secrets
import string
from typing import Iterable, Optional, Tuple


def random_string(length: int) -> str:
allchar = string.ascii_letters + string.digits
return "".join(secrets.choice(allchar) for x in range(length))


def random_transaction_id() -> bytes:
return os.urandom(12)


async def create_datagram_endpoint(protocol_factory,
remote_addr: Tuple[str, int] = None,
local_address: str = None,
local_ports: Optional[Iterable[int]] = None,
):
"""
Asynchronousley create a datagram endpoint.
:param protocol_factory: Callable returning a protocol instance.
:param remote_addr: Remote address and port.
:param local_address: Local address to bind to.
:param local_ports: Set of allowed local ports to bind to.
"""
if local_ports is not None:
ports = list(local_ports)
random.shuffle(ports)
else:
ports = (0,)
loop = asyncio.get_event_loop()
for port in ports:
try:
transport, protocol = await loop.create_datagram_endpoint(
protocol_factory, remote_addr=remote_addr, local_addr=(local_address, port)
)
return transport, protocol
except OSError as exc:
if port == ports[-1]:
# this was the last port, give up
raise exc
raise ValueError("local_ports must not be empty")

0 comments on commit a9bd8ad

Please sign in to comment.