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 return accept4(socket, _address, _addressLength, 0); 196 } 197 198 199 extern "C" int 200 accept4(int socket, struct sockaddr *_address, socklen_t *_addressLength, int flags) 201 { 202 bool r5compatible = check_r5_compatibility(); 203 struct sockaddr haikuAddr; 204 205 sockaddr* address; 206 socklen_t addressLength; 207 208 if (r5compatible && _address != NULL) { 209 address = &haikuAddr; 210 addressLength = sizeof(haikuAddr); 211 } else { 212 address = _address; 213 addressLength = _addressLength ? *_addressLength : 0; 214 } 215 216 int acceptSocket = _kern_accept(socket, address, &addressLength, flags); 217 218 pthread_testcancel(); 219 220 if (acceptSocket < 0) { 221 errno = acceptSocket; 222 return -1; 223 } 224 225 if (r5compatible && _address != NULL) { 226 convert_to_r5_sockaddr(_address, &haikuAddr); 227 if (_addressLength != NULL) 228 *_addressLength = sizeof(struct r5_sockaddr_in); 229 } else if (_addressLength != NULL) 230 *_addressLength = addressLength; 231 232 return acceptSocket; 233 } 234 235 236 extern "C" ssize_t 237 recv(int socket, void *data, size_t length, int flags) 238 { 239 RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_recv(socket, data, length, flags)); 240 } 241 242 243 extern "C" ssize_t 244 recvfrom(int socket, void *data, size_t length, int flags, 245 struct sockaddr *_address, socklen_t *_addressLength) 246 { 247 bool r5compatible = check_r5_compatibility(); 248 struct sockaddr haikuAddr; 249 250 sockaddr* address; 251 socklen_t addressLength; 252 253 if (r5compatible && _address != NULL) { 254 address = &haikuAddr; 255 addressLength = sizeof(haikuAddr); 256 } else { 257 address = _address; 258 addressLength = _addressLength ? *_addressLength : 0; 259 } 260 261 ssize_t bytesReceived = _kern_recvfrom(socket, data, length, flags, 262 address, &addressLength); 263 264 pthread_testcancel(); 265 266 if (bytesReceived < 0) { 267 errno = bytesReceived; 268 return -1; 269 } 270 271 if (r5compatible) { 272 convert_to_r5_sockaddr(_address, &haikuAddr); 273 if (_addressLength != NULL) 274 *_addressLength = sizeof(struct r5_sockaddr_in); 275 } else if (_addressLength != NULL) 276 *_addressLength = addressLength; 277 278 return bytesReceived; 279 } 280 281 282 extern "C" ssize_t 283 recvmsg(int socket, struct msghdr *message, int flags) 284 { 285 RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_recvmsg(socket, message, flags)); 286 } 287 288 289 extern "C" ssize_t 290 send(int socket, const void *data, size_t length, int flags) 291 { 292 RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_send(socket, data, length, flags)); 293 } 294 295 296 extern "C" ssize_t 297 sendto(int socket, const void *data, size_t length, int flags, 298 const struct sockaddr *address, socklen_t addressLength) 299 { 300 struct sockaddr haikuAddr; 301 302 if (check_r5_compatibility()) { 303 convert_from_r5_sockaddr(&haikuAddr, address); 304 address = &haikuAddr; 305 addressLength = sizeof(struct sockaddr_in); 306 } 307 308 RETURN_AND_SET_ERRNO_TEST_CANCEL( 309 _kern_sendto(socket, data, length, flags, address, addressLength)); 310 } 311 312 313 extern "C" ssize_t 314 sendmsg(int socket, const struct msghdr *message, int flags) 315 { 316 RETURN_AND_SET_ERRNO_TEST_CANCEL(_kern_sendmsg(socket, message, flags)); 317 } 318 319 320 extern "C" int 321 getsockopt(int socket, int level, int option, void *value, socklen_t *_length) 322 { 323 if (check_r5_compatibility()) { 324 if (option == R5_SO_FIONREAD) { 325 // there is no SO_FIONREAD in our stack; we're using FIONREAD 326 // instead 327 *_length = sizeof(int); 328 return ioctl(socket, FIONREAD, value); 329 } 330 331 convert_from_r5_sockopt(level, option); 332 } 333 334 RETURN_AND_SET_ERRNO(_kern_getsockopt(socket, level, option, value, 335 _length)); 336 } 337 338 339 extern "C" int 340 setsockopt(int socket, int level, int option, const void *value, 341 socklen_t length) 342 { 343 if (check_r5_compatibility()) 344 convert_from_r5_sockopt(level, option); 345 346 RETURN_AND_SET_ERRNO(_kern_setsockopt(socket, level, option, value, 347 length)); 348 } 349 350 351 extern "C" int 352 getpeername(int socket, struct sockaddr *_address, socklen_t *_addressLength) 353 { 354 bool r5compatible = check_r5_compatibility(); 355 struct sockaddr haikuAddr; 356 357 sockaddr* address; 358 socklen_t addressLength; 359 360 if (r5compatible && _address != NULL) { 361 address = &haikuAddr; 362 addressLength = sizeof(haikuAddr); 363 } else { 364 address = _address; 365 addressLength = _addressLength ? *_addressLength : 0; 366 } 367 368 status_t error = _kern_getpeername(socket, address, &addressLength); 369 if (error != B_OK) { 370 errno = error; 371 return -1; 372 } 373 374 if (r5compatible) { 375 convert_to_r5_sockaddr(_address, &haikuAddr); 376 if (_addressLength != NULL) 377 *_addressLength = sizeof(struct r5_sockaddr_in); 378 } else if (_addressLength != NULL) 379 *_addressLength = addressLength; 380 381 return 0; 382 } 383 384 385 extern "C" int 386 getsockname(int socket, struct sockaddr *_address, socklen_t *_addressLength) 387 { 388 bool r5compatible = check_r5_compatibility(); 389 struct sockaddr haikuAddr; 390 391 sockaddr* address; 392 socklen_t addressLength; 393 394 if (r5compatible && _address != NULL) { 395 address = &haikuAddr; 396 addressLength = sizeof(haikuAddr); 397 } else { 398 address = _address; 399 addressLength = _addressLength ? *_addressLength : 0; 400 } 401 402 status_t error = _kern_getsockname(socket, address, &addressLength); 403 if (error != B_OK) { 404 errno = error; 405 return -1; 406 } 407 408 if (r5compatible) { 409 convert_to_r5_sockaddr(_address, &haikuAddr); 410 if (_addressLength != NULL) 411 *_addressLength = sizeof(struct r5_sockaddr_in); 412 } else if (_addressLength != NULL) 413 *_addressLength = addressLength; 414 415 return 0; 416 } 417 418 419 extern "C" int 420 sockatmark(int socket) 421 { 422 RETURN_AND_SET_ERRNO(_kern_sockatmark(socket)); 423 } 424 425 426 extern "C" int 427 socketpair(int family, int type, int protocol, int socketVector[2]) 428 { 429 RETURN_AND_SET_ERRNO(_kern_socketpair(family, type, protocol, 430 socketVector)); 431 } 432