BPicture: Fix archive constructor.
[haiku.git] / src / kits / network / socket.cpp
blob7829f20507045be846cab28281c555f24699fd4f
1 /*
2 * Copyright 2002-2008, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 */
6 /*!
7 The socket API directly forwards all requests into the kernel stack
8 via the networking stack driver.
9 */
11 #include <r5_compatibility.h>
13 #include <errno.h>
14 #include <netinet/in.h>
15 #include <pthread.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <sys/ioctl.h>
19 #include <unistd.h>
21 #include <syscall_utils.h>
23 #include <syscalls.h>
26 static void
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);
35 if (from == NULL)
36 return;
38 if (from->sin_family == R5_AF_INET)
39 to->sin_family = AF_INET;
40 else
41 to->sin_family = from->sin_family;
43 to->sin_port = from->sin_port;
44 to->sin_addr.s_addr = from->sin_addr;
48 static void
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;
55 if (to == NULL)
56 return;
58 memset(to, 0, sizeof(r5_sockaddr_in));
60 if (from->sin_family == AF_INET)
61 to->sin_family = R5_AF_INET;
62 else
63 to->sin_family = from->sin_family;
65 to->sin_port = from->sin_port;
66 to->sin_addr = from->sin_addr.s_addr;
70 static void
71 convert_from_r5_socket(int& family, int& type, int& protocol)
73 switch (family) {
74 case R5_AF_INET:
75 family = AF_INET;
76 break;
79 switch (type) {
80 case R5_SOCK_DGRAM:
81 type = SOCK_DGRAM;
82 break;
83 case R5_SOCK_STREAM:
84 type = SOCK_STREAM;
85 break;
86 #if 0
87 case R5_SOCK_RAW:
88 type = SOCK_RAW;
89 break;
90 #endif
93 switch (protocol) {
94 case R5_IPPROTO_UDP:
95 protocol = IPPROTO_UDP;
96 break;
97 case R5_IPPROTO_TCP:
98 protocol = IPPROTO_TCP;
99 break;
100 case R5_IPPROTO_ICMP:
101 protocol = IPPROTO_ICMP;
102 break;
107 static void
108 convert_from_r5_sockopt(int& level, int& option)
110 if (level == R5_SOL_SOCKET)
111 level = SOL_SOCKET;
113 switch (option) {
114 case R5_SO_DEBUG:
115 option = SO_DEBUG;
116 break;
117 case R5_SO_REUSEADDR:
118 option = SO_REUSEADDR;
119 break;
120 case R5_SO_NONBLOCK:
121 option = SO_NONBLOCK;
122 break;
123 case R5_SO_REUSEPORT:
124 option = SO_REUSEPORT;
125 break;
126 case R5_SO_FIONREAD:
127 // there is no SO_FIONREAD
128 option = -1;
129 break;
134 // #pragma mark -
137 extern "C" int
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));
147 extern "C" int
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));
162 extern "C" int
163 shutdown(int socket, int how)
165 RETURN_AND_SET_ERRNO(_kern_shutdown_socket(socket, how));
169 extern "C" int
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));
185 extern "C" int
186 listen(int socket, int backlog)
188 RETURN_AND_SET_ERRNO(_kern_listen(socket, backlog));
192 extern "C" int
193 accept(int socket, struct sockaddr *_address, socklen_t *_addressLength)
195 bool r5compatible = check_r5_compatibility();
196 struct sockaddr haikuAddr;
198 sockaddr* address;
199 socklen_t addressLength;
201 if (r5compatible && _address != NULL) {
202 address = &haikuAddr;
203 addressLength = sizeof(haikuAddr);
204 } else {
205 address = _address;
206 addressLength = _addressLength ? *_addressLength : 0;
209 int acceptSocket = _kern_accept(socket, address, &addressLength);
211 pthread_testcancel();
213 if (acceptSocket < 0) {
214 errno = acceptSocket;
215 return -1;
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;
225 return acceptSocket;
229 extern "C" ssize_t
230 recv(int socket, void *data, size_t length, int flags)
232 RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_recv(socket, data, length, flags));
236 extern "C" ssize_t
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;
243 sockaddr* address;
244 socklen_t addressLength;
246 if (r5compatible && _address != NULL) {
247 address = &haikuAddr;
248 addressLength = sizeof(haikuAddr);
249 } else {
250 address = _address;
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;
261 return -1;
264 if (r5compatible) {
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;
275 extern "C" ssize_t
276 recvmsg(int socket, struct msghdr *message, int flags)
278 RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_recvmsg(socket, message, flags));
282 extern "C" ssize_t
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));
289 extern "C" ssize_t
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));
306 extern "C" ssize_t
307 sendmsg(int socket, const struct msghdr *message, int flags)
309 RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_sendmsg(socket, message, flags));
313 extern "C" int
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
319 // instead
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,
328 _length));
332 extern "C" int
333 setsockopt(int socket, int level, int option, const void *value,
334 socklen_t length)
336 if (check_r5_compatibility())
337 convert_from_r5_sockopt(level, option);
339 RETURN_AND_SET_ERRNO(_kern_setsockopt(socket, level, option, value,
340 length));
344 extern "C" int
345 getpeername(int socket, struct sockaddr *_address, socklen_t *_addressLength)
347 bool r5compatible = check_r5_compatibility();
348 struct sockaddr haikuAddr;
350 sockaddr* address;
351 socklen_t addressLength;
353 if (r5compatible && _address != NULL) {
354 address = &haikuAddr;
355 addressLength = sizeof(haikuAddr);
356 } else {
357 address = _address;
358 addressLength = _addressLength ? *_addressLength : 0;
361 status_t error = _kern_getpeername(socket, address, &addressLength);
362 if (error != B_OK) {
363 errno = error;
364 return -1;
367 if (r5compatible) {
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;
374 return 0;
378 extern "C" int
379 getsockname(int socket, struct sockaddr *_address, socklen_t *_addressLength)
381 bool r5compatible = check_r5_compatibility();
382 struct sockaddr haikuAddr;
384 sockaddr* address;
385 socklen_t addressLength;
387 if (r5compatible && _address != NULL) {
388 address = &haikuAddr;
389 addressLength = sizeof(haikuAddr);
390 } else {
391 address = _address;
392 addressLength = _addressLength ? *_addressLength : 0;
395 status_t error = _kern_getsockname(socket, address, &addressLength);
396 if (error != B_OK) {
397 errno = error;
398 return -1;
401 if (r5compatible) {
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;
408 return 0;
412 extern "C" int
413 sockatmark(int socket)
415 RETURN_AND_SET_ERRNO(_kern_sockatmark(socket));
419 extern "C" int
420 socketpair(int family, int type, int protocol, int socketVector[2])
422 RETURN_AND_SET_ERRNO(_kern_socketpair(family, type, protocol,
423 socketVector));