Skip to content

Commit 2e52ce8

Browse files
bors[bot]asomers
andauthored
Merge #1145
1145: Fix sys::socket::recvfrom for TCP sockets r=asomers a=asomers recvfrom(2) only returns the sender's address for protocols that provide it. Usually, that means it returns the sender's address for datagram sockets but not for stream sockets. Fixes #1144 Co-authored-by: Alan Somers <[email protected]>
2 parents a2bbbae + e10e537 commit 2e52ce8

File tree

3 files changed

+82
-5
lines changed

3 files changed

+82
-5
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).
1919
([#1133](https://github.com/nix-rust/nix/pull/1133))
2020

2121
### Changed
22+
- `sys::socket::recvfrom` now returns
23+
`Result<(usize, Option<SockAddr>)>` instead of `Result<(usize, SockAddr)>`.
24+
([#1145](https://github.com/nix-rust/nix/pull/1145))
25+
2226
- `Signal::from_c_int` has been replaced by `Signal::try_from`
2327
([#1113](https://github.com/nix-rust/nix/pull/1113))
2428

src/sys/socket/mod.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,10 +1075,13 @@ pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> {
10751075
}
10761076

10771077
/// Receive data from a connectionless or connection-oriented socket. Returns
1078-
/// the number of bytes read and the socket address of the sender.
1078+
/// the number of bytes read and, for connectionless sockets, the socket
1079+
/// address of the sender.
10791080
///
10801081
/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html)
1081-
pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) -> Result<(usize, SockAddr)> {
1082+
pub fn recvfrom(sockfd: RawFd, buf: &mut [u8])
1083+
-> Result<(usize, Option<SockAddr>)>
1084+
{
10821085
unsafe {
10831086
let mut addr: sockaddr_storage = mem::zeroed();
10841087
let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
@@ -1089,10 +1092,13 @@ pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) -> Result<(usize, SockAddr)> {
10891092
buf.len() as size_t,
10901093
0,
10911094
&mut addr as *mut libc::sockaddr_storage as *mut libc::sockaddr,
1092-
&mut len as *mut socklen_t))?;
1095+
&mut len as *mut socklen_t))? as usize;
10931096

1094-
sockaddr_storage_to_addr(&addr, len as usize)
1095-
.map(|addr| (ret as usize, addr))
1097+
match sockaddr_storage_to_addr(&addr, len as usize) {
1098+
Err(Error::Sys(Errno::ENOTCONN)) => Ok((ret, None)),
1099+
Ok(addr) => Ok((ret, Some(addr))),
1100+
Err(e) => Err(e)
1101+
}
10961102
}
10971103
}
10981104

test/sys/test_socket.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,73 @@ pub fn test_socketpair() {
161161
assert_eq!(&buf[..], b"hello");
162162
}
163163

164+
mod recvfrom {
165+
use nix::Result;
166+
use nix::sys::socket::*;
167+
use std::thread;
168+
use super::*;
169+
170+
const MSG: &'static [u8] = b"Hello, World!";
171+
172+
fn sendrecv<F>(rsock: RawFd, ssock: RawFd, f: F) -> Option<SockAddr>
173+
where F: Fn(RawFd, &[u8], MsgFlags) -> Result<usize> + Send + 'static
174+
{
175+
let mut buf: [u8; 13] = [0u8; 13];
176+
let mut l = 0;
177+
let mut from = None;
178+
179+
let send_thread = thread::spawn(move || {
180+
let mut l = 0;
181+
while l < std::mem::size_of_val(MSG) {
182+
l += f(ssock, &MSG[l..], MsgFlags::empty()).unwrap();
183+
}
184+
});
185+
186+
while l < std::mem::size_of_val(MSG) {
187+
let (len, from_) = recvfrom(rsock, &mut buf[l..]).unwrap();
188+
from = from_;
189+
l += len;
190+
}
191+
assert_eq!(&buf, MSG);
192+
send_thread.join().unwrap();
193+
from
194+
}
195+
196+
#[test]
197+
pub fn stream() {
198+
let (fd2, fd1) = socketpair(AddressFamily::Unix, SockType::Stream,
199+
None, SockFlag::empty()).unwrap();
200+
// Ignore from for stream sockets
201+
let _ = sendrecv(fd1, fd2, |s, m, flags| {
202+
send(s, m, flags)
203+
});
204+
}
205+
206+
#[test]
207+
pub fn udp() {
208+
let std_sa = SocketAddr::from_str("127.0.0.1:6789").unwrap();
209+
let inet_addr = InetAddr::from_std(&std_sa);
210+
let sock_addr = SockAddr::new_inet(inet_addr);
211+
let rsock = socket(AddressFamily::Inet,
212+
SockType::Datagram,
213+
SockFlag::empty(),
214+
None
215+
).unwrap();
216+
bind(rsock, &sock_addr).unwrap();
217+
let ssock = socket(
218+
AddressFamily::Inet,
219+
SockType::Datagram,
220+
SockFlag::empty(),
221+
None,
222+
).expect("send socket failed");
223+
let from = sendrecv(rsock, ssock, move |s, m, flags| {
224+
sendto(s, m, &sock_addr, flags)
225+
});
226+
// UDP sockets should set the from address
227+
assert_eq!(AddressFamily::Inet, from.unwrap().family());
228+
}
229+
}
230+
164231
// Test error handling of our recvmsg wrapper
165232
#[test]
166233
pub fn test_recvmsg_ebadf() {

0 commit comments

Comments
 (0)