1 /* 2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <stdio.h> 8 #include <sys/un.h> 9 10 #include <new> 11 12 #include <AutoDeleter.h> 13 14 #include <fs/fd.h> 15 #include <lock.h> 16 #include <util/AutoLock.h> 17 #include <vfs.h> 18 19 #include <net_buffer.h> 20 #include <net_protocol.h> 21 #include <net_socket.h> 22 #include <net_stack.h> 23 24 #include "UnixAddressManager.h" 25 #include "UnixEndpoint.h" 26 27 28 #define UNIX_MODULE_DEBUG_LEVEL 0 29 #define UNIX_DEBUG_LEVEL UNIX_MODULE_DEBUG_LEVEL 30 #include "UnixDebug.h" 31 32 33 extern net_protocol_module_info gUnixModule; 34 // extern only for forwarding 35 36 net_stack_module_info *gStackModule; 37 net_socket_module_info *gSocketModule; 38 net_buffer_module_info *gBufferModule; 39 UnixAddressManager gAddressManager; 40 41 static struct net_domain *sDomain; 42 43 44 void 45 destroy_scm_rights_descriptors(const ancillary_data_header* header, 46 void* data) 47 { 48 int count = header->len / sizeof(file_descriptor*); 49 file_descriptor** descriptors = (file_descriptor**)data; 50 51 for (int i = 0; i < count; i++) { 52 if (descriptors[i] != NULL) { 53 close_fd(descriptors[i]); 54 put_fd(descriptors[i]); 55 } 56 } 57 } 58 59 60 // #pragma mark - 61 62 63 net_protocol * 64 unix_init_protocol(net_socket *socket) 65 { 66 TRACE("[%ld] unix_init_protocol(%p)\n", find_thread(NULL), socket); 67 68 UnixEndpoint* endpoint = new(std::nothrow) UnixEndpoint(socket); 69 if (endpoint == NULL) 70 return NULL; 71 72 status_t error = endpoint->Init(); 73 if (error != B_OK) { 74 delete endpoint; 75 return NULL; 76 } 77 78 return endpoint; 79 } 80 81 82 status_t 83 unix_uninit_protocol(net_protocol *_protocol) 84 { 85 TRACE("[%ld] unix_uninit_protocol(%p)\n", find_thread(NULL), _protocol); 86 ((UnixEndpoint*)_protocol)->Uninit(); 87 return B_OK; 88 } 89 90 91 status_t 92 unix_open(net_protocol *_protocol) 93 { 94 return ((UnixEndpoint*)_protocol)->Open(); 95 } 96 97 98 status_t 99 unix_close(net_protocol *_protocol) 100 { 101 return ((UnixEndpoint*)_protocol)->Close(); 102 } 103 104 105 status_t 106 unix_free(net_protocol *_protocol) 107 { 108 return ((UnixEndpoint*)_protocol)->Free(); 109 } 110 111 112 status_t 113 unix_connect(net_protocol *_protocol, const struct sockaddr *address) 114 { 115 return ((UnixEndpoint*)_protocol)->Connect(address); 116 } 117 118 119 status_t 120 unix_accept(net_protocol *_protocol, struct net_socket **_acceptedSocket) 121 { 122 return ((UnixEndpoint*)_protocol)->Accept(_acceptedSocket); 123 } 124 125 126 status_t 127 unix_control(net_protocol *protocol, int level, int option, void *value, 128 size_t *_length) 129 { 130 return B_BAD_VALUE; 131 } 132 133 134 status_t 135 unix_getsockopt(net_protocol *protocol, int level, int option, void *value, 136 int *_length) 137 { 138 UnixEndpoint* endpoint = (UnixEndpoint*)protocol; 139 140 if (level == SOL_SOCKET && option == SO_PEERCRED) { 141 if (*_length < (int)sizeof(ucred)) 142 return B_BAD_VALUE; 143 144 *_length = sizeof(ucred); 145 146 return endpoint->GetPeerCredentials((ucred*)value); 147 } 148 149 return gSocketModule->get_option(protocol->socket, level, option, value, 150 _length); 151 } 152 153 154 status_t 155 unix_setsockopt(net_protocol *protocol, int level, int option, 156 const void *_value, int length) 157 { 158 UnixEndpoint* endpoint = (UnixEndpoint*)protocol; 159 160 if (level == SOL_SOCKET) { 161 if (option == SO_RCVBUF) { 162 if (length != sizeof(int)) 163 return B_BAD_VALUE; 164 165 status_t error = endpoint->SetReceiveBufferSize(*(int*)_value); 166 if (error != B_OK) 167 return error; 168 } else if (option == SO_SNDBUF) { 169 // We don't have a receive buffer, so silently ignore this one. 170 } 171 } 172 173 return gSocketModule->set_option(protocol->socket, level, option, 174 _value, length); 175 } 176 177 178 status_t 179 unix_bind(net_protocol *_protocol, const struct sockaddr *_address) 180 { 181 return ((UnixEndpoint*)_protocol)->Bind(_address); 182 } 183 184 185 status_t 186 unix_unbind(net_protocol *_protocol, struct sockaddr *_address) 187 { 188 return ((UnixEndpoint*)_protocol)->Unbind(); 189 } 190 191 192 status_t 193 unix_listen(net_protocol *_protocol, int count) 194 { 195 return ((UnixEndpoint*)_protocol)->Listen(count); 196 } 197 198 199 status_t 200 unix_shutdown(net_protocol *_protocol, int direction) 201 { 202 return ((UnixEndpoint*)_protocol)->Shutdown(direction); 203 } 204 205 206 status_t 207 unix_send_routed_data(net_protocol *_protocol, struct net_route *route, 208 net_buffer *buffer) 209 { 210 return B_ERROR; 211 } 212 213 214 status_t 215 unix_send_data(net_protocol *_protocol, net_buffer *buffer) 216 { 217 return B_ERROR; 218 } 219 220 221 ssize_t 222 unix_send_avail(net_protocol *_protocol) 223 { 224 return ((UnixEndpoint*)_protocol)->Sendable(); 225 } 226 227 228 status_t 229 unix_read_data(net_protocol *_protocol, size_t numBytes, uint32 flags, 230 net_buffer **_buffer) 231 { 232 return B_ERROR; 233 } 234 235 236 ssize_t 237 unix_read_avail(net_protocol *_protocol) 238 { 239 return ((UnixEndpoint*)_protocol)->Receivable(); 240 } 241 242 243 struct net_domain * 244 unix_get_domain(net_protocol *protocol) 245 { 246 return sDomain; 247 } 248 249 250 size_t 251 unix_get_mtu(net_protocol *protocol, const struct sockaddr *address) 252 { 253 return UNIX_MAX_TRANSFER_UNIT; 254 } 255 256 257 status_t 258 unix_receive_data(net_buffer *buffer) 259 { 260 return B_ERROR; 261 } 262 263 264 status_t 265 unix_deliver_data(net_protocol *_protocol, net_buffer *buffer) 266 { 267 return B_ERROR; 268 } 269 270 271 status_t 272 unix_error_received(net_error error, net_buffer *data) 273 { 274 return B_ERROR; 275 } 276 277 278 status_t 279 unix_error_reply(net_protocol *protocol, net_buffer *cause, net_error error, 280 net_error_data *errorData) 281 { 282 return B_ERROR; 283 } 284 285 286 status_t 287 unix_add_ancillary_data(net_protocol *self, ancillary_data_container *container, 288 const cmsghdr *header) 289 { 290 TRACE("[%ld] unix_add_ancillary_data(%p, %p, %p (level: %d, type: %d, " 291 "len: %d))\n", find_thread(NULL), self, container, header, 292 header->cmsg_level, header->cmsg_type, (int)header->cmsg_len); 293 294 // we support only SCM_RIGHTS 295 if (header->cmsg_level != SOL_SOCKET || header->cmsg_type != SCM_RIGHTS) 296 return B_BAD_VALUE; 297 298 int* fds = (int*)CMSG_DATA(header); 299 int count = (header->cmsg_len - CMSG_ALIGN(sizeof(cmsghdr))) / sizeof(int); 300 if (count == 0) 301 return B_BAD_VALUE; 302 303 file_descriptor** descriptors = new(std::nothrow) file_descriptor*[count]; 304 if (descriptors == NULL) 305 return ENOBUFS; 306 ArrayDeleter<file_descriptor*> _(descriptors); 307 memset(descriptors, 0, sizeof(file_descriptor*) * count); 308 309 // get the file descriptors 310 io_context* ioContext = get_current_io_context(!gStackModule->is_syscall()); 311 312 status_t error = B_OK; 313 for (int i = 0; i < count; i++) { 314 descriptors[i] = get_open_fd(ioContext, fds[i]); 315 if (descriptors[i] == NULL) { 316 error = EBADF; 317 break; 318 } 319 } 320 321 // attach the ancillary data to the container 322 if (error == B_OK) { 323 ancillary_data_header header; 324 header.level = SOL_SOCKET; 325 header.type = SCM_RIGHTS; 326 header.len = count * sizeof(file_descriptor*); 327 328 TRACE("[%ld] unix_add_ancillary_data(): adding %d FDs to " 329 "container\n", find_thread(NULL), count); 330 331 error = gStackModule->add_ancillary_data(container, &header, 332 descriptors, destroy_scm_rights_descriptors, NULL); 333 } 334 335 // cleanup on error 336 if (error != B_OK) { 337 for (int i = 0; i < count; i++) { 338 if (descriptors[i] != NULL) { 339 close_fd(descriptors[i]); 340 put_fd(descriptors[i]); 341 } 342 } 343 } 344 345 return error; 346 } 347 348 349 ssize_t 350 unix_process_ancillary_data(net_protocol *self, 351 const ancillary_data_header *header, const void *data, void *buffer, 352 size_t bufferSize) 353 { 354 TRACE("[%ld] unix_process_ancillary_data(%p, %p (level: %d, type: %d, " 355 "len: %lu), %p, %p, %lu)\n", find_thread(NULL), self, header, 356 header->level, header->type, header->len, data, buffer, bufferSize); 357 358 // we support only SCM_RIGHTS 359 if (header->level != SOL_SOCKET || header->type != SCM_RIGHTS) 360 return B_BAD_VALUE; 361 362 int count = header->len / sizeof(file_descriptor*); 363 file_descriptor** descriptors = (file_descriptor**)data; 364 365 // check if there's enough space in the buffer 366 size_t neededBufferSpace = CMSG_SPACE(sizeof(int) * count); 367 if (bufferSize < neededBufferSpace) 368 return B_BAD_VALUE; 369 370 // init header 371 cmsghdr* messageHeader = (cmsghdr*)buffer; 372 messageHeader->cmsg_level = header->level; 373 messageHeader->cmsg_type = header->type; 374 messageHeader->cmsg_len = CMSG_LEN(sizeof(int) * count); 375 376 // create FDs for the current process 377 int* fds = (int*)CMSG_DATA(messageHeader); 378 io_context* ioContext = get_current_io_context(!gStackModule->is_syscall()); 379 380 status_t error = B_OK; 381 for (int i = 0; i < count; i++) { 382 // Get an additional reference which will go to the FD table index. The 383 // reference and open reference acquired in unix_add_ancillary_data() 384 // will be released when the container is destroyed. 385 inc_fd_ref_count(descriptors[i]); 386 fds[i] = new_fd(ioContext, descriptors[i]); 387 388 if (fds[i] < 0) { 389 error = fds[i]; 390 put_fd(descriptors[i]); 391 392 // close FD indices 393 for (int k = i - 1; k >= 0; k--) 394 close_fd_index(ioContext, fds[k]); 395 break; 396 } 397 } 398 399 return error == B_OK ? neededBufferSpace : error; 400 } 401 402 403 ssize_t 404 unix_send_data_no_buffer(net_protocol *_protocol, const iovec *vecs, 405 size_t vecCount, ancillary_data_container *ancillaryData, 406 const struct sockaddr *address, socklen_t addressLength) 407 { 408 return ((UnixEndpoint*)_protocol)->Send(vecs, vecCount, ancillaryData); 409 } 410 411 412 ssize_t 413 unix_read_data_no_buffer(net_protocol *_protocol, const iovec *vecs, 414 size_t vecCount, ancillary_data_container **_ancillaryData, 415 struct sockaddr *_address, socklen_t *_addressLength) 416 { 417 return ((UnixEndpoint*)_protocol)->Receive(vecs, vecCount, _ancillaryData, 418 _address, _addressLength); 419 } 420 421 422 // #pragma mark - 423 424 425 status_t 426 init_unix() 427 { 428 new(&gAddressManager) UnixAddressManager; 429 status_t error = gAddressManager.Init(); 430 if (error != B_OK) 431 return error; 432 433 error = gStackModule->register_domain_protocols(AF_UNIX, SOCK_STREAM, 0, 434 "network/protocols/unix/v1", NULL); 435 if (error != B_OK) { 436 gAddressManager.~UnixAddressManager(); 437 return error; 438 } 439 440 error = gStackModule->register_domain(AF_UNIX, "unix", &gUnixModule, 441 &gAddressModule, &sDomain); 442 if (error != B_OK) { 443 gAddressManager.~UnixAddressManager(); 444 return error; 445 } 446 447 return B_OK; 448 } 449 450 451 status_t 452 uninit_unix() 453 { 454 gStackModule->unregister_domain(sDomain); 455 456 gAddressManager.~UnixAddressManager(); 457 458 return B_OK; 459 } 460 461 462 static status_t 463 unix_std_ops(int32 op, ...) 464 { 465 switch (op) { 466 case B_MODULE_INIT: 467 return init_unix(); 468 case B_MODULE_UNINIT: 469 return uninit_unix(); 470 471 default: 472 return B_ERROR; 473 } 474 } 475 476 477 net_protocol_module_info gUnixModule = { 478 { 479 "network/protocols/unix/v1", 480 0, 481 unix_std_ops 482 }, 483 0, // NET_PROTOCOL_ATOMIC_MESSAGES, 484 485 unix_init_protocol, 486 unix_uninit_protocol, 487 unix_open, 488 unix_close, 489 unix_free, 490 unix_connect, 491 unix_accept, 492 unix_control, 493 unix_getsockopt, 494 unix_setsockopt, 495 unix_bind, 496 unix_unbind, 497 unix_listen, 498 unix_shutdown, 499 unix_send_data, 500 unix_send_routed_data, 501 unix_send_avail, 502 unix_read_data, 503 unix_read_avail, 504 unix_get_domain, 505 unix_get_mtu, 506 unix_receive_data, 507 unix_deliver_data, 508 unix_error_received, 509 unix_error_reply, 510 unix_add_ancillary_data, 511 unix_process_ancillary_data, 512 NULL, 513 unix_send_data_no_buffer, 514 unix_read_data_no_buffer 515 }; 516 517 module_dependency module_dependencies[] = { 518 {NET_STACK_MODULE_NAME, (module_info **)&gStackModule}, 519 {NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule}, 520 // {NET_DATALINK_MODULE_NAME, (module_info **)&sDatalinkModule}, 521 {NET_SOCKET_MODULE_NAME, (module_info **)&gSocketModule}, 522 {} 523 }; 524 525 module_info *modules[] = { 526 (module_info *)&gUnixModule, 527 NULL 528 }; 529