Skip to main content

relibc/platform/redox/
socket.rs

1use alloc::vec::Vec;
2use core::{cmp, mem, ptr, slice, str};
3use redox_protocols::protocol::{FsCall, O_CLOEXEC, SocketCall};
4use redox_rt::proc::FdGuard;
5use syscall::{self, flag::*};
6
7use super::{
8    super::{Pal, PalSocket, types::*},
9    Sys,
10    path::dir_path_and_fd_path,
11};
12use crate::{
13    error::{Errno, Result},
14    header::{
15        arpa_inet::inet_aton,
16        bits_safamily_t::sa_family_t,
17        bits_ucred::ucred,
18        errno::{
19            EAFNOSUPPORT, EDOM, EFAULT, EINVAL, EMSGSIZE, ENOMEM, ENOSYS, ENOTSOCK, EOPNOTSUPP,
20            EPROTONOSUPPORT,
21        },
22        netinet_in::{in_addr, in_port_t, sockaddr_in},
23        string::strnlen,
24        sys_select::timeval,
25        sys_socket::{
26            CMSG_ALIGN, CMSG_DATA, CMSG_FIRSTHDR, CMSG_LEN, CMSG_NXTHDR, CMSG_SPACE, cmsghdr,
27            constants::*, msghdr, sockaddr, socklen_t,
28        },
29        sys_uio::iovec,
30        sys_un::sockaddr_un,
31    },
32};
33
34unsafe fn bind_or_connect(
35    op: SocketCall,
36    socket: c_int,
37    address: *const sockaddr,
38    address_len: socklen_t,
39) -> Result<usize, Errno> {
40    if (address_len as usize) < mem::size_of::<sa_family_t>() {
41        return Err(Errno(EINVAL));
42    }
43
44    let path = match unsafe { (*address).sa_family } as c_int {
45        AF_INET => {
46            if (address_len as usize) != mem::size_of::<sockaddr_in>() {
47                return Err(Errno(EINVAL));
48            }
49
50            let data = unsafe { &*(address as *const sockaddr_in) };
51            let addr = unsafe {
52                slice::from_raw_parts(
53                    &data.sin_addr.s_addr as *const _ as *const u8,
54                    mem::size_of_val(&data.sin_addr.s_addr),
55                )
56            };
57            let port = in_port_t::from_be(data.sin_port);
58
59            match op {
60                SocketCall::Bind => {
61                    format!("/{}.{}.{}.{}:{}", addr[0], addr[1], addr[2], addr[3], port)
62                }
63                SocketCall::Connect => {
64                    format!("{}.{}.{}.{}:{}", addr[0], addr[1], addr[2], addr[3], port)
65                }
66                _ => unreachable!(),
67            }
68        }
69        AF_UNIX => {
70            log::warn!("bind/connect with AF_UNIX were replaced with SYS_CALL.");
71            return Err(Errno(EAFNOSUPPORT));
72        }
73        AF_UNSPEC => match op {
74            SocketCall::Bind => {
75                // Bind is not a valid socket call for AF_UNSPEC
76                return Err(Errno(EAFNOSUPPORT));
77            }
78            SocketCall::Connect => {
79                // When a connect is made using AF_UNSPEC TCP and UDP need to disconnect from the default peer
80                format!("disconnect")
81            }
82            _ => unreachable!(),
83        },
84        _ => return Err(Errno(EAFNOSUPPORT)),
85    };
86    let fd = redox_rt::sys::dup(socket as usize, path.as_bytes())?;
87    Ok(fd)
88}
89
90pub unsafe fn bind_or_connect_into(
91    op: SocketCall,
92    socket: c_int,
93    address: *const sockaddr,
94    address_len: socklen_t,
95) -> Result<c_int, Errno> {
96    // Duplicate the socket, and then duplicate the copy back to the original fd
97    let fd = FdGuard::new(unsafe { bind_or_connect(op, socket, address, address_len) }?);
98    redox_rt::sys::dup2(fd.as_raw_fd(), socket as usize, &[])?;
99    Ok(0)
100}
101
102unsafe fn inner_af_unix(buf: &[u8], address: *mut sockaddr, address_len: *mut socklen_t) {
103    let data = unsafe { &mut *(address as *mut sockaddr_un) };
104
105    data.sun_family = AF_UNIX as c_ushort;
106
107    let path = unsafe {
108        slice::from_raw_parts_mut(&mut data.sun_path as *mut _ as *mut u8, data.sun_path.len())
109    };
110
111    let len = cmp::min(path.len(), buf.len());
112    path[..len].copy_from_slice(&buf[..len]);
113    if len < path.len() {
114        path[len] = 0;
115    }
116
117    unsafe { *address_len = len as socklen_t };
118}
119
120unsafe fn inner_af_inet(
121    local: bool,
122    buf: &[u8],
123    address: *mut sockaddr,
124    address_len: *mut socklen_t,
125) {
126    let mut parts = buf.split(|c| *c == b'/');
127    if local {
128        // Skip the remote part
129        parts.next();
130    }
131    let mut unparsed_addr = Vec::from(parts.next().expect("missing address"));
132
133    let sep = memchr::memchr(b':', &unparsed_addr).expect("missing port");
134    let (raw_addr, rest) = unparsed_addr.split_at_mut(sep);
135    let (colon, raw_port) = rest.split_at_mut(1);
136    let port = str::from_utf8(raw_port)
137        .expect("non-utf8 port")
138        .parse()
139        .expect("invalid port");
140
141    // Make address be followed by a NUL-byte
142    colon[0] = b'\0';
143
144    log::trace!("address: {:?}, port: {:?}", str::from_utf8(&raw_addr), port);
145
146    let mut addr = in_addr::default();
147    assert_eq!(
148        unsafe { inet_aton(raw_addr.as_ptr() as *mut c_char, &mut addr) },
149        1,
150        "inet_aton might be broken, failed to parse netstack address"
151    );
152
153    let ret = sockaddr_in {
154        sin_family: AF_INET as sa_family_t,
155        sin_port: in_port_t::to_be(port),
156        sin_addr: addr,
157
158        ..sockaddr_in::default()
159    };
160    let len = cmp::min(unsafe { *address_len } as usize, mem::size_of_val(&ret));
161
162    unsafe {
163        ptr::copy_nonoverlapping(&ret as *const _ as *const u8, address as *mut u8, len);
164        *address_len = len as socklen_t;
165    }
166}
167
168unsafe fn inner_get_name_inner(
169    local: bool,
170    address: *mut sockaddr,
171    address_len: *mut socklen_t,
172    buf: &[u8],
173) -> Result<()> {
174    if buf.starts_with(b"tcp:") || buf.starts_with(b"udp:") {
175        unsafe { inner_af_inet(local, &buf[4..], address, address_len) };
176    } else if buf.starts_with(b"/scheme/tcp/") || buf.starts_with(b"/scheme/udp/") {
177        unsafe { inner_af_inet(local, &buf[12..], address, address_len) };
178    } else if buf.starts_with(b"chan:") {
179        unsafe { inner_af_unix(&buf[5..], address, address_len) };
180    } else if buf.starts_with(b"/scheme/chan/") {
181        unsafe { inner_af_unix(&buf[13..], address, address_len) };
182    } else if buf.starts_with(b"/scheme/uds_stream/") {
183        unsafe { inner_af_unix(&buf[19..], address, address_len) };
184    } else if buf.starts_with(b"/scheme/uds_dgram/") {
185        unsafe { inner_af_unix(&buf[18..], address, address_len) };
186    } else {
187        // Socket doesn't belong to any scheme
188        log::trace!(
189            "socket {:?} doesn't match either tcp, udp or chan schemes",
190            str::from_utf8(buf)
191        );
192        return Err(Errno(ENOTSOCK));
193    }
194    Ok(())
195}
196
197fn socket_domain_type(socket: c_int) -> Result<(c_int, c_int)> {
198    let mut buf = [0; 256];
199    let len = syscall::fpath(socket as usize, &mut buf)?;
200    Ok(
201        if buf.starts_with(b"tcp:") || buf.starts_with(b"/scheme/tcp/") {
202            (AF_INET, SOCK_STREAM)
203        } else if buf.starts_with(b"udp:") || buf.starts_with(b"/scheme/udp/") {
204            (AF_INET, SOCK_DGRAM)
205        } else if buf.starts_with(b"/scheme/uds_stream/") {
206            (AF_UNIX, SOCK_STREAM)
207        } else if buf.starts_with(b"/scheme/uds_dgram/") {
208            (AF_UNIX, SOCK_DGRAM)
209        } else {
210            return Err(Errno(ENOTSOCK));
211        },
212    )
213}
214
215fn socket_kind(mut kind: c_int) -> (c_int, usize) {
216    let mut flags = O_RDWR;
217    if kind & SOCK_NONBLOCK == SOCK_NONBLOCK {
218        kind &= !SOCK_NONBLOCK;
219        flags |= O_NONBLOCK;
220    }
221    if kind & SOCK_CLOEXEC == SOCK_CLOEXEC {
222        kind &= !SOCK_CLOEXEC;
223        flags |= O_CLOEXEC;
224    }
225    (kind, flags)
226}
227
228unsafe fn serialize_payload_to_stream(
229    msg_stream: &mut Vec<u8>,
230    iovs: &[iovec],
231    whole_iov_size: usize,
232) -> Result<usize> {
233    msg_stream.extend_from_slice(&whole_iov_size.to_le_bytes());
234
235    for iov in iovs {
236        if iov.iov_len > 0 {
237            if iov.iov_base.is_null() {
238                return Err(Errno(EFAULT));
239            }
240            let source_slice: &[u8] =
241                unsafe { slice::from_raw_parts(iov.iov_base as *const u8, iov.iov_len) };
242            msg_stream.extend_from_slice(source_slice);
243        }
244    }
245    Ok(whole_iov_size)
246}
247
248unsafe fn serialize_ancillary_data_to_stream(
249    msg: *const msghdr,
250    mhdr: &msghdr,
251    socket: c_int,
252    msg_stream: &mut Vec<u8>,
253) -> Result<()> {
254    if mhdr.msg_control.is_null() {
255        return Err(Errno(EINVAL));
256    }
257
258    let mut cmsg: *mut cmsghdr = unsafe { CMSG_FIRSTHDR(msg) };
259    while !cmsg.is_null() {
260        let current_cmsg = unsafe { &*cmsg };
261        let min_cmsg_len = unsafe { CMSG_ALIGN(mem::size_of::<cmsghdr>()) };
262        if current_cmsg.cmsg_len < min_cmsg_len {
263            return Err(Errno(EINVAL));
264        }
265
266        // cmsg entry format: [level(i32)][type(i32)][data_len(usize)][data]
267        msg_stream.extend_from_slice(&current_cmsg.cmsg_level.to_le_bytes());
268        msg_stream.extend_from_slice(&current_cmsg.cmsg_type.to_le_bytes());
269
270        match (current_cmsg.cmsg_level, current_cmsg.cmsg_type) {
271            (SOL_SOCKET, SCM_RIGHTS) => {
272                let data_len = current_cmsg.cmsg_len - min_cmsg_len;
273                if data_len % mem::size_of::<c_int>() != 0 {
274                    return Err(Errno(EINVAL));
275                }
276                let fd_count = data_len / mem::size_of::<c_int>();
277
278                if fd_count > 0 {
279                    let fds_ptr = unsafe { CMSG_DATA(cmsg) } as *const c_int;
280                    let c_fds = unsafe { slice::from_raw_parts(fds_ptr, fd_count) };
281                    let fds_usize: Vec<usize> = c_fds.iter().map(|&fd| fd as usize).collect();
282                    let fds_slice = unsafe {
283                        slice::from_raw_parts(
284                            fds_usize.as_ptr() as *const u8,
285                            fds_usize.len() * mem::size_of::<usize>(),
286                        )
287                    };
288                    redox_rt::sys::sys_call_wo(socket as usize, &fds_slice, CallFlags::FD, &[])?;
289                }
290
291                // Serialize to ancillary_data_stream.
292                // Our intermediate format: data_len is size of fd_count (usize), data is fd_count (usize)
293                let data_for_stream_len = mem::size_of::<usize>();
294                let data_for_stream_payload = (fd_count as usize).to_le_bytes();
295
296                msg_stream.extend_from_slice(&(data_for_stream_len as usize).to_le_bytes());
297                msg_stream.extend_from_slice(&data_for_stream_payload);
298            }
299            (SOL_SOCKET, SCM_CREDENTIALS) => {
300                // Our intermediate format: data_len is 0, no data payload
301                let data_for_stream_len = 0usize;
302                msg_stream.extend_from_slice(&(data_for_stream_len as usize).to_le_bytes());
303            }
304            _ => {
305                return Err(Errno(EOPNOTSUPP));
306            }
307        }
308        cmsg = unsafe { CMSG_NXTHDR(msg, cmsg) };
309    }
310    Ok(())
311}
312
313unsafe fn deserialize_name_from_stream(
314    mhdr: &mut msghdr,
315    msg_stream: &[u8],
316    cursor: &mut usize,
317) -> Result<()> {
318    // Read name_len from stream
319    let name_len_in_stream = read_num::<usize>(&msg_stream[*cursor..])?;
320    let name_len = cmp::min(name_len_in_stream, mhdr.msg_namelen as usize);
321    *cursor += mem::size_of::<usize>();
322
323    if name_len > 0 {
324        if *cursor + name_len > msg_stream.len() {
325            return Err(Errno(EMSGSIZE));
326        }
327        if !mhdr.msg_name.is_null() && mhdr.msg_namelen > 0 {
328            let name_buffer = &msg_stream[*cursor..*cursor + name_len_in_stream];
329            (unsafe {
330                inner_get_name_inner(
331                    false,
332                    mhdr.msg_name as *mut sockaddr,
333                    &mut mhdr.msg_namelen,
334                    name_buffer,
335                )
336            })?;
337        }
338        *cursor += name_len_in_stream;
339    } else {
340        // If name_len is 0, set msg_namelen to 0
341        mhdr.msg_namelen = 0;
342    }
343    Ok(())
344}
345
346unsafe fn deserialize_payload_from_stream(
347    mhdr: &mut msghdr,
348    msg_stream: &[u8],
349    iovs: &[iovec],
350    whole_iov_size: usize,
351    cursor: &mut usize,
352    test: u8,
353) -> Result<usize> {
354    let full_payload_len_from_scheme = read_num::<usize>(&msg_stream[*cursor..])?;
355    *cursor += mem::size_of::<usize>();
356    // Determine actual payload data available in the stream
357    let payload_len_to_read = cmp::min(full_payload_len_from_scheme, whole_iov_size);
358    let payload_data_from_stream = &msg_stream[*cursor..*cursor + payload_len_to_read];
359    *cursor += payload_len_to_read;
360
361    let mut total_bytes_written: usize = 0;
362    if !iovs.is_empty() && payload_len_to_read > 0 {
363        let mut source_bytes_consumed: usize = 0;
364        for iov in iovs {
365            if iov.iov_len == 0 {
366                continue;
367            }
368            if iov.iov_base.is_null() {
369                return Err(Errno(EFAULT));
370            }
371
372            let source_bytes_remaining = payload_data_from_stream
373                .len()
374                .saturating_sub(source_bytes_consumed);
375            if source_bytes_remaining == 0 {
376                break;
377            }
378
379            let bytes_to_write = cmp::min(iov.iov_len, source_bytes_remaining);
380            if bytes_to_write > 0 {
381                let dest_slice: &mut [u8] =
382                    unsafe { slice::from_raw_parts_mut(iov.iov_base as *mut u8, iov.iov_len) };
383
384                let source_sub_slice = &payload_data_from_stream
385                    [source_bytes_consumed..source_bytes_consumed + bytes_to_write];
386                dest_slice[..bytes_to_write].copy_from_slice(source_sub_slice);
387                total_bytes_written += bytes_to_write;
388                source_bytes_consumed += bytes_to_write;
389            }
390        }
391    }
392
393    if full_payload_len_from_scheme > whole_iov_size {
394        mhdr.msg_flags |= MSG_TRUNC;
395    }
396
397    Ok(total_bytes_written)
398}
399
400unsafe fn deserialize_ancillary_data_from_stream(
401    mhdr: &mut msghdr,
402    socket: c_int,
403    msg_stream: &[u8],
404    cursor: &mut usize,
405    cmsg_space_provided: usize,
406    flags: c_int,
407) -> Result<()> {
408    let mut current_cmsg_ptr_in_user_buf = if !mhdr.msg_control.is_null() && cmsg_space_provided > 0
409    {
410        unsafe { CMSG_FIRSTHDR(mhdr) }
411    } else {
412        ptr::null_mut()
413    };
414    let mut remaining_user_cmsg_buf_len = cmsg_space_provided;
415    let mut total_csmg_bytes_written_to_user_buf: usize = 0;
416
417    while *cursor < msg_stream.len() {
418        const CMSG_HEADER_LEN_IN_STREAM: usize =
419            mem::size_of::<c_int>() * 2 + mem::size_of::<usize>();
420        if *cursor + CMSG_HEADER_LEN_IN_STREAM > msg_stream.len() {
421            if msg_stream[*cursor..].iter().any(|&b| b != 0) {
422                mhdr.msg_flags |= MSG_CTRUNC;
423            }
424            break;
425        }
426
427        // cmsg entry format: [level(i32)][type(i32)][data_len(usize)][data]
428        let cmsg_level = read_num::<c_int>(&msg_stream[*cursor..])?;
429        *cursor += mem::size_of::<c_int>();
430        let cmsg_type = read_num::<c_int>(&msg_stream[*cursor..])?;
431        *cursor += mem::size_of::<c_int>();
432        let cmsg_data_len_in_stream = read_num::<usize>(&msg_stream[*cursor..])?;
433        *cursor += mem::size_of::<usize>();
434
435        if *cursor + cmsg_data_len_in_stream > msg_stream.len() {
436            mhdr.msg_flags |= MSG_CTRUNC;
437            break;
438        }
439
440        let cmsg_data_from_stream = &msg_stream[*cursor..*cursor + cmsg_data_len_in_stream];
441        *cursor += cmsg_data_len_in_stream;
442
443        let mut temp_posix_cmsg_data_buf: Vec<u8> = Vec::new();
444
445        let actual_posix_cmsg_data_len = match (cmsg_level, cmsg_type) {
446            (SOL_SOCKET, SCM_RIGHTS) => {
447                if cmsg_data_len_in_stream != mem::size_of::<usize>() {
448                    return Err(Errno(EINVAL));
449                }
450                let fd_count = read_num::<usize>(&cmsg_data_from_stream)?;
451
452                let mut fds_usize = vec![0usize; fd_count];
453
454                let fds_bytes = unsafe {
455                    slice::from_raw_parts_mut(
456                        fds_usize.as_mut_ptr() as *mut u8,
457                        fds_usize.len() * mem::size_of::<usize>(),
458                    )
459                };
460
461                let mut call_flags = CallFlags::FD;
462                if flags & MSG_CMSG_CLOEXEC == MSG_CMSG_CLOEXEC {
463                    call_flags |= CallFlags::FD_CLOEXEC;
464                }
465
466                redox_rt::sys::sys_call_ro(socket as usize, fds_bytes, call_flags, &[])?;
467
468                for fd in fds_usize {
469                    temp_posix_cmsg_data_buf.extend_from_slice(&(fd as c_int).to_le_bytes());
470                }
471                temp_posix_cmsg_data_buf.len()
472            }
473            (SOL_SOCKET, SCM_CREDENTIALS) => {
474                if cmsg_data_len_in_stream
475                    != mem::size_of::<pid_t>() + mem::size_of::<uid_t>() + mem::size_of::<gid_t>()
476                {
477                    return Err(Errno(EINVAL));
478                }
479
480                let pid = read_num::<pid_t>(&cmsg_data_from_stream)?;
481                let uid_offset = mem::size_of::<pid_t>();
482                let uid = read_num::<uid_t>(&cmsg_data_from_stream[uid_offset..])?;
483                let gid_offset = uid_offset + mem::size_of::<uid_t>();
484                let gid = read_num::<gid_t>(&cmsg_data_from_stream[gid_offset..])?;
485                let cred = ucred { pid, uid, gid };
486
487                temp_posix_cmsg_data_buf.extend_from_slice(unsafe {
488                    slice::from_raw_parts(
489                        &cred as *const ucred as *const u8,
490                        mem::size_of::<ucred>(),
491                    )
492                });
493                temp_posix_cmsg_data_buf.len()
494            }
495            _ => {
496                return Err(Errno(EINVAL));
497            }
498        };
499
500        let space_needed_for_posix_cmsg =
501            unsafe { CMSG_SPACE(actual_posix_cmsg_data_len as u32) } as usize;
502
503        if !current_cmsg_ptr_in_user_buf.is_null()
504            && remaining_user_cmsg_buf_len >= space_needed_for_posix_cmsg
505        {
506            let cmsg_ref = unsafe { &mut *current_cmsg_ptr_in_user_buf };
507            cmsg_ref.cmsg_len = unsafe { CMSG_LEN(actual_posix_cmsg_data_len as u32) } as usize;
508            cmsg_ref.cmsg_level = cmsg_level;
509            cmsg_ref.cmsg_type = cmsg_type;
510
511            let data_ptr_in_user_cmsg = unsafe { CMSG_DATA(cmsg_ref) };
512            unsafe {
513                ptr::copy_nonoverlapping(
514                    temp_posix_cmsg_data_buf.as_ptr(),
515                    data_ptr_in_user_cmsg as *mut u8,
516                    actual_posix_cmsg_data_len,
517                )
518            };
519
520            let aligned_len_written = unsafe { CMSG_ALIGN(cmsg_ref.cmsg_len) };
521            total_csmg_bytes_written_to_user_buf += aligned_len_written;
522            remaining_user_cmsg_buf_len -= aligned_len_written;
523            current_cmsg_ptr_in_user_buf =
524                unsafe { CMSG_NXTHDR(mhdr, current_cmsg_ptr_in_user_buf) };
525        } else {
526            mhdr.msg_flags |= MSG_CTRUNC;
527            break;
528        }
529    }
530    mhdr.msg_controllen = total_csmg_bytes_written_to_user_buf;
531    Ok(())
532}
533
534impl PalSocket for Sys {
535    unsafe fn accept(
536        socket: c_int,
537        address: *mut sockaddr,
538        address_len: *mut socklen_t,
539    ) -> Result<c_int> {
540        let stream = redox_rt::sys::dup(socket as usize, b"listen")?;
541        if address != ptr::null_mut() && address_len != ptr::null_mut() {
542            if let Err(err) = unsafe { Self::getpeername(stream as c_int, address, address_len) } {
543                let _ = redox_rt::sys::close(stream);
544                return Err(err);
545            }
546        }
547        Ok(stream as c_int)
548    }
549
550    unsafe fn bind(socket: c_int, address: *const sockaddr, address_len: socklen_t) -> Result<()> {
551        match unsafe { (*address).sa_family } as c_int {
552            AF_INET => {
553                (unsafe { bind_or_connect_into(SocketCall::Bind, socket, address, address_len) })?;
554            }
555            AF_UNIX => {
556                let data = unsafe { &*(address as *const sockaddr_un) };
557
558                // NOTE: It's UB to access data in given address that exceeds
559                // the given address length.
560
561                let maxlen = cmp::min(
562                    // Max path length of the full-sized struct
563                    data.sun_path.len(),
564                    // Length inferred from given addrlen
565                    address_len as usize - data.path_offset(),
566                );
567                let len = cmp::min(
568                    // The maximum length of the address
569                    maxlen,
570                    // The first NUL byte, if any
571                    unsafe { strnlen(&data.sun_path as *const _, maxlen as size_t) },
572                );
573
574                let addr =
575                    unsafe { slice::from_raw_parts(&data.sun_path as *const _ as *const u8, len) };
576                let path = format!("{}", str::from_utf8(addr).unwrap());
577                log::trace!("bind(): path: {:?}", path);
578
579                let (dir_path, fd_path) = dir_path_and_fd_path(&path)?;
580
581                redox_rt::sys::sys_call_wo(
582                    socket as usize,
583                    fd_path.as_bytes(),
584                    CallFlags::empty(),
585                    &[SocketCall::Bind as u64],
586                )?;
587
588                let fs_bind_result = (|| -> Result<()> {
589                    let dirfd = FdGuard::open(
590                        &dir_path,
591                        syscall::O_RDONLY | syscall::O_DIRECTORY | O_CLOEXEC,
592                    )?;
593                    let fd_to_send =
594                        FdGuard::new(redox_rt::sys::dup_into_upper(socket as usize, &[])?)
595                            .to_upper()
596                            .unwrap();
597                    dirfd.call_wo(
598                        &fd_to_send.as_raw_fd().to_ne_bytes(),
599                        syscall::CallFlags::FD,
600                        &[],
601                    )?;
602                    Ok(())
603                })();
604
605                if let Err(original_error) = fs_bind_result {
606                    if let Err(unbind_error) = redox_rt::sys::sys_call_wo(
607                        socket as usize,
608                        &[],
609                        CallFlags::empty(),
610                        &[SocketCall::Unbind as u64],
611                    ) {
612                        todo_error!(
613                            0,
614                            unbind_error,
615                            "bind: CRITICAL: failed to unbind socket after a failed transaction"
616                        );
617                    }
618
619                    return Err(original_error);
620                }
621            }
622            _ => {
623                return Err(Errno(EAFNOSUPPORT));
624            }
625        };
626
627        Ok(())
628    }
629
630    unsafe fn connect(
631        socket: c_int,
632        address: *const sockaddr,
633        address_len: socklen_t,
634    ) -> Result<c_int> {
635        match unsafe { (*address).sa_family } as c_int {
636            AF_INET => unsafe {
637                bind_or_connect_into(SocketCall::Connect, socket, address, address_len)
638            },
639            AF_UNIX => {
640                let data = unsafe { &*(address as *const sockaddr_un) };
641
642                // NOTE: It's UB to access data in given address that exceeds
643                // the given address length.
644
645                let maxlen = cmp::min(
646                    // Max path length of the full-sized struct
647                    data.sun_path.len(),
648                    // Length inferred from given addrlen
649                    address_len as usize - data.path_offset(),
650                );
651                let len = cmp::min(
652                    // The maximum length of the address
653                    maxlen,
654                    // The first NUL byte, if any
655                    unsafe { strnlen(&data.sun_path as *const _, maxlen as size_t) },
656                );
657
658                let addr =
659                    unsafe { slice::from_raw_parts(&data.sun_path as *const _ as *const u8, len) };
660                let path = format!("{}", str::from_utf8(addr).unwrap());
661                log::trace!("connect(): path: {:?}", path);
662
663                let (_, fd_path) = dir_path_and_fd_path(&path)?;
664
665                let target_path = format!("/{fd_path}");
666                let socket_file_fd = FdGuard::open(&target_path, syscall::O_RDWR)?;
667
668                const TOKEN_BUF_SIZE: usize = 16;
669
670                let mut token_buf = [0u8; TOKEN_BUF_SIZE];
671
672                redox_rt::sys::sys_call_ro(
673                    socket_file_fd.as_raw_fd(),
674                    &mut token_buf,
675                    CallFlags::empty(),
676                    &[FsCall::Connect as u64],
677                )?;
678
679                redox_rt::sys::sys_call_wo(
680                    socket as usize,
681                    &token_buf,
682                    CallFlags::empty(),
683                    &[SocketCall::Connect as u64],
684                )?;
685                Result::<c_int, Errno>::Ok(0)
686            }
687            AF_UNSPEC => unsafe {
688                bind_or_connect_into(SocketCall::Connect, socket, address, address_len)
689            },
690            _ => Err(Errno(EAFNOSUPPORT)),
691        }
692    }
693
694    unsafe fn getpeername(
695        socket: c_int,
696        address: *mut sockaddr,
697        address_len: *mut socklen_t,
698    ) -> Result<()> {
699        let mut buf = [0; 256];
700        let len = redox_rt::sys::sys_call_ro(
701            socket as usize,
702            &mut buf,
703            CallFlags::empty(),
704            &[SocketCall::GetPeerName as u64],
705        )?;
706
707        unsafe { inner_get_name_inner(false, address, address_len, &buf[..len]) }
708    }
709
710    unsafe fn getsockname(
711        socket: c_int,
712        address: *mut sockaddr,
713        address_len: *mut socklen_t,
714    ) -> Result<()> {
715        let mut buf = [0; 256];
716        let len = syscall::fpath(socket as usize, &mut buf)?;
717
718        unsafe { inner_get_name_inner(true, address, address_len, &buf[..len]) }
719    }
720
721    unsafe fn getsockopt(
722        socket: c_int,
723        level: c_int,
724        option_name: c_int,
725        option_value: *mut c_void,
726        option_len_ptr: *mut socklen_t,
727    ) -> Result<()> {
728        if option_len_ptr.is_null() {
729            return Err(Errno(EFAULT));
730        }
731        let option_len = (unsafe { *option_len_ptr }) as usize;
732
733        let option_c_int = || -> Result<&mut c_int> {
734            if option_value.is_null() {
735                return Err(Errno(EFAULT));
736            }
737
738            if option_len < mem::size_of::<c_int>() {
739                return Err(Errno(EINVAL));
740            }
741
742            Ok(unsafe { &mut *(option_value as *mut c_int) })
743        };
744
745        match level {
746            SOL_SOCKET => match option_name {
747                SO_DOMAIN => {
748                    let option = option_c_int()?;
749                    *option = socket_domain_type(socket)?.0;
750                    unsafe { *option_len_ptr = mem::size_of::<c_int>() as socklen_t };
751                    return Ok(());
752                }
753                SO_ERROR => {
754                    let option = option_c_int()?;
755                    //TODO: Socket nonblock connection error
756                    *option = 0;
757                    unsafe { *option_len_ptr = mem::size_of::<c_int>() as socklen_t };
758                    return Ok(());
759                }
760                SO_TYPE => {
761                    let option = option_c_int()?;
762                    *option = socket_domain_type(socket)?.1;
763                    unsafe { *option_len_ptr = mem::size_of::<c_int>() as socklen_t };
764                    return Ok(());
765                }
766                _ => {
767                    let metadata = [SocketCall::GetSockOpt as u64, option_name as u64];
768                    let payload =
769                        unsafe { slice::from_raw_parts_mut(option_value as *mut u8, option_len) };
770                    let call_flags = CallFlags::empty();
771                    unsafe {
772                        *option_len_ptr = redox_rt::sys::sys_call_ro(
773                            socket as usize,
774                            payload,
775                            CallFlags::empty(),
776                            &metadata,
777                        )? as socklen_t;
778                    }
779                    return Ok(());
780                }
781            },
782            _ => (),
783        }
784
785        todo_skip!(
786            0,
787            "getsockopt({}, {}, {}, {:p}, {:p})",
788            socket,
789            level,
790            option_name,
791            option_value,
792            option_len_ptr
793        );
794        Err(Errno(ENOSYS))
795    }
796
797    fn listen(socket: c_int, backlog: c_int) -> Result<()> {
798        // Redox has no need to listen
799        Ok(())
800    }
801
802    unsafe fn recvfrom(
803        socket: c_int,
804        buf: *mut c_void,
805        len: size_t,
806        flags: c_int,
807        address: *mut sockaddr,
808        address_len: *mut socklen_t,
809    ) -> Result<usize> {
810        if address.is_null() && flags == 0 {
811            Self::read(socket, unsafe {
812                slice::from_raw_parts_mut(buf as *mut u8, len)
813            })
814        } else {
815            // Convert to recvmsg
816            let mut iov = iovec {
817                iov_base: buf,
818                iov_len: len,
819            };
820            let mut msg = msghdr {
821                msg_name: address as *mut c_void,
822                msg_namelen: if !address_len.is_null() {
823                    unsafe { *address_len }
824                } else {
825                    0
826                },
827                msg_iov: &mut iov,
828                msg_iovlen: 1,
829                msg_control: ptr::null_mut(),
830                msg_controllen: 0,
831                msg_flags: 0,
832            };
833            let count = unsafe { Self::recvmsg(socket, &mut msg, flags) }?;
834            if !address_len.is_null() {
835                unsafe { *address_len = msg.msg_namelen };
836            }
837            return Ok(count);
838        }
839    }
840
841    unsafe fn recvmsg(socket: c_int, msg: *mut msghdr, flags: c_int) -> Result<usize> {
842        if msg.is_null() {
843            return Err(Errno(EINVAL));
844        }
845        let mut mhdr = unsafe { &mut *msg };
846        let iovs_slice: &[iovec] = if mhdr.msg_iov.is_null() || mhdr.msg_iovlen == 0 {
847            &[]
848        } else {
849            unsafe { slice::from_raw_parts(mhdr.msg_iov, mhdr.msg_iovlen as usize) }
850        };
851        let whole_iov_size: usize = iovs_slice.iter().map(|iov| iov.iov_len).sum();
852
853        let mut msg_stream: Vec<u8> = Vec::new();
854
855        // Prepare space for the message stream.
856        // [name_len(usize)][name_buffer]
857        // [payload_len(usize)][payload_data_buffer]
858        // [ancillary_stream_buffer]
859        let expected_stream_size = {
860            64                             //reserve extra space for the scheme path
861            + mem::size_of::<usize>()      // name_len
862            + mhdr.msg_namelen as usize    // name_buffer
863            + mem::size_of::<usize>()      // payload_len
864            + whole_iov_size               // payload_data_buffer
865            + mem::size_of::<usize>()      // control_len
866            + mhdr.msg_controllen as usize // ancillary_stream_buffer
867        };
868        msg_stream
869            .try_reserve_exact(expected_stream_size)
870            .map_err(|_| Errno(ENOMEM))?;
871        msg_stream.resize(expected_stream_size, 0);
872
873        // Write the information about the msghdr
874        let mut cursor: usize = 0;
875        msg_stream[cursor..cursor + mem::size_of::<usize>()]
876            .copy_from_slice(&(mhdr.msg_namelen as usize).to_le_bytes());
877        cursor += mem::size_of::<usize>();
878        msg_stream[cursor..cursor + mem::size_of::<usize>()]
879            .copy_from_slice(&(whole_iov_size).to_le_bytes());
880        cursor += mem::size_of::<usize>();
881        msg_stream[cursor..cursor + mem::size_of::<usize>()]
882            .copy_from_slice(&(mhdr.msg_controllen as usize).to_le_bytes());
883
884        // Read the message stream.
885        let metadata = [SocketCall::RecvMsg as u64, flags as u64];
886        let call_flags = CallFlags::empty();
887        let actual_read_len =
888            redox_rt::sys::sys_call_rw(socket as usize, &mut msg_stream, call_flags, &metadata)?;
889        msg_stream.truncate(actual_read_len);
890
891        cursor = 0;
892        let cmsg_space_provided_by_user = mhdr.msg_controllen;
893        mhdr.msg_flags = 0;
894
895        // Read sender name.
896        (unsafe { deserialize_name_from_stream(&mut mhdr, &msg_stream, &mut cursor) })?;
897
898        // Read payload data.
899        let actual_payload_bytes_written_to_iov = unsafe {
900            deserialize_payload_from_stream(
901                &mut mhdr,
902                &msg_stream,
903                iovs_slice,
904                whole_iov_size,
905                &mut cursor,
906                0u8,
907            )
908        }?;
909
910        // Reconstruct the ancillary data in the user-provided buffer.
911        let has_cmsg_buffer = !mhdr.msg_control.is_null() && cmsg_space_provided_by_user > 0;
912        let has_ancillary_data = cursor < msg_stream.len();
913        if has_cmsg_buffer && has_ancillary_data {
914            (unsafe {
915                deserialize_ancillary_data_from_stream(
916                    mhdr,
917                    socket,
918                    &msg_stream,
919                    &mut cursor,
920                    cmsg_space_provided_by_user as usize,
921                    flags,
922                )
923            })?;
924        } else {
925            mhdr.msg_controllen = 0; // No ancillary data
926        }
927        Ok(actual_payload_bytes_written_to_iov)
928    }
929
930    unsafe fn sendmsg(socket: c_int, msg: *const msghdr, flags: c_int) -> Result<usize> {
931        if msg.is_null() {
932            return Err(Errno(EINVAL));
933        }
934        let mhdr = unsafe { &*msg };
935
936        // Reserve space for the message stream.
937        // [payload_len(usize)][payload_data_buffer]
938        // [ancillary_stream_buffer]
939        let iovs_slice: &[iovec] = if mhdr.msg_iov.is_null() || mhdr.msg_iovlen == 0 {
940            &[]
941        } else {
942            unsafe { slice::from_raw_parts(mhdr.msg_iov, mhdr.msg_iovlen as usize) }
943        };
944
945        let mut msg_stream: Vec<u8> = Vec::new();
946        let whole_iov_size: usize = iovs_slice.iter().map(|iov| iov.iov_len).sum();
947        msg_stream
948            .try_reserve_exact(
949                mem::size_of::<usize>()     // payload_len
950            + whole_iov_size                // payload_data_buffer
951            + mhdr.msg_controllen as usize, // ancillary_stream_buffer
952            )
953            .map_err(|_| Errno(ENOMEM))?;
954
955        // Write the message to the msg_stream.
956        let mut actual_payload_bytes_serialized = 0;
957        if !mhdr.msg_iov.is_null() && mhdr.msg_iovlen > 0 {
958            actual_payload_bytes_serialized = unsafe {
959                serialize_payload_to_stream(&mut msg_stream, &iovs_slice, whole_iov_size)
960            }?;
961        }
962        // Process Control Messages from msghdr and serialize them.
963        if mhdr.msg_controllen > 0 {
964            (unsafe { serialize_ancillary_data_to_stream(msg, mhdr, socket, &mut msg_stream) })?;
965        }
966
967        // Send the message stream.
968        let metadata = [SocketCall::SendMsg as u64, flags as u64];
969        let call_flags = CallFlags::empty();
970        let written = redox_rt::sys::sys_call_rw(
971            socket as usize,
972            msg_stream.as_mut_slice(),
973            call_flags,
974            &metadata,
975        )?;
976
977        Ok(actual_payload_bytes_serialized)
978    }
979
980    unsafe fn sendto(
981        socket: c_int,
982        buf: *const c_void,
983        len: size_t,
984        flags: c_int,
985        dest_addr: *const sockaddr,
986        dest_len: socklen_t,
987    ) -> Result<usize> {
988        if flags != 0 {
989            // Convert to sendmsg
990            let mut iov = iovec {
991                iov_base: buf as *mut c_void,
992                iov_len: len,
993            };
994            let msg = msghdr {
995                msg_name: dest_addr as *mut c_void,
996                msg_namelen: dest_len,
997                msg_iov: &mut iov,
998                msg_iovlen: 1,
999                msg_control: ptr::null_mut(),
1000                msg_controllen: 0,
1001                msg_flags: 0,
1002            };
1003            return unsafe { Self::sendmsg(socket, &msg, flags) };
1004        }
1005        if dest_addr == ptr::null() || dest_len == 0 {
1006            Self::write(socket, unsafe {
1007                slice::from_raw_parts(buf as *const u8, len)
1008            })
1009        } else {
1010            let fd = FdGuard::new(unsafe {
1011                bind_or_connect(SocketCall::Connect, socket, dest_addr, dest_len)
1012            }?);
1013            Self::write(fd.as_c_fd().unwrap(), unsafe {
1014                slice::from_raw_parts(buf as *const u8, len)
1015            })
1016        }
1017    }
1018
1019    unsafe fn setsockopt(
1020        socket: c_int,
1021        level: c_int,
1022        option_name: c_int,
1023        option_value: *const c_void,
1024        option_len: socklen_t,
1025    ) -> Result<()> {
1026        let set_timeout = |timeout_name: &[u8]| -> Result<()> {
1027            if option_value.is_null() {
1028                return Err(Errno(EFAULT));
1029            }
1030
1031            if (option_len as usize) < mem::size_of::<timeval>() {
1032                return Err(Errno(EINVAL));
1033            }
1034
1035            let timeval = unsafe { &*(option_value as *const timeval) };
1036
1037            let fd = FdGuard::new(redox_rt::sys::dup(socket as usize, timeout_name)?);
1038
1039            let Some(tv_nsec) = timeval.tv_usec.checked_mul(1000) else {
1040                return Err(Errno(EDOM));
1041            };
1042
1043            let timespec = syscall::TimeSpec {
1044                tv_sec: timeval.tv_sec as i64,
1045                tv_nsec,
1046            };
1047
1048            Self::write(fd.as_c_fd().unwrap(), &timespec)?;
1049            Ok(())
1050        };
1051
1052        match level {
1053            SOL_SOCKET => match option_name {
1054                SO_RCVTIMEO => return set_timeout(b"read_timeout"),
1055                SO_SNDTIMEO => return set_timeout(b"write_timeout"),
1056                _ => {
1057                    let metadata = [SocketCall::SetSockOpt as u64, option_name as u64];
1058                    let payload = unsafe {
1059                        slice::from_raw_parts_mut(option_value as *mut u8, option_len as usize)
1060                    };
1061                    let call_flags = CallFlags::empty();
1062                    redox_rt::sys::sys_call_rw(
1063                        socket as usize,
1064                        payload,
1065                        CallFlags::empty(),
1066                        &metadata,
1067                    )?;
1068                    return Ok(());
1069                }
1070            },
1071            _ => (),
1072        }
1073
1074        todo_skip!(
1075            0,
1076            "setsockopt({}, {}, {}, {:p}, {}) - unknown option",
1077            socket,
1078            level,
1079            option_name,
1080            option_value,
1081            option_len
1082        );
1083        Ok(())
1084    }
1085
1086    fn shutdown(socket: c_int, how: c_int) -> Result<()> {
1087        let metadata = [SocketCall::Shutdown as u64, how as u64];
1088        redox_rt::sys::sys_call_wo(socket as usize, &[], CallFlags::empty(), &metadata)?;
1089        Ok(())
1090    }
1091
1092    unsafe fn socket(domain: c_int, kind: c_int, protocol: c_int) -> Result<c_int> {
1093        if domain != AF_INET && domain != AF_UNIX {
1094            return Err(Errno(EAFNOSUPPORT));
1095        }
1096        // if protocol != 0 {
1097        //     ERRNO.set(syscall::EPROTONOSUPPORT);
1098        //     return -1;
1099        // }
1100
1101        let (kind, flags) = socket_kind(kind);
1102
1103        // The tcp: and udp: schemes allow using no path,
1104        // and later specifying one using `dup`.
1105        Ok(match (domain, kind) {
1106            (AF_INET, SOCK_STREAM) => redox_rt::sys::open("/scheme/tcp", flags)? as c_int,
1107            (AF_INET, SOCK_DGRAM) => redox_rt::sys::open("/scheme/udp", flags)? as c_int,
1108            (AF_UNIX, SOCK_STREAM) => {
1109                redox_rt::sys::open("/scheme/uds_stream", flags | O_CREAT)? as c_int
1110            }
1111            (AF_UNIX, SOCK_DGRAM) => {
1112                redox_rt::sys::open("/scheme/uds_dgram", flags | O_CREAT)? as c_int
1113            }
1114            _ => return Err(Errno(EPROTONOSUPPORT)),
1115        })
1116    }
1117
1118    fn socketpair(domain: c_int, kind: c_int, protocol: c_int, sv: &mut [c_int; 2]) -> Result<()> {
1119        let (kind, flags) = socket_kind(kind);
1120
1121        match (domain, kind) {
1122            (AF_UNIX, SOCK_STREAM) => {
1123                let listener = FdGuard::open("/scheme/uds_stream", flags | O_CREAT)?;
1124
1125                // For now, uds_stream: lets connects be instant, and instead blocks
1126                // on any I/O performed. So we don't need to mark this as
1127                // nonblocking.
1128
1129                let fd0 = listener.dup(b"connect")?;
1130                let fd1 = listener.dup(b"listen")?;
1131
1132                sv[0] = fd0.take() as c_int;
1133                sv[1] = fd1.take() as c_int;
1134                Ok(())
1135            }
1136            (AF_UNIX, SOCK_DGRAM) => {
1137                let listener = FdGuard::open("/scheme/uds_dgram", flags | O_CREAT)?;
1138
1139                // For now, uds_dgram: lets connects be instant, and instead blocks
1140                // on any I/O performed. So we don't need to mark this as
1141                // nonblocking.
1142
1143                let fd0 = listener.dup(b"connect")?;
1144
1145                sv[0] = fd0.take() as c_int;
1146                sv[1] = listener.take() as c_int;
1147                Ok(())
1148            }
1149            _ => {
1150                todo_skip!(
1151                    0,
1152                    "socketpair({}, {}, {}, {:p})",
1153                    domain,
1154                    kind,
1155                    protocol,
1156                    sv.as_mut_ptr()
1157                );
1158                Err(Errno(EPROTONOSUPPORT))
1159            }
1160        }
1161    }
1162}
1163
1164fn read_num<T>(buffer: &[u8]) -> Result<T>
1165where
1166    T: NumFromBytes,
1167{
1168    T::from_le_bytes_slice(buffer)
1169}
1170trait NumFromBytes: Sized {
1171    fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self>;
1172}
1173impl NumFromBytes for i32 {
1174    fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self> {
1175        Ok(i32::from_le_bytes(
1176            buffer
1177                .get(..mem::size_of::<i32>())
1178                .and_then(|slice| slice.try_into().ok())
1179                .ok_or_else(|| Errno(EFAULT))?,
1180        ))
1181    }
1182}
1183impl NumFromBytes for usize {
1184    fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self> {
1185        Ok(usize::from_le_bytes(
1186            buffer
1187                .get(..mem::size_of::<usize>())
1188                .and_then(|slice| slice.try_into().ok())
1189                .ok_or_else(|| Errno(EFAULT))?,
1190        ))
1191    }
1192}