Fix UDP socket binding for WhoIs/IAm broadcast on Linux#157
Open
imurasawa wants to merge 1 commit into
Open
Conversation
This was referenced May 11, 2026
Author
|
I noticed that this file is the only one in the repository where CRLF and LF line endings are mixed. Scanning all .cs files in the repository:
This was introduced by PR #95, where shaggygi inadvertently left the header as LF while converting the rest of the file to CRLF. You can verify with PowerShell: Get-ChildItem -Recurse -Filter *.cs | ForEach-Object {
$bytes = [System.IO.File]::ReadAllBytes($_.FullName)
$text = [System.Text.Encoding]::UTF8.GetString($bytes)
$hasCRLF = $text -match "`r`n"
$hasLFonly = $text -match "(?<!`r)`n"
if ($hasCRLF -and $hasLFonly) {
Write-Output $_.FullName
}
}Should this file be normalized to LF? Happy to submit a separate PR if desired. |
This was referenced May 26, 2026
Closed
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR fixes an issue where WhoIs broadcast packets are not received on Linux (.NET 8 / Raspberry Pi 4), causing IAm responses to never be sent.
Related issues: #88, #48, #59, #93
Root Cause
On Windows, broadcast packets are forwarded to all addresses bound within the subnet. On Linux, broadcast packets are only delivered to sockets explicitly bound to the broadcast address or 0.0.0.0.
As a result:
_sharedConnis bound to a specific IP, WhoIs broadcast packets are never receivednew UdpClient(ep)binds withoutReuseAddress, causing a second bind to the same port to fail on Linux, which results in a crash when initializing_exclusiveConnChanges
File:
Transport/BacnetIpUdpProtocolTransport.csFix 1: Line 100 — Remove localEndpoint override for
_sharedConn_sharedConnmust always be bound toIPAddress.Any (0.0.0.0)in order to receive broadcast packets on Linux. Lines 97–99 are unchanged. Only the if statement on line 100 is removed._sharedConn = new UdpClient { ExclusiveAddressUse = false }; _sharedConn.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); var ep = new IPEndPoint(IPAddress.Any, SharedPort); - if (!string.IsNullOrEmpty(_localEndpoint)) ep = new IPEndPoint(IPAddress.Parse(_localEndpoint), SharedPort); DisableConnReset(_sharedConn);Fix 2: Line 112 — Add ReuseAddress for first open of
_exclusiveConnFix 3: Lines 121–124 — Add ReuseAddress for re-open of
_exclusiveConnRecommended Configuration
After this fix, the following combination is recommended on Linux:
useExclusivePort = falselocalEndpointIp= the IP address of the BACnet network interface (e.g.192.168.10.12)With this combination:
_sharedConn(bound to 0.0.0.0) handles WhoIs broadcast reception_exclusiveConn(bound to specific IP) handles unicast send/receiveGetAddressDefaultInterface()is bypassed entirely and the broadcast address is calculated correctly based on the specified IPRelationship to PR #100
PR #100 proposed changing
unicastAddresses.Single()tounicastAddresses.First()to address the issue whereGetAddressDefaultInterface()returnsnullin multi-NIC environments, causing 255.255.255.255 (which is not compliant with the BACnet standard) to be used as the broadcast address. However, the concern that "which NIC will be selected is non-deterministic" was never resolved, and the PR has not been merged.This PR avoids the problem entirely by bypassing
GetAddressDefaultInterface()whenlocalEndpointIpis explicitly specified. This approach works correctly in both of the following cases:Test Results
Before this fix (original code):
After this fix (this PR):
Legend:
Test Environment
This fix was developed and tested on .NET 8 / Linux (Raspberry Pi 4). We are using .NET 8 as recommended in response to the memory leak reported in #89. The fix itself does not depend on .NET 8 and should be applicable to net48 / netstandard2.0 as well, but has not been verified in those environments.
Windows and Mac are untested. For potential impact of
ReuseAddresson Windows, see dotnet/runtime#83525.Not Included in This PR
BACnet.csproj(related to issue Memory leak on Linux #89)