2 * Copyright 2002-2008, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
7 The socket API directly forwards all requests into the kernel stack
8 via the networking stack driver.
11 #include <r5_compatibility.h>
14 #include <netinet/in.h>
18 #include <sys/ioctl.h>
21 #include <syscall_utils.h>
27 convert_from_r5_sockaddr(struct sockaddr
*_to
, const struct sockaddr
*_from
)
29 const r5_sockaddr_in
*from
= (r5_sockaddr_in
*)_from
;
30 sockaddr_in
*to
= (sockaddr_in
*)_to
;
32 memset(to
, 0, sizeof(sockaddr
));
33 to
->sin_len
= sizeof(sockaddr
);
38 if (from
->sin_family
== R5_AF_INET
)
39 to
->sin_family
= AF_INET
;
41 to
->sin_family
= from
->sin_family
;
43 to
->sin_port
= from
->sin_port
;
44 to
->sin_addr
.s_addr
= from
->sin_addr
;
49 convert_to_r5_sockaddr(struct sockaddr
*_to
,
50 const struct sockaddr
*_from
)
52 const sockaddr_in
*from
= (sockaddr_in
*)_from
;
53 r5_sockaddr_in
*to
= (r5_sockaddr_in
*)_to
;
58 memset(to
, 0, sizeof(r5_sockaddr_in
));
60 if (from
->sin_family
== AF_INET
)
61 to
->sin_family
= R5_AF_INET
;
63 to
->sin_family
= from
->sin_family
;
65 to
->sin_port
= from
->sin_port
;
66 to
->sin_addr
= from
->sin_addr
.s_addr
;
71 convert_from_r5_socket(int& family
, int& type
, int& protocol
)
95 protocol
= IPPROTO_UDP
;
98 protocol
= IPPROTO_TCP
;
100 case R5_IPPROTO_ICMP
:
101 protocol
= IPPROTO_ICMP
;
108 convert_from_r5_sockopt(int& level
, int& option
)
110 if (level
== R5_SOL_SOCKET
)
117 case R5_SO_REUSEADDR
:
118 option
= SO_REUSEADDR
;
121 option
= SO_NONBLOCK
;
123 case R5_SO_REUSEPORT
:
124 option
= SO_REUSEPORT
;
127 // there is no SO_FIONREAD
138 socket(int family
, int type
, int protocol
)
140 if (check_r5_compatibility())
141 convert_from_r5_socket(family
, type
, protocol
);
143 RETURN_AND_SET_ERRNO(_kern_socket(family
, type
, protocol
));
148 bind(int socket
, const struct sockaddr
*address
, socklen_t addressLength
)
150 struct sockaddr haikuAddr
;
152 if (check_r5_compatibility()) {
153 convert_from_r5_sockaddr(&haikuAddr
, address
);
154 address
= &haikuAddr
;
155 addressLength
= sizeof(struct sockaddr_in
);
158 RETURN_AND_SET_ERRNO(_kern_bind(socket
, address
, addressLength
));
163 shutdown(int socket
, int how
)
165 RETURN_AND_SET_ERRNO(_kern_shutdown_socket(socket
, how
));
170 connect(int socket
, const struct sockaddr
*address
, socklen_t addressLength
)
172 struct sockaddr haikuAddr
;
174 if (check_r5_compatibility()) {
175 convert_from_r5_sockaddr(&haikuAddr
, address
);
176 address
= &haikuAddr
;
177 addressLength
= sizeof(struct sockaddr_in
);
180 RETURN_AND_SET_ERRNO_TEST_CANCEL(
181 _kern_connect(socket
, address
, addressLength
));
186 listen(int socket
, int backlog
)
188 RETURN_AND_SET_ERRNO(_kern_listen(socket
, backlog
));
193 accept(int socket
, struct sockaddr
*_address
, socklen_t
*_addressLength
)
195 bool r5compatible
= check_r5_compatibility();
196 struct sockaddr haikuAddr
;
199 socklen_t addressLength
;
201 if (r5compatible
&& _address
!= NULL
) {
202 address
= &haikuAddr
;
203 addressLength
= sizeof(haikuAddr
);
206 addressLength
= _addressLength
? *_addressLength
: 0;
209 int acceptSocket
= _kern_accept(socket
, address
, &addressLength
);
211 pthread_testcancel();
213 if (acceptSocket
< 0) {
214 errno
= acceptSocket
;
218 if (r5compatible
&& _address
!= NULL
) {
219 convert_to_r5_sockaddr(_address
, &haikuAddr
);
220 if (_addressLength
!= NULL
)
221 *_addressLength
= sizeof(struct r5_sockaddr_in
);
222 } else if (_addressLength
!= NULL
)
223 *_addressLength
= addressLength
;
230 recv(int socket
, void *data
, size_t length
, int flags
)
232 RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_recv(socket
, data
, length
, flags
));
237 recvfrom(int socket
, void *data
, size_t length
, int flags
,
238 struct sockaddr
*_address
, socklen_t
*_addressLength
)
240 bool r5compatible
= check_r5_compatibility();
241 struct sockaddr haikuAddr
;
244 socklen_t addressLength
;
246 if (r5compatible
&& _address
!= NULL
) {
247 address
= &haikuAddr
;
248 addressLength
= sizeof(haikuAddr
);
251 addressLength
= _addressLength
? *_addressLength
: 0;
254 ssize_t bytesReceived
= _kern_recvfrom(socket
, data
, length
, flags
,
255 address
, &addressLength
);
257 pthread_testcancel();
259 if (bytesReceived
< 0) {
260 errno
= bytesReceived
;
265 convert_to_r5_sockaddr(_address
, &haikuAddr
);
266 if (_addressLength
!= NULL
)
267 *_addressLength
= sizeof(struct r5_sockaddr_in
);
268 } else if (_addressLength
!= NULL
)
269 *_addressLength
= addressLength
;
271 return bytesReceived
;
276 recvmsg(int socket
, struct msghdr
*message
, int flags
)
278 RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_recvmsg(socket
, message
, flags
));
283 send(int socket
, const void *data
, size_t length
, int flags
)
285 RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_send(socket
, data
, length
, flags
));
290 sendto(int socket
, const void *data
, size_t length
, int flags
,
291 const struct sockaddr
*address
, socklen_t addressLength
)
293 struct sockaddr haikuAddr
;
295 if (check_r5_compatibility()) {
296 convert_from_r5_sockaddr(&haikuAddr
, address
);
297 address
= &haikuAddr
;
298 addressLength
= sizeof(struct sockaddr_in
);
301 RETURN_AND_SET_ERRNO_TEST_CANCEL(
302 _kern_sendto(socket
, data
, length
, flags
, address
, addressLength
));
307 sendmsg(int socket
, const struct msghdr
*message
, int flags
)
309 RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_sendmsg(socket
, message
, flags
));
314 getsockopt(int socket
, int level
, int option
, void *value
, socklen_t
*_length
)
316 if (check_r5_compatibility()) {
317 if (option
== R5_SO_FIONREAD
) {
318 // there is no SO_FIONREAD in our stack; we're using FIONREAD
320 *_length
= sizeof(int);
321 return ioctl(socket
, FIONREAD
, value
);
324 convert_from_r5_sockopt(level
, option
);
327 RETURN_AND_SET_ERRNO(_kern_getsockopt(socket
, level
, option
, value
,
333 setsockopt(int socket
, int level
, int option
, const void *value
,
336 if (check_r5_compatibility())
337 convert_from_r5_sockopt(level
, option
);
339 RETURN_AND_SET_ERRNO(_kern_setsockopt(socket
, level
, option
, value
,
345 getpeername(int socket
, struct sockaddr
*_address
, socklen_t
*_addressLength
)
347 bool r5compatible
= check_r5_compatibility();
348 struct sockaddr haikuAddr
;
351 socklen_t addressLength
;
353 if (r5compatible
&& _address
!= NULL
) {
354 address
= &haikuAddr
;
355 addressLength
= sizeof(haikuAddr
);
358 addressLength
= _addressLength
? *_addressLength
: 0;
361 status_t error
= _kern_getpeername(socket
, address
, &addressLength
);
368 convert_to_r5_sockaddr(_address
, &haikuAddr
);
369 if (_addressLength
!= NULL
)
370 *_addressLength
= sizeof(struct r5_sockaddr_in
);
371 } else if (_addressLength
!= NULL
)
372 *_addressLength
= addressLength
;
379 getsockname(int socket
, struct sockaddr
*_address
, socklen_t
*_addressLength
)
381 bool r5compatible
= check_r5_compatibility();
382 struct sockaddr haikuAddr
;
385 socklen_t addressLength
;
387 if (r5compatible
&& _address
!= NULL
) {
388 address
= &haikuAddr
;
389 addressLength
= sizeof(haikuAddr
);
392 addressLength
= _addressLength
? *_addressLength
: 0;
395 status_t error
= _kern_getsockname(socket
, address
, &addressLength
);
402 convert_to_r5_sockaddr(_address
, &haikuAddr
);
403 if (_addressLength
!= NULL
)
404 *_addressLength
= sizeof(struct r5_sockaddr_in
);
405 } else if (_addressLength
!= NULL
)
406 *_addressLength
= addressLength
;
413 sockatmark(int socket
)
415 RETURN_AND_SET_ERRNO(_kern_sockatmark(socket
));
420 socketpair(int family
, int type
, int protocol
, int socketVector
[2])
422 RETURN_AND_SET_ERRNO(_kern_socketpair(family
, type
, protocol
,