Browse Source

Various unix socket fixes (+socketpair!)

jD91mZM2 4 years ago
parent
commit
f8b49936bc
3 changed files with 80 additions and 28 deletions
  1. 9 0
      src/header/sys_un/mod.rs
  2. 5 5
      src/platform/redox/epoll.rs
  3. 66 23
      src/platform/redox/socket.rs

+ 9 - 0
src/header/sys_un/mod.rs

@@ -5,3 +5,12 @@ pub struct sockaddr_un {
     pub sun_family: sa_family_t,
     pub sun_path: [c_char; 108],
 }
+
+impl sockaddr_un {
+    pub fn path_len(&self) -> usize {
+        let base = self as *const _ as usize;
+        let path = &self.sun_path as *const _ as usize;
+        trace!("base: {:#X}, path: {:#X}", base, path);
+        path - base
+    }
+}

+ 5 - 5
src/platform/redox/epoll.rs

@@ -29,9 +29,9 @@ impl PalEpoll for Sys {
                         id: fd as usize,
                         flags: syscall::EventFlags::from_bits(unsafe { (*event).events as usize })
                             .expect("epoll: invalid bit pattern"),
-                        // NOTE: Danger when using non 64-bit systems. If this is
-                        // needed, use a box or something
-                        data: unsafe { mem::transmute((*event).data) },
+                        // NOTE: Danger when using something smaller than 64-bit
+                        // systems. If this is needed, use a box or something
+                        data: unsafe { (*event).data.u64 as usize },
                     },
                 ) as c_int
             }
@@ -102,7 +102,7 @@ impl PalEpoll for Sys {
         if bytes_read == -1 {
             return -1;
         }
-        let read = bytes_read as usize / mem::size_of::<epoll_event>();
+        let read = bytes_read as usize / mem::size_of::<syscall::Event>();
 
         let mut count = 0;
         for i in 0..read {
@@ -117,7 +117,7 @@ impl PalEpoll for Sys {
                 }
                 *event_ptr = epoll_event {
                     events: event.flags.bits() as _,
-                    data: mem::transmute(event.data),
+                    data: epoll_data { u64: event.data as u64, },
                     ..Default::default()
                 };
                 count += 1;

+ 66 - 23
src/platform/redox/socket.rs

@@ -32,13 +32,17 @@ macro_rules! bind_or_connect {
         0
     }};
     ($mode:ident copy, $socket:expr, $address:expr, $address_len:expr) => {{
-        if ($address_len as usize) < mem::size_of::<sockaddr>() {
+        if ($address_len as usize) < mem::size_of::<sa_family_t>() {
             errno = syscall::EINVAL;
             return -1;
         }
 
         let path = match (*$address).sa_family as c_int {
             AF_INET => {
+                if ($address_len as usize) != mem::size_of::<sockaddr_in>() {
+                    errno = syscall::EINVAL;
+                    return -1;
+                }
                 let data = &*($address as *const sockaddr_in);
                 let addr = slice::from_raw_parts(
                     &data.sin_addr.s_addr as *const _ as *const u8,
@@ -58,9 +62,10 @@ macro_rules! bind_or_connect {
             },
             AF_UNIX => {
                 let data = &*($address as *const sockaddr_un);
+                trace!("address: {:p}, data: {:p}, data2: {:#X}", $address, data, data as *const _ as usize);
                 let addr = slice::from_raw_parts(
                     &data.sun_path as *const _ as *const u8,
-                    mem::size_of_val(&data.sun_path),
+                    $address_len as usize - data.path_len(),
                 );
                 let path = format!(
                     "{}",
@@ -91,7 +96,7 @@ unsafe fn inner_af_unix(buf: &[u8], address: *mut sockaddr, address_len: *mut so
 
     let path = slice::from_raw_parts_mut(
         &mut data.sun_path as *mut _ as *mut u8,
-        mem::size_of_val(&data.sun_path),
+        data.path_len(),
     );
 
     let len = cmp::min(path.len(), buf.len());
@@ -165,6 +170,19 @@ unsafe fn inner_get_name(
     Ok(0)
 }
 
+fn socket_kind(mut kind: c_int) -> (c_int, usize) {
+    let mut flags = O_RDWR;
+    if kind & SOCK_NONBLOCK == SOCK_NONBLOCK {
+        kind &= !SOCK_NONBLOCK;
+        flags |= O_NONBLOCK;
+    }
+    if kind & SOCK_CLOEXEC == SOCK_CLOEXEC {
+        kind &= !SOCK_CLOEXEC;
+        flags |= O_CLOEXEC;
+    }
+    (kind, flags)
+}
+
 impl PalSocket for Sys {
     unsafe fn accept(socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t) -> c_int {
         let stream = e(syscall::dup(socket as usize, b"listen")) as c_int;
@@ -357,7 +375,7 @@ impl PalSocket for Sys {
         e(Err(syscall::Error::new(syscall::ENOSYS))) as c_int
     }
 
-    unsafe fn socket(domain: c_int, mut kind: c_int, protocol: c_int) -> c_int {
+    unsafe fn socket(domain: c_int, kind: c_int, protocol: c_int) -> c_int {
         if domain != AF_INET && domain != AF_UNIX {
             errno = syscall::EAFNOSUPPORT;
             return -1;
@@ -367,15 +385,7 @@ impl PalSocket for Sys {
         //     return -1;
         // }
 
-        let mut flags = O_RDWR;
-        if kind & SOCK_NONBLOCK == SOCK_NONBLOCK {
-            kind &= !SOCK_NONBLOCK;
-            flags |= O_NONBLOCK;
-        }
-        if kind & SOCK_CLOEXEC == SOCK_CLOEXEC {
-            kind &= !SOCK_CLOEXEC;
-            flags |= O_CLOEXEC;
-        }
+        let (kind, flags) = socket_kind(kind);
 
         // The tcp: and udp: schemes allow using no path,
         // and later specifying one using `dup`.
@@ -386,19 +396,52 @@ impl PalSocket for Sys {
             _ => {
                 errno = syscall::EPROTONOSUPPORT;
                 -1
-            }
+            },
         }
     }
 
     fn socketpair(domain: c_int, kind: c_int, protocol: c_int, sv: &mut [c_int; 2]) -> c_int {
-        eprintln!(
-            "socketpair({}, {}, {}, {:p})",
-            domain,
-            kind,
-            protocol,
-            sv.as_mut_ptr()
-        );
-        unsafe { errno = syscall::ENOSYS };
-        return -1;
+        let (kind, flags) = socket_kind(kind);
+
+        match (domain, kind) {
+            (AF_UNIX, SOCK_STREAM) => {
+                let listener = e(syscall::open("chan:", flags | O_CREAT));
+                if listener == !0 {
+                    return -1;
+                }
+
+                // For now, chan: lets connects be instant, and instead blocks
+                // on any I/O performed. So we don't need to mark this as
+                // nonblocking.
+
+                let fd0 = e(syscall::dup(listener, b"connect"));
+                if fd0 == !0 {
+                    let _ = syscall::close(listener);
+                    return -1;
+                }
+
+                let fd1 = e(syscall::dup(listener, b"listen"));
+                if fd1 == !0 {
+                    let _ = syscall::close(fd0);
+                    let _ = syscall::close(listener);
+                    return -1;
+                }
+
+                sv[0] = fd0 as c_int;
+                sv[1] = fd1 as c_int;
+                0
+            },
+            _ => unsafe {
+                eprintln!(
+                    "socketpair({}, {}, {}, {:p})",
+                    domain,
+                    kind,
+                    protocol,
+                    sv.as_mut_ptr()
+                );
+                errno = syscall::EPROTONOSUPPORT;
+                -1
+            },
+        }
     }
 }