1 /* 2 * Copyright 2002-2008, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 /*! 7 The socket API directly forwards all requests into the kernel stack 8 via the networking stack driver. 9 */ 10 11 #include <r5_compatibility.h> 12 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> 20 21 #include <syscall_utils.h> 22 23 #include <syscalls.h> 24 25 26 static void 27 convert_from_r5_sockaddr(struct sockaddr *_to, const struct sockaddr *_from) 28 { 29 const r5_sockaddr_in *from = (r5_sockaddr_in *)_from; 30 sockaddr_in *to = (sockaddr_in *)_to; 31 32 memset(to, 0, sizeof(sockaddr)); 33 to->sin_len = sizeof(sockaddr); 34 35 if (from == NULL) 36 return; 37 38 if (from->sin_family == R5_AF_INET) 39 to->sin_family = AF_INET; 40 else 41 to->sin_family = from->sin_family; 42 43 to->sin_port = from->sin_port; 44 to->sin_addr.s_addr = from->sin_addr; 45 } 46 47 48 static void 49 convert_to_r5_sockaddr(struct sockaddr *_to, 50 const struct sockaddr *_from) 51 { 52 const sockaddr_in *from = (sockaddr_in *)_from; 53 r5_sockaddr_in *to = (r5_sockaddr_in *)_to; 54 55 if (to == NULL) 56 return; 57 58 memset(to, 0, sizeof(r5_sockaddr_in)); 59 60 if (from->sin_family == AF_INET) 61 to->sin_family = R5_AF_INET; 62 else 63 to->sin_family = from->sin_family; 64 65 to->sin_port = from->sin_port; 66 to->sin_addr = from->sin_addr.s_addr; 67 } 68 69 70 static void 71 convert_from_r5_socket(int& family, int& type, int& protocol) 72 { 73 switch (family) { 74 case R5_AF_INET: 75 family = AF_INET; 76 break; 77 } 78 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 91 } 92 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; 103 } 104 } 105 106 107 static void 108 convert_from_r5_sockopt(int& level, int& option) 109 { 110 if (level == R5_SOL_SOCKET) 111 level = SOL_SOCKET; 112 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; 130 } 131 } 132 133 134 // #pragma mark - 135 136 137 extern "C" int 138 socket(int family, int type, int protocol) 139 { 140 if (check_r5_compatibility()) 141 convert_from_r5_socket(family, type, protocol); 142 143 RETURN_AND_SET_ERRNO(_kern_socket(family, type, protocol)); 144 } 145 146 147 extern "C" int 148 bind(int socket, const struct sockaddr *address, socklen_t addressLength) 149 { 150 struct sockaddr haikuAddr; 151 152 if (check_r5_compatibility()) { 153 convert_from_r5_sockaddr(&haikuAddr, address); 154 address = &haikuAddr; 155 addressLength = sizeof(struct sockaddr_in); 156 } 157 158 RETURN_AND_SET_ERRNO(_kern_bind(socket, address, addressLength)); 159 } 160 161 162 extern "C" int 163 shutdown(int socket, int how) 164 { 165 RETURN_AND_SET_ERRNO(_kern_shutdown_socket(socket, how)); 166 } 167 168 169 extern "C" int 170 connect(int socket, const struct sockaddr *address, socklen_t addressLength) 171 { 172 struct sockaddr haikuAddr; 173 174 if (check_r5_compatibility()) { 175 convert_from_r5_sockaddr(&haikuAddr, address); 176 address = &haikuAddr; 177 addressLength = sizeof(struct sockaddr_in); 178 } 179 180 RETURN_AND_SET_ERRNO_TEST_CANCEL( 181 _kern_connect(socket, address, addressLength)); 182 } 183 184 185 extern "C" int 186 listen(int socket, int backlog) 187 { 188 RETURN_AND_SET_ERRNO(_kern_listen(socket, backlog)); 189 } 190 191 192 extern "C" int 193 accept(int socket, struct sockaddr *_address, socklen_t *_addressLength) 194 { 195 bool r5compatible = check_r5_compatibility(); 196 struct sockaddr haikuAddr; 197 198 sockaddr* address; 199 socklen_t addressLength; 200 201 if (r5compatible && _address != NULL) { 202 address = &haikuAddr; 203 addressLength = sizeof(haikuAddr); 204 } else { 205 address = _address; 206 addressLength = _addressLength ? *_addressLength : 0; 207 } 208 209 int acceptSocket = _kern_accept(socket, address, &addressLength); 210 211 pthread_testcancel(); 212 213 if (acceptSocket < 0) { 214 errno = acceptSocket; 215 return -1; 216 } 217 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; 224 225 return acceptSocket; 226 } 227 228 229 extern "C" ssize_t 230 recv(int socket, void *data, size_t length, int flags) 231 { 232 RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_recv(socket, data, length, flags)); 233 } 234 235 236 extern "C" ssize_t 237 recvfrom(int socket, void *data, size_t length, int flags, 238 struct sockaddr *_address, socklen_t *_addressLength) 239 { 240 bool r5compatible = check_r5_compatibility(); 241 struct sockaddr haikuAddr; 242 243 sockaddr* address; 244 socklen_t addressLength; 245 246 if (r5compatible && _address != NULL) { 247 address = &haikuAddr; 248 addressLength = sizeof(haikuAddr); 249 } else { 250 address = _address; 251 addressLength = _addressLength ? *_addressLength : 0; 252 } 253 254 ssize_t bytesReceived = _kern_recvfrom(socket, data, length, flags, 255 address, &addressLength); 256 257 pthread_testcancel(); 258 259 if (bytesReceived < 0) { 260 errno = bytesReceived; 261 return -1; 262 } 263 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; 270 271 return bytesReceived; 272 } 273 274 275 extern "C" ssize_t 276 recvmsg(int socket, struct msghdr *message, int flags) 277 { 278 RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_recvmsg(socket, message, flags)); 279 } 280 281 282 extern "C" ssize_t 283 send(int socket, const void *data, size_t length, int flags) 284 { 285 RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_send(socket, data, length, flags)); 286 } 287 288 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) 292 { 293 struct sockaddr haikuAddr; 294 295 if (check_r5_compatibility()) { 296 convert_from_r5_sockaddr(&haikuAddr, address); 297 address = &haikuAddr; 298 addressLength = sizeof(struct sockaddr_in); 299 } 300 301 RETURN_AND_SET_ERRNO_TEST_CANCEL( 302 _kern_sendto(socket, data, length, flags, address, addressLength)); 303 } 304 305 306 extern "C" ssize_t 307 sendmsg(int socket, const struct msghdr *message, int flags) 308 { 309 RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_sendmsg(socket, message, flags)); 310 } 311 312 313 extern "C" int 314 getsockopt(int socket, int level, int option, void *value, socklen_t *_length) 315 { 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); 322 } 323 324 convert_from_r5_sockopt(level, option); 325 } 326 327 RETURN_AND_SET_ERRNO(_kern_getsockopt(socket, level, option, value, 328 _length)); 329 } 330 331 332 extern "C" int 333 setsockopt(int socket, int level, int option, const void *value, 334 socklen_t length) 335 { 336 if (check_r5_compatibility()) 337 convert_from_r5_sockopt(level, option); 338 339 RETURN_AND_SET_ERRNO(_kern_setsockopt(socket, level, option, value, 340 length)); 341 } 342 343 344 extern "C" int 345 getpeername(int socket, struct sockaddr *_address, socklen_t *_addressLength) 346 { 347 bool r5compatible = check_r5_compatibility(); 348 struct sockaddr haikuAddr; 349 350 sockaddr* address; 351 socklen_t addressLength; 352 353 if (r5compatible && _address != NULL) { 354 address = &haikuAddr; 355 addressLength = sizeof(haikuAddr); 356 } else { 357 address = _address; 358 addressLength = _addressLength ? *_addressLength : 0; 359 } 360 361 status_t error = _kern_getpeername(socket, address, &addressLength); 362 if (error != B_OK) { 363 errno = error; 364 return -1; 365 } 366 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; 373 374 return 0; 375 } 376 377 378 extern "C" int 379 getsockname(int socket, struct sockaddr *_address, socklen_t *_addressLength) 380 { 381 bool r5compatible = check_r5_compatibility(); 382 struct sockaddr haikuAddr; 383 384 sockaddr* address; 385 socklen_t addressLength; 386 387 if (r5compatible && _address != NULL) { 388 address = &haikuAddr; 389 addressLength = sizeof(haikuAddr); 390 } else { 391 address = _address; 392 addressLength = _addressLength ? *_addressLength : 0; 393 } 394 395 status_t error = _kern_getsockname(socket, address, &addressLength); 396 if (error != B_OK) { 397 errno = error; 398 return -1; 399 } 400 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; 407 408 return 0; 409 } 410 411 412 extern "C" int 413 sockatmark(int socket) 414 { 415 RETURN_AND_SET_ERRNO(_kern_sockatmark(socket)); 416 } 417 418 419 extern "C" int 420 socketpair(int family, int type, int protocol, int socketVector[2]) 421 { 422 RETURN_AND_SET_ERRNO(_kern_socketpair(family, type, protocol, 423 socketVector)); 424 } 425