vita_newlib_shims/
lib.rs

1#![no_std]
2#![feature(c_variadic)]
3
4#[no_mangle]
5#[allow(clippy::missing_safety_doc)]
6#[cfg(all(target_os = "vita", feature = "socketpair"))]
7pub unsafe extern "C" fn socketpair(
8    _domain: libc::c_int,
9    r#type: libc::c_int,
10    protocol: libc::c_int,
11    socket_vector: *mut libc::c_int,
12) -> libc::c_int {
13    let mut server_addr: libc::sockaddr_in = core::mem::zeroed();
14    let mut addr_len: libc::socklen_t =
15        core::mem::size_of::<libc::sockaddr_in>() as libc::socklen_t;
16
17    let listener = libc::socket(libc::AF_INET, r#type, protocol);
18    if listener == -1 {
19        return -1;
20    }
21
22    server_addr.sin_family = libc::AF_INET as libc::sa_family_t;
23    server_addr.sin_port = 0;
24    server_addr.sin_addr.s_addr = libc::INADDR_LOOPBACK.to_be();
25
26    if libc::bind(listener, &mut server_addr as *mut _ as *mut _, addr_len) == -1 {
27        with_errno(|| {
28            libc::close(listener);
29        });
30        return -1;
31    }
32
33    if libc::listen(listener, 1) == -1 {
34        with_errno(|| {
35            libc::close(listener);
36        });
37        return -1;
38    }
39
40    if libc::getsockname(
41        listener,
42        &mut server_addr as *mut _ as *mut _,
43        &mut addr_len,
44    ) == -1
45    {
46        with_errno(|| {
47            libc::close(listener);
48        });
49        return -1;
50    }
51
52    let client_socket: libc::c_int = libc::socket(libc::AF_INET, r#type, protocol);
53    if client_socket == -1 {
54        with_errno(|| {
55            libc::close(listener);
56        });
57        return -1;
58    }
59
60    if libc::connect(
61        client_socket,
62        &mut server_addr as *mut _ as *mut _,
63        addr_len,
64    ) == -1
65    {
66        with_errno(|| {
67            libc::close(client_socket);
68            libc::close(listener);
69        });
70        return -1;
71    }
72
73    let peer_socket: libc::c_int = libc::accept(
74        listener,
75        &mut server_addr as *mut _ as *mut _,
76        &mut addr_len,
77    );
78    if peer_socket == -1 {
79        with_errno(|| {
80            libc::close(client_socket);
81            libc::close(listener);
82        });
83        return -1;
84    }
85
86    socket_vector.offset(0).write(peer_socket);
87    socket_vector.offset(1).write(client_socket);
88
89    libc::close(listener);
90
91    0
92}
93
94#[no_mangle]
95#[allow(clippy::missing_safety_doc)]
96#[cfg(all(target_os = "vita", feature = "pipe2"))]
97pub unsafe extern "C" fn pipe2(pipefd: &mut [libc::c_int; 2], flags: libc::c_int) -> libc::c_int {
98    #[cfg(not(feature = "socketpair"))]
99    use libc::socketpair;
100
101    if socketpair(libc::AF_INET, libc::SOCK_STREAM, 0, pipefd.as_mut_ptr()) == -1 {
102        return -1;
103    }
104
105    let pipefd = *pipefd;
106    for fd in pipefd {
107        let linger = libc::linger {
108            l_onoff: 1,
109            l_linger: 0,
110        };
111        if setsockopt(fd, libc::SOL_SOCKET, libc::SO_LINGER, linger) == -1 {
112            with_errno(|| {
113                libc::close(pipefd[0]);
114                libc::close(pipefd[1]);
115            });
116            return -1;
117        }
118    }
119
120    if flags & libc::O_NONBLOCK != 0 {
121        for fd in pipefd {
122            if setsockopt(fd, libc::SOL_SOCKET, libc::SO_NONBLOCK, 1) == -1 {
123                with_errno(|| {
124                    libc::close(pipefd[0]);
125                    libc::close(pipefd[1]);
126                });
127                return -1;
128            }
129        }
130    }
131
132    0
133}
134
135#[cfg(all(
136    target_os = "vita",
137    any(feature = "pipe2", feature = "socketpair", feature = "fcntl")
138))]
139extern "C" {
140    #[cfg_attr(target_os = "vita", link_name = "__errno")]
141    fn errno_location() -> *mut libc::c_int;
142}
143
144#[cfg(all(target_os = "vita", any(feature = "pipe2", feature = "socketpair")))]
145unsafe fn with_errno(mut f: impl FnMut()) {
146    let errno = *errno_location();
147    f();
148    *errno_location() = errno as libc::c_int;
149}
150
151#[no_mangle]
152#[allow(clippy::missing_safety_doc)]
153#[cfg(all(target_os = "vita", feature = "fcntl"))]
154pub unsafe extern "C" fn fcntl(fd: libc::c_int, cmd: libc::c_int, mut args: ...) -> libc::c_int {
155    let mut arg: libc::c_int = 0;
156
157    if cmd == libc::F_SETFL {
158        arg = args.arg::<libc::c_int>();
159    }
160
161    match cmd {
162        libc::F_GETFD => 0,
163        libc::F_GETFL => {
164            let mut val: libc::c_int = 0;
165
166            let res = getsockopt(fd, libc::SOL_SOCKET, libc::SO_NONBLOCK, &mut val);
167            if res == -1 {
168                return -1;
169            }
170
171            match val {
172                0 => 0,
173                _ => libc::O_NONBLOCK,
174            }
175        }
176        libc::F_SETFL => {
177            let val = (arg & libc::O_NONBLOCK) != 0;
178            setsockopt(fd, libc::SOL_SOCKET, libc::SO_NONBLOCK, val as libc::c_int)
179        }
180        _ => {
181            *errno_location() = libc::ENOTSUP;
182            -1
183        }
184    }
185}
186
187#[cfg(all(target_os = "vita", any(feature = "pipe2", feature = "fcntl")))]
188unsafe fn setsockopt<T>(
189    fd: libc::c_int,
190    level: libc::c_int,
191    name: libc::c_int,
192    val: T,
193) -> libc::c_int {
194    libc::setsockopt(
195        fd,
196        level,
197        name,
198        &val as *const _ as *const _,
199        core::mem::size_of::<T>() as libc::socklen_t,
200    )
201}
202
203#[cfg(all(target_os = "vita", feature = "fcntl"))]
204unsafe fn getsockopt<T>(
205    fd: libc::c_int,
206    level: libc::c_int,
207    name: libc::c_int,
208    val: &mut T,
209) -> libc::c_int {
210    let mut len: libc::socklen_t = core::mem::size_of::<T>() as libc::socklen_t;
211    libc::getsockopt(
212        fd,
213        level,
214        name,
215        val as *mut _ as *mut _,
216        &mut len as *mut _ as *mut _,
217    )
218}