Skip to content
This repository was archived by the owner on Sep 18, 2025. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions tests/test_listener.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import pytest

import ucp


@pytest.mark.asyncio
async def test_bind_ip():
listener = ucp.create_listener(lambda: None, ip_address="127.0.0.1")

assert isinstance(listener.port, int)
assert listener.port >= 1024

assert isinstance(listener.ip, str)
assert listener.ip == "127.0.0.1"


@pytest.mark.asyncio
async def test_bind_port():
listener = None
port = None

for i in range(10000, 20000):
try:
listener = ucp.create_listener(
lambda: None,
i,
)
except ucp.UCXError:
# Port already in use, try another
continue
else:
port = i
break

assert isinstance(listener.port, int)
assert listener.port == port

assert isinstance(listener.ip, str)
14 changes: 12 additions & 2 deletions ucp/_libs/ucx_listener.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ cdef class UCXListener(UCXObject):
Extra arguments to the call-back function
cb_kwargs: dict, optional
Extra keyword arguments to the call-back function
ip_address: str, optional
IP address to bind the listener to. Binds to `0.0.0.0` if not
specified.

Returns
-------
Expand All @@ -69,7 +72,8 @@ cdef class UCXListener(UCXObject):
uint16_t port,
cb_func,
tuple cb_args=None,
dict cb_kwargs=None
dict cb_kwargs=None,
str ip_address=None,
):
if cb_args is None:
cb_args = ()
Expand All @@ -90,7 +94,13 @@ cdef class UCXListener(UCXObject):
)
params.conn_handler.cb = _listener_cb
params.conn_handler.arg = <void*> self.cb_data
if c_util_set_sockaddr(&params.sockaddr, NULL, port):

cdef alloc_sockaddr_ret = (
c_util_set_sockaddr(&params.sockaddr, NULL, port)
if ip_address is None else
c_util_set_sockaddr(&params.sockaddr, ip_address.encode(), port)
)
if alloc_sockaddr_ret:
raise MemoryError("Failed allocation of sockaddr")

cdef ucs_status_t status = ucp_listener_create(
Expand Down
10 changes: 9 additions & 1 deletion ucp/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ def create_listener(
callback_func,
port=0,
endpoint_error_handling=True,
ip_address=None,
):
"""Create and start a listener to accept incoming connections

Expand All @@ -257,6 +258,9 @@ def create_listener(
but prevents a process from terminating unexpectedly that may
happen when disabled. If `False` endpoint endpoint error handling
is disabled.
ip_address: str, optional
IP address to bind the listener to. Binds to `0.0.0.0` if not
specified.

Returns
-------
Expand All @@ -274,6 +278,7 @@ def create_listener(
port=port,
cb_func=_listener_handler,
cb_args=(callback_func, self, endpoint_error_handling),
ip_address=ip_address,
)
)
return ret
Expand Down Expand Up @@ -992,11 +997,14 @@ def register_am_allocator(allocator, allocator_type):
return _get_ctx().register_am_allocator(allocator, allocator_type)


def create_listener(callback_func, port=None, endpoint_error_handling=True):
def create_listener(
callback_func, port=None, endpoint_error_handling=True, ip_address=None
):
return _get_ctx().create_listener(
callback_func,
port,
endpoint_error_handling=endpoint_error_handling,
ip_address=ip_address,
)


Expand Down