xref: /relibc/src/platform/redox/socket.rs (revision a2f2484e4559206922b0fcc16217598a6867c8a2)
1 use core::{mem, ptr, slice, str};
2 use syscall::{self, flag::*, Result};
3 
4 use super::{
5     super::{errno, types::*, Pal, PalSocket},
6     e, Sys,
7 };
8 use crate::header::{
9     netinet_in::{in_port_t, sockaddr_in},
10     sys_socket::{constants::*, sockaddr, socklen_t},
11     sys_time::timeval,
12     sys_un::sockaddr_un,
13 };
14 
15 macro_rules! bind_or_connect {
16     (bind $path:expr) => {
17         concat!("/", $path)
18     };
19     (connect $path:expr) => {
20         $path
21     };
22     ($mode:ident into, $socket:expr, $address:expr, $address_len:expr) => {{
23         let fd = bind_or_connect!($mode copy, $socket, $address, $address_len);
24 
25         let result = syscall::dup2(fd, $socket as usize, &[]);
26         let _ = syscall::close(fd);
27         if (e(result) as c_int) < 0 {
28             return -1;
29         }
30         0
31     }};
32     ($mode:ident copy, $socket:expr, $address:expr, $address_len:expr) => {{
33         if ($address_len as usize) < mem::size_of::<sockaddr>() {
34             errno = syscall::EINVAL;
35             return -1;
36         }
37 
38         let path = match (*$address).sa_family as c_int {
39             AF_INET => {
40                 let data = &*($address as *const sockaddr_in);
41                 let addr = slice::from_raw_parts(
42                     &data.sin_addr.s_addr as *const _ as *const u8,
43                     mem::size_of_val(&data.sin_addr.s_addr),
44                 );
45                 let port = in_port_t::from_be(data.sin_port);
46                 let path = format!(
47                     bind_or_connect!($mode "{}.{}.{}.{}:{}"),
48                     addr[0],
49                     addr[1],
50                     addr[2],
51                     addr[3],
52                     port
53                 );
54 
55                 path
56             },
57             AF_UNIX => {
58                 let data = &*($address as *const sockaddr_un);
59                 let addr = slice::from_raw_parts(
60                     &data.sun_path as *const _ as *const u8,
61                     mem::size_of_val(&data.sun_path),
62                 );
63                 let path = format!(
64                     "{}",
65                     str::from_utf8(addr).unwrap()
66                 );
67 
68                 path
69             },
70             _ => {
71                 errno = syscall::EAFNOSUPPORT;
72                 return -1;
73             },
74         };
75 
76         // Duplicate the socket, and then duplicate the copy back to the original fd
77         let fd = e(syscall::dup($socket as usize, path.as_bytes()));
78         if (fd as c_int) < 0 {
79             return -1;
80         }
81         fd
82     }};
83 }
84 
85 unsafe fn inner_af_unix(buf: &[u8], address: *mut sockaddr, address_len: *mut socklen_t) {
86     let data = &mut *(address as *mut sockaddr_un);
87 
88     data.sun_family = AF_UNIX as c_ushort;
89 
90     let path = slice::from_raw_parts_mut(
91         &mut data.sun_path as *mut _ as *mut u8,
92         mem::size_of_val(&data.sun_path),
93     );
94 
95     let len = path.len().min(buf.len());
96     path[..len].copy_from_slice(&buf[..len]);
97 
98     *address_len = len as socklen_t;
99 }
100 
101 unsafe fn inner_af_inet(
102     local: bool,
103     buf: &[u8],
104     address: *mut sockaddr,
105     address_len: *mut socklen_t,
106 ) {
107     let mut parts = buf.split(|c| *c == b'/');
108     if local {
109         // Skip the remote part
110         parts.next();
111     }
112     let part = parts.next().expect("Invalid reply from netstack");
113 
114     trace!("path: {}", ::core::str::from_utf8_unchecked(&part));
115 
116     (*address).sa_family = AF_INET as c_ushort;
117 
118     let data = slice::from_raw_parts_mut(
119         &mut (*address).sa_data as *mut _ as *mut u8,
120         (*address).sa_data.len(),
121     );
122 
123     let len = data.len().min(part.len());
124     data[..len].copy_from_slice(&part[..len]);
125 
126     *address_len = len as socklen_t;
127 }
128 
129 unsafe fn inner_get_name(
130     local: bool,
131     socket: c_int,
132     address: *mut sockaddr,
133     address_len: *mut socklen_t,
134 ) -> Result<usize> {
135     // 32 should probably be large enough.
136     // Format: [udp|tcp:]remote/local, chan:path
137     let mut buf = [0; 32];
138     let len = syscall::fpath(socket as usize, &mut buf)?;
139     let buf = &buf[..len];
140     assert!(&buf[..4] == b"tcp:" || &buf[..4] == b"udp:" || &buf[..5] == b"chan:");
141 
142     match &buf[..5] {
143         b"tcp:" | b"udp:" => {
144             inner_af_inet(local, &buf[4..], address, address_len);
145         }
146         b"chan:" => {
147             inner_af_unix(&buf[5..], address, address_len);
148         }
149         // Socket doesn't belong to any scheme
150         _ => panic!("socket doesn't match either tcp, udp or chan schemes"),
151     };
152 
153     Ok(0)
154 }
155 
156 impl PalSocket for Sys {
157     unsafe fn accept(socket: c_int, address: *mut sockaddr, address_len: *mut socklen_t) -> c_int {
158         let stream = e(syscall::dup(socket as usize, b"listen")) as c_int;
159         if stream < 0 {
160             return -1;
161         }
162         if address != ptr::null_mut()
163             && address_len != ptr::null_mut()
164             && Self::getpeername(stream, address, address_len) < 0
165         {
166             return -1;
167         }
168         stream
169     }
170 
171     unsafe fn bind(socket: c_int, address: *const sockaddr, address_len: socklen_t) -> c_int {
172         bind_or_connect!(bind into, socket, address, address_len)
173     }
174 
175     unsafe fn connect(socket: c_int, address: *const sockaddr, address_len: socklen_t) -> c_int {
176         bind_or_connect!(connect into, socket, address, address_len)
177     }
178 
179     unsafe fn getpeername(
180         socket: c_int,
181         address: *mut sockaddr,
182         address_len: *mut socklen_t,
183     ) -> c_int {
184         e(inner_get_name(false, socket, address, address_len)) as c_int
185     }
186 
187     unsafe fn getsockname(
188         socket: c_int,
189         address: *mut sockaddr,
190         address_len: *mut socklen_t,
191     ) -> c_int {
192         e(inner_get_name(true, socket, address, address_len)) as c_int
193     }
194 
195     fn getsockopt(
196         socket: c_int,
197         level: c_int,
198         option_name: c_int,
199         option_value: *mut c_void,
200         option_len: *mut socklen_t,
201     ) -> c_int {
202         match level {
203             SOL_SOCKET => match option_name {
204                 SO_ERROR => {
205                     if option_value.is_null() {
206                         return e(Err(syscall::Error::new(syscall::EFAULT))) as c_int;
207                     }
208 
209                     if (option_len as usize) < mem::size_of::<c_int>() {
210                         return e(Err(syscall::Error::new(syscall::EINVAL))) as c_int;
211                     }
212 
213                     let error = unsafe { &mut *(option_value as *mut c_int) };
214                     //TODO: Socket nonblock connection error
215                     *error = 0;
216 
217                     return 0;
218                 },
219                 _ => (),
220             },
221             _ => (),
222         }
223 
224         eprintln!(
225             "getsockopt({}, {}, {}, {:p}, {:p})",
226             socket, level, option_name, option_value, option_len
227         );
228         e(Err(syscall::Error::new(syscall::ENOSYS))) as c_int
229     }
230 
231     fn listen(socket: c_int, backlog: c_int) -> c_int {
232         // Redox has no need to listen
233         0
234     }
235 
236     unsafe fn recvfrom(
237         socket: c_int,
238         buf: *mut c_void,
239         len: size_t,
240         flags: c_int,
241         address: *mut sockaddr,
242         address_len: *mut socklen_t,
243     ) -> ssize_t {
244         if flags != 0 {
245             errno = syscall::EOPNOTSUPP;
246             return -1;
247         }
248         if address == ptr::null_mut() || address_len == ptr::null_mut() {
249             Self::read(socket, slice::from_raw_parts_mut(buf as *mut u8, len))
250         } else {
251             let fd = e(syscall::dup(socket as usize, b"listen"));
252             if fd == !0 {
253                 return -1;
254             }
255             if Self::getpeername(fd as c_int, address, address_len) < 0 {
256                 let _ = syscall::close(fd);
257                 return -1;
258             }
259 
260             let ret = Self::read(fd as c_int, slice::from_raw_parts_mut(buf as *mut u8, len));
261             let _ = syscall::close(fd);
262             ret
263         }
264     }
265 
266     unsafe fn sendto(
267         socket: c_int,
268         buf: *const c_void,
269         len: size_t,
270         flags: c_int,
271         dest_addr: *const sockaddr,
272         dest_len: socklen_t,
273     ) -> ssize_t {
274         if flags != 0 {
275             errno = syscall::EOPNOTSUPP;
276             return -1;
277         }
278         if dest_addr == ptr::null() || dest_len == 0 {
279             Self::write(socket, slice::from_raw_parts(buf as *const u8, len))
280         } else {
281             let fd = bind_or_connect!(connect copy, socket, dest_addr, dest_len);
282             let ret = Self::write(fd as c_int, slice::from_raw_parts(buf as *const u8, len));
283             let _ = syscall::close(fd);
284             ret
285         }
286     }
287 
288     fn setsockopt(
289         socket: c_int,
290         level: c_int,
291         option_name: c_int,
292         option_value: *const c_void,
293         option_len: socklen_t,
294     ) -> c_int {
295         let set_timeout = |timeout_name: &[u8]| -> c_int {
296             if option_value.is_null() {
297                 return e(Err(syscall::Error::new(syscall::EFAULT))) as c_int;
298             }
299 
300             if (option_len as usize) < mem::size_of::<timeval>() {
301                 return e(Err(syscall::Error::new(syscall::EINVAL))) as c_int;
302             }
303 
304             let timeval = unsafe { &*(option_value as *const timeval) };
305 
306             let fd = e(syscall::dup(socket as usize, timeout_name));
307             if fd == !0 {
308                 return -1;
309             }
310 
311             let timespec = syscall::TimeSpec {
312                 tv_sec: timeval.tv_sec,
313                 tv_nsec: timeval.tv_usec * 1000,
314             };
315 
316             let ret = Self::write(fd as c_int, &timespec);
317 
318             let _ = syscall::close(fd);
319 
320             if ret >= 0 {
321                 0
322             } else {
323                 -1
324             }
325         };
326 
327         match level {
328             SOL_SOCKET => match option_name {
329                 SO_RCVTIMEO => return set_timeout(b"read_timeout"),
330                 SO_SNDTIMEO => return set_timeout(b"write_timeout"),
331                 _ => (),
332             },
333             _ => (),
334         }
335 
336         eprintln!(
337             "setsockopt({}, {}, {}, {:p}, {})",
338             socket, level, option_name, option_value, option_len
339         );
340         e(Err(syscall::Error::new(syscall::ENOSYS))) as c_int
341     }
342 
343     fn shutdown(socket: c_int, how: c_int) -> c_int {
344         eprintln!("shutdown({}, {})", socket, how);
345         e(Err(syscall::Error::new(syscall::ENOSYS))) as c_int
346     }
347 
348     unsafe fn socket(domain: c_int, mut kind: c_int, protocol: c_int) -> c_int {
349         if domain != AF_INET && domain != AF_UNIX {
350             errno = syscall::EAFNOSUPPORT;
351             return -1;
352         }
353         // if protocol != 0 {
354         //     errno = syscall::EPROTONOSUPPORT;
355         //     return -1;
356         // }
357 
358         let mut flags = O_RDWR;
359         if kind & SOCK_NONBLOCK == SOCK_NONBLOCK {
360             kind &= !SOCK_NONBLOCK;
361             flags |= O_NONBLOCK;
362         }
363         if kind & SOCK_CLOEXEC == SOCK_CLOEXEC {
364             kind &= !SOCK_CLOEXEC;
365             flags |= O_CLOEXEC;
366         }
367 
368         // The tcp: and udp: schemes allow using no path,
369         // and later specifying one using `dup`.
370         match (domain, kind) {
371             (AF_INET, SOCK_STREAM) => e(syscall::open("tcp:", flags)) as c_int,
372             (AF_INET, SOCK_DGRAM) => e(syscall::open("udp:", flags)) as c_int,
373             (AF_UNIX, SOCK_STREAM) => e(syscall::open("chan:", flags | O_CREAT)) as c_int,
374             _ => {
375                 errno = syscall::EPROTONOSUPPORT;
376                 -1
377             }
378         }
379     }
380 
381     fn socketpair(domain: c_int, kind: c_int, protocol: c_int, sv: &mut [c_int; 2]) -> c_int {
382         eprintln!(
383             "socketpair({}, {}, {}, {:p})",
384             domain,
385             kind,
386             protocol,
387             sv.as_mut_ptr()
388         );
389         unsafe { errno = syscall::ENOSYS };
390         return -1;
391     }
392 }
393