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