Skip to content

Commit e10e537

Browse files
committed
Fix sys::socket::recvfrom for TCP sockets
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
1 parent a2bbbae commit e10e537

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)