Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
fe043b9
Portmapping: add windowsAddress support
richfr Mar 30, 2026
04a4541
Portmapping: add windowsAddress support
richfr Mar 30, 2026
cf34fb8
Addressing PR feedback: update wslcsdk.cpp
richfr Apr 1, 2026
954d1a0
Addressing clang formatting error
richfr Apr 1, 2026
31e28b4
Providing default values for port bindings: wslcsdk.cpp
richfr Apr 1, 2026
7ca8e51
Merge branch 'feature/wsl-for-apps' into richfr/portmapping
1wizkid Apr 1, 2026
7f1eca4
Merge branch 'feature/wsl-for-apps' into richfr/portmapping
1wizkid Apr 1, 2026
eff50d2
Fixed merge conflicts. Set default BindingAddress to 127.0.0.1. Valid…
richfr Apr 7, 2026
41a39eb
Added new function InetNtopToHresult() to map inet result error value…
richfr Apr 7, 2026
895a604
return family name if socket address is invalid
richfr Apr 7, 2026
a788da8
Removed unnecessasry variable bindingAddressStrings. Also, commented …
richfr Apr 7, 2026
644ebab
Fixed clang formatting errors
richfr Apr 7, 2026
47c28f2
Added WSLC Sdk API tests for WslcContainerPortMapping.windowsAddress …
richfr Apr 7, 2026
9ed0f18
Add unique name to containerSettings var to make test debugging from …
richfr Apr 7, 2026
fb9c466
Adjust AF_UNIX portmapping test so that it fails if value accepted
richfr Apr 8, 2026
13ba738
Return more accurate strncpy_s error result
richfr Apr 8, 2026
e482e48
Improved error return value of IP address verification
richfr Apr 8, 2026
1e7656a
Merge branch 'feature/wsl-for-apps' into richfr/portmapping
1wizkid Apr 8, 2026
f4fd0ba
Merge branch 'feature/wsl-for-apps' into richfr/portmapping
1wizkid Apr 8, 2026
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
Binary file added diagnostics/trace01.etl
Binary file not shown.
Binary file added diagnostics/trace02.etl
Binary file not shown.
85 changes: 80 additions & 5 deletions src/windows/WslcSDK/wslcsdk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,26 @@ void EnsureAbsolutePath(const std::filesystem::path& path, bool containerPath)
}
}

HRESULT InetNtopToHresult(int af, const void* src, char* dst, size_t dstCount)
{
const char* result = inet_ntop(af, src, dst, dstCount);
if (result)
{
return S_OK;
}

switch (errno)
{
case EAFNOSUPPORT:
return E_INVALIDARG;
case ENOSPC:
return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
default:
return E_FAIL;
}
}


bool CopyProcessSettingsToRuntime(WSLCProcessOptions& runtimeOptions, const WslcContainerProcessOptionsInternal* initProcessOptions)
{
if (initProcessOptions)
Expand Down Expand Up @@ -660,9 +680,11 @@ try
}

std::unique_ptr<WSLCPortMapping[]> convertedPorts;
std::vector<std::string> bindingAddressStrings;
if (internalContainerSettings->ports && internalContainerSettings->portsCount)
{
convertedPorts = std::make_unique<WSLCPortMapping[]>(internalContainerSettings->portsCount);
bindingAddressStrings.resize(internalContainerSettings->portsCount);
for (uint32_t i = 0; i < internalContainerSettings->portsCount; ++i)
{
const WslcContainerPortMapping& internalPort = internalContainerSettings->ports[i];
Expand All @@ -671,12 +693,60 @@ try
convertedPort.HostPort = internalPort.windowsPort;
convertedPort.ContainerPort = internalPort.containerPort;

// TODO: Ipv6 & custom binding address support.
convertedPort.Family = AF_INET;

// TODO: Consider using standard protocol numbers instead of our own enum.
convertedPort.Protocol = internalPort.protocol == WSLC_PORT_PROTOCOL_TCP ? IPPROTO_TCP : IPPROTO_UDP;
strcpy_s(convertedPort.BindingAddress, "127.0.0.1");
// Validate IP address if provided and if valid, copy to runtime structure.
if (internalPort.windowsAddress != nullptr)
{
char addrBuf[INET6_ADDRSTRLEN]{};
switch (internalPort.windowsAddress->ss_family)
{
case AF_INET:
{
const auto* addr4 = reinterpret_cast<const sockaddr_in*>(internalPort.windowsAddress);

HRESULT hr = InetNtopToHresult(AF_INET, &addr4->sin_addr, addrBuf, sizeof(addrBuf));
if (FAILED(hr))
{
THROW_HR_MSG(hr, "inet_ntop() failed for address family AF_INET");
}
convertedPort.Family = AF_INET;
break;
}

case AF_INET6:
{
const auto* addr6 = reinterpret_cast<const sockaddr_in6*>(internalPort.windowsAddress);
HRESULT hr = InetNtopToHresult(AF_INET6, &addr6->sin6_addr, addrBuf, sizeof(addrBuf));
if (FAILED(hr))
{
THROW_HR_MSG(hr, "inet_ntop() failed for address family AF_INET6");
}
convertedPort.Family = AF_INET6;
break;
}

default:
// Reject unsupported or malformed address families
THROW_HR(E_INVALIDARG);
}
bindingAddressStrings[i] = addrBuf;
HRESULT hr = strncpy_s(convertedPort.BindingAddress,
sizeof(convertedPort.BindingAddress),
bindingAddressStrings[i].c_str(),
_TRUNCATE);

if (hr == STRUNCATE)
{
// Log this as a warning since the address is valid but was truncated to fit in the buffer, which means the port mapping may not work as expected.
}
}
else
{
// If no binding address is provided, default to local host.
convertedPort.Family = AF_INET;
strcpy_s(convertedPort.BindingAddress, "127.0.0.1");
}
}
containerOptions.Ports = convertedPorts.get();
containerOptions.PortsCount = static_cast<ULONG>(internalContainerSettings->portsCount);
Expand Down Expand Up @@ -707,6 +777,7 @@ try
}
CATCH_RETURN();


STDAPI WslcStartContainer(_In_ WslcContainer container, _In_ WslcContainerStartFlags flags, _Outptr_opt_result_z_ PWSTR* errorMessage)
try
{
Expand Down Expand Up @@ -809,7 +880,11 @@ try

for (uint32_t i = 0; i < portMappingCount; ++i)
{
RETURN_HR_IF(E_NOTIMPL, portMappings[i].windowsAddress != nullptr);
if (portMappings[i].windowsAddress != nullptr)
{
const auto family = portMappings[i].windowsAddress->ss_family;
RETURN_HR_IF(E_INVALIDARG, family != AF_INET && family != AF_INET6);
}
RETURN_HR_IF(E_NOTIMPL, portMappings[i].protocol != 0);
}

Expand Down
Loading