-
-
Notifications
You must be signed in to change notification settings - Fork 168
fix(net): udp getsockname/getpeername #1460
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(net): udp getsockname/getpeername #1460
Conversation
|
@claude review this PR in Chinese |
|
Claude finished @fslongjin's task in 7m 56s —— View job 代码审查: fix(net): udp getsockname/getpeername待办事项:
分支: fix-udp-getname 审查总结这个PR修复了UDP socket的 主要变更1. 移除了冗余的本地端点缓存 (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR fixes the UDP socket getsockname and getpeername operations by implementing the remote_endpoint() method (which was previously marked as todo!()) and refactoring the local_endpoint() implementation. The changes remove the redundant cached local_endpoint field from the BoundUdp struct and instead retrieve the endpoint information directly from the underlying smoltcp socket, making the implementation more robust and consistent.
Key changes include:
- Implementation of
remote_endpoint()to return the connected remote address orENOTCONNerror - Refactored
local_endpoint()to query the socket's endpoint directly instead of using a cached field - Changed error code from
EADDRNOTAVAILtoEDESTADDRREQfor missing destination address scenarios
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| kernel/src/net/socket/inet/datagram/mod.rs | Implements remote_endpoint() and updates local_endpoint() to return proper endpoint information, including handling for unbound sockets with unspecified addresses |
| kernel/src/net/socket/inet/datagram/inner.rs | Removes the redundant local_endpoint field from BoundUdp struct and adds a remote_endpoint() method to retrieve the remote address from the lock |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| { | ||
| let mut inner_guard = self.inner.write(); | ||
| let inner = match inner_guard.take().expect("Udp Inner is None") { | ||
| let inner = match inner_guard.take().expect("Udp Inner is None") { // TODO: 此处会为空,需要DEBUG |
Copilot
AI
Dec 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The TODO comment indicates that the inner can be empty and needs debugging. However, the code uses expect() which will panic if it's None. If this is a known issue that needs to be fixed, consider using proper error handling (e.g., ok_or(SystemError::EBADF)?) instead of expect() to prevent panics. If this is not expected to be None, the TODO comment should be clarified to explain when this condition can occur.
| let inner = match inner_guard.take().expect("Udp Inner is None") { // TODO: 此处会为空,需要DEBUG | |
| let inner = match inner_guard.take().ok_or(SystemError::EBADF)? { // TODO: 此处会为空,需要DEBUG |
|
|
||
| fn remote_endpoint(&self) -> Result<Endpoint, SystemError> { | ||
| todo!() | ||
| match self.inner.read().as_ref().unwrap() { |
Copilot
AI
Dec 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of unwrap() here could panic if the inner Option is None. While the inner field is initialized as Some(UdpInner::Unbound(...)) in new(), it can be set to None via take() in the close() method (line 93). If remote_endpoint() is called after the socket is closed, this will panic. Consider using a more explicit error handling approach, such as ok_or(SystemError::EBADF)? to return an appropriate error when the socket is closed.
| match self.inner.read().as_ref().unwrap() { | |
| match self.inner.read().as_ref().ok_or(SystemError::EBADF)? { |
|
|
||
| fn local_endpoint(&self) -> Result<Endpoint, SystemError> { | ||
| use smoltcp::wire::{IpListenEndpoint, IpEndpoint, IpAddress::*}; | ||
| match self.inner.read().as_ref().unwrap() { |
Copilot
AI
Dec 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of unwrap() here could panic if the inner Option is None. While the inner field is initialized as Some(UdpInner::Unbound(...)) in new(), it can be set to None via take() in the close() method (line 93). If local_endpoint() is called after the socket is closed, this will panic. Consider using a more explicit error handling approach, such as ok_or(SystemError::EBADF)? to return an appropriate error when the socket is closed.
| match self.inner.read().as_ref().unwrap() { | |
| match self.inner.read().as_ref().ok_or(SystemError::EBADF)? { |
| _ => Err(SystemError::ENOTCONN), | ||
| UdpInner::Bound(bound) => { | ||
| let IpListenEndpoint { addr, port } = bound.endpoint(); | ||
| Ok(Endpoint::Ip(IpEndpoint::new(addr.unwrap_or(Ipv4([0, 0, 0, 0].into())), port))) |
Copilot
AI
Dec 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The hardcoded IPv4 address [0, 0, 0, 0] creates a magic number. Consider using a named constant like UNSPECIFIED_LOCAL_ENDPOINT_V4 (defined at kernel/src/net/socket/inet/mod.rs:32-33) for better maintainability and consistency with the TCP implementation.
| Ok(Endpoint::Ip(IpEndpoint::new(addr.unwrap_or(Ipv4([0, 0, 0, 0].into())), port))) | ||
| }, | ||
| // TODO: IPv6 support | ||
| _ => Ok(Endpoint::Ip(IpEndpoint::new(Ipv4([0, 0, 0, 0].into()), 0))), |
Copilot
AI
Dec 11, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The hardcoded IPv4 address [0, 0, 0, 0] and port 0 create magic numbers. Consider using a named constant like UNSPECIFIED_LOCAL_ENDPOINT_V4 (defined at kernel/src/net/socket/inet/mod.rs:32-33) for better maintainability and consistency with the TCP implementation.
03382d9 to
3a70585
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the final PR Bugbot will review for you during this billing cycle
Your free Bugbot reviews will reset on January 26
Details
You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
| remote: SpinLock::new(Some(endpoint)), | ||
| local_endpoint: endpoint, | ||
| }) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: getsockname returns wrong data after implicit bind
The bind_ephemeral function reserves an ephemeral port via port_manager().bind_ephemeral_port() but never binds the smoltcp socket to that port (unlike the bind function which explicitly calls socket.bind()). The old code stored the endpoint in a local_endpoint field and returned it correctly. The new local_endpoint() implementation relies on socket.endpoint() from the smoltcp socket, which returns incorrect/default data for sockets that went through bind_ephemeral since they were never actually bound. This causes getsockname() to return wrong data after implicit binding via sendto().
Additional Locations (1)
| let endpoint = smoltcp::wire::IpEndpoint::new(address, bound_port); | ||
| Ok(BoundUdp { | ||
| inner, | ||
| remote: SpinLock::new(Some(endpoint)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: bind_ephemeral stores local endpoint in remote field
In bind_ephemeral, the endpoint variable is constructed from the local address and local bound_port, making it the local endpoint. However, this is stored in the remote field. The newly implemented remote_endpoint() method returns this value, so getpeername() would return the local endpoint instead of the remote endpoint for sockets that went through bind_ephemeral. While this existed in the old code, it's now exposed since remote_endpoint() was changed from todo!() to an actual implementation.
Note
Implements UDP
getsockname/getpeername, refactors endpoint handling, fixes unbound send behavior, and enables gVisor socket/udp tests with blocklists.kernel/src/net/socket/inet/datagram):UdpSocket::remote_endpoint()and refinelocal_endpoint()to derive fromIpListenEndpoint(defaults to0.0.0.0:0when unbound).try_send, bind ephemeral on first send using destination address and returnEDESTADDRREQwhen destination is missing.kernel/src/net/socket/inet/datagram/inner.rs):local_endpoint; derive viasocket.endpoint().BoundUdp::remote_endpoint(); droplocal_endpoint()method.socket_testandudp_socket_testinuser/apps/tests/syscall/gvisor/whitelist.txt.socket_testand extensive cases inudp_socket_testto gate unsupported scenarios.Written by Cursor Bugbot for commit 726e143. This will update automatically on new commits. Configure here.