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}