1 /* 2 * Unix Domain Sockets Implementation (PF_UNIX, PF_LOCAL) 3 * This code handles requests generated by operations on /dev/uds 4 * 5 * The interface to UNIX domain sockets is similar to the interface to network 6 * sockets. There is a character device (/dev/uds) and this server is a 7 * 'driver' for that device. 8 */ 9 10 #include "uds.h" 11 12 static ssize_t uds_perform_write(devminor_t, endpoint_t, cp_grant_id_t, size_t, 13 int); 14 15 static int uds_open(devminor_t, int, endpoint_t); 16 static int uds_close(devminor_t); 17 static ssize_t uds_read(devminor_t, u64_t, endpoint_t, cp_grant_id_t, size_t, 18 int, cdev_id_t); 19 static ssize_t uds_write(devminor_t, u64_t, endpoint_t, cp_grant_id_t, size_t, 20 int, cdev_id_t); 21 static int uds_ioctl(devminor_t, unsigned long, endpoint_t, cp_grant_id_t, int, 22 endpoint_t, cdev_id_t); 23 static int uds_cancel(devminor_t, endpoint_t, cdev_id_t); 24 static int uds_select(devminor_t, unsigned int, endpoint_t); 25 26 static struct chardriver uds_tab = { 27 .cdr_open = uds_open, 28 .cdr_close = uds_close, 29 .cdr_read = uds_read, 30 .cdr_write = uds_write, 31 .cdr_ioctl = uds_ioctl, 32 .cdr_cancel = uds_cancel, 33 .cdr_select = uds_select 34 }; 35 36 /* File Descriptor Table */ 37 uds_fd_t uds_fd_table[NR_FDS]; 38 39 static unsigned int uds_exit_left; 40 41 static int 42 uds_open(devminor_t UNUSED(orig_minor), int access, 43 endpoint_t user_endpt) 44 { 45 devminor_t minor; 46 char *buf; 47 int i; 48 49 dprintf(("UDS: uds_open() from %d\n", user_endpt)); 50 51 /* 52 * Find a slot in the descriptor table for the new descriptor. 53 * The index of the descriptor in the table will be returned. 54 * Subsequent calls to read/write/close/ioctl/etc will use this 55 * minor number. The minor number must be different from the 56 * the /dev/uds device's minor number (0). 57 */ 58 for (minor = 1; minor < NR_FDS; minor++) 59 if (uds_fd_table[minor].state == UDS_FREE) 60 break; 61 62 if (minor == NR_FDS) 63 return ENFILE; 64 65 /* 66 * Allocate memory for the ringer buffer. In order to save on memory 67 * in the common case, the buffer is allocated only when the socket is 68 * in use. We use mmap instead of malloc to allow the memory to be 69 * actually freed later. 70 */ 71 if ((buf = mmap(NULL, UDS_BUF, PROT_READ | PROT_WRITE, 72 MAP_ANON | MAP_PRIVATE, -1, 0)) == MAP_FAILED) 73 return ENOMEM; 74 75 /* 76 * Allocate the socket, and set its initial parameters. 77 */ 78 uds_fd_table[minor].state = UDS_INUSE; 79 uds_fd_table[minor].owner = user_endpt; 80 uds_fd_table[minor].sel_endpt = NONE; 81 uds_fd_table[minor].sel_ops = 0; 82 uds_fd_table[minor].buf = buf; 83 uds_fd_table[minor].pos = 0; 84 uds_fd_table[minor].size = 0; 85 uds_fd_table[minor].mode = UDS_R | UDS_W; 86 uds_fd_table[minor].type = -1; 87 88 for (i = 0; i < UDS_SOMAXCONN; i++) 89 uds_fd_table[minor].backlog[i] = -1; 90 uds_fd_table[minor].backlog_size = UDS_SOMAXCONN; 91 92 memset(&uds_fd_table[minor].ancillary_data, '\0', 93 sizeof(struct ancillary)); 94 for (i = 0; i < OPEN_MAX; i++) 95 uds_fd_table[minor].ancillary_data.fds[i] = -1; 96 97 uds_fd_table[minor].listening = 0; 98 uds_fd_table[minor].peer = -1; 99 uds_fd_table[minor].child = -1; 100 101 memset(&uds_fd_table[minor].addr, '\0', sizeof(struct sockaddr_un)); 102 memset(&uds_fd_table[minor].source, '\0', sizeof(struct sockaddr_un)); 103 memset(&uds_fd_table[minor].target, '\0', sizeof(struct sockaddr_un)); 104 105 uds_fd_table[minor].suspended = UDS_NOT_SUSPENDED; 106 107 return CDEV_CLONED | minor; 108 } 109 110 static void 111 uds_reset(devminor_t minor) 112 { 113 /* Disconnect the socket from its peer. */ 114 uds_fd_table[minor].peer = -1; 115 116 /* Set an error to pass to the caller. */ 117 uds_fd_table[minor].err = ECONNRESET; 118 119 /* If a process was blocked on I/O, revive it. */ 120 if (uds_fd_table[minor].suspended != UDS_NOT_SUSPENDED) 121 uds_unsuspend(minor); 122 123 /* All of the peer's calls will fail immediately now. */ 124 if (uds_fd_table[minor].sel_ops != 0) { 125 chardriver_reply_select(uds_fd_table[minor].sel_endpt, minor, 126 uds_fd_table[minor].sel_ops); 127 uds_fd_table[minor].sel_ops = 0; 128 } 129 } 130 131 static int 132 uds_close(devminor_t minor) 133 { 134 int i, peer; 135 136 dprintf(("UDS: uds_close(%d)\n", minor)); 137 138 if (minor < 0 || minor >= NR_FDS) return ENXIO; 139 140 if (uds_fd_table[minor].state != UDS_INUSE) 141 return EINVAL; 142 143 peer = uds_fd_table[minor].peer; 144 if (peer != -1 && uds_fd_table[peer].peer == -1) { 145 /* Connecting socket: clear from server's backlog. */ 146 if (!uds_fd_table[peer].listening) 147 panic("connecting socket attached to non-server"); 148 149 for (i = 0; i < uds_fd_table[peer].backlog_size; i++) { 150 if (uds_fd_table[peer].backlog[i] == minor) { 151 uds_fd_table[peer].backlog[i] = -1; 152 break; 153 } 154 } 155 } else if (peer != -1) { 156 /* Connected socket: disconnect it. */ 157 uds_reset(peer); 158 } else if (uds_fd_table[minor].listening) { 159 /* Listening socket: disconnect all sockets in the backlog. */ 160 for (i = 0; i < uds_fd_table[minor].backlog_size; i++) 161 if (uds_fd_table[minor].backlog[i] != -1) 162 uds_reset(uds_fd_table[minor].backlog[i]); 163 } 164 165 if (uds_fd_table[minor].ancillary_data.nfiledes > 0) 166 uds_clear_fds(minor, &uds_fd_table[minor].ancillary_data); 167 168 /* Release the memory for the ring buffer. */ 169 munmap(uds_fd_table[minor].buf, UDS_BUF); 170 171 /* Set the socket back to its original UDS_FREE state. */ 172 memset(&uds_fd_table[minor], '\0', sizeof(uds_fd_t)); 173 174 /* If terminating, and this was the last open socket, exit now. */ 175 if (uds_exit_left > 0) { 176 if (--uds_exit_left == 0) 177 chardriver_terminate(); 178 } 179 180 return OK; 181 } 182 183 static int 184 uds_select(devminor_t minor, unsigned int ops, endpoint_t endpt) 185 { 186 unsigned int ready_ops; 187 int i, bytes, watch; 188 189 dprintf(("UDS: uds_select(%d)\n", minor)); 190 191 if (minor < 0 || minor >= NR_FDS) return ENXIO; 192 193 if (uds_fd_table[minor].state != UDS_INUSE) 194 return EINVAL; 195 196 watch = (ops & CDEV_NOTIFY); 197 ops &= (CDEV_OP_RD | CDEV_OP_WR | CDEV_OP_ERR); 198 199 ready_ops = 0; 200 201 /* Check if there is data available to read. */ 202 if (ops & CDEV_OP_RD) { 203 bytes = uds_perform_read(minor, NONE, GRANT_INVALID, 1, 1); 204 if (bytes > 0) { 205 ready_ops |= CDEV_OP_RD; /* data available */ 206 } else if (uds_fd_table[minor].listening == 1) { 207 /* Check for pending connections. */ 208 for (i = 0; i < uds_fd_table[minor].backlog_size; i++) 209 { 210 if (uds_fd_table[minor].backlog[i] != -1) { 211 ready_ops |= CDEV_OP_RD; 212 break; 213 } 214 } 215 } else if (bytes != EDONTREPLY) { 216 ready_ops |= CDEV_OP_RD; /* error */ 217 } 218 } 219 220 /* Check if we can write without blocking. */ 221 if (ops & CDEV_OP_WR) { 222 bytes = uds_perform_write(minor, NONE, GRANT_INVALID, 1, 1); 223 if (bytes != 0 && bytes != EDONTREPLY) 224 ready_ops |= CDEV_OP_WR; 225 } 226 227 /* 228 * If not all requested ops were ready, and the caller requests to be 229 * notified about changes, we add the remaining ops to the saved set. 230 */ 231 ops &= ~ready_ops; 232 if (ops && watch) { 233 uds_fd_table[minor].sel_endpt = endpt; 234 uds_fd_table[minor].sel_ops |= ops; 235 } 236 237 return ready_ops; 238 } 239 240 ssize_t 241 uds_perform_read(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant, 242 size_t size, int pretend) 243 { 244 size_t pos, subsize; 245 int r, peer; 246 247 dprintf(("UDS: uds_perform_read(%d)\n", minor)); 248 249 peer = uds_fd_table[minor].peer; 250 251 /* Skip reads of zero bytes. */ 252 if (size == 0) 253 return 0; 254 255 /* Check if the socket isn't shut down for reads. */ 256 if (!(uds_fd_table[minor].mode & UDS_R)) 257 return EPIPE; 258 259 if (uds_fd_table[minor].size == 0) { 260 if (peer == -1) { 261 /* 262 * We're not connected. That's only a problem when this 263 * socket is connection oriented. 264 */ 265 if (uds_fd_table[minor].type == SOCK_STREAM || 266 uds_fd_table[minor].type == SOCK_SEQPACKET) { 267 if (uds_fd_table[minor].err == ECONNRESET) { 268 if (!pretend) 269 uds_fd_table[minor].err = 0; 270 return ECONNRESET; 271 } else 272 return ENOTCONN; 273 } 274 } 275 276 /* Check if process is reading from a closed pipe. */ 277 if (peer != -1 && !(uds_fd_table[peer].mode & UDS_W) && 278 uds_fd_table[minor].size == 0) 279 return 0; 280 281 if (pretend) 282 return EDONTREPLY; 283 284 if (peer != -1 && 285 uds_fd_table[peer].suspended == UDS_SUSPENDED_WRITE) 286 panic("writer blocked on empty socket"); 287 288 dprintf(("UDS: suspending read request on %d\n", minor)); 289 290 /* Process is reading from an empty pipe. Suspend it. */ 291 return EDONTREPLY; 292 } 293 294 /* How much can we get from the ring buffer? */ 295 if (size > uds_fd_table[minor].size) 296 size = uds_fd_table[minor].size; 297 298 if (pretend) 299 return size; 300 301 /* Get the data from the tail of the ring buffer. */ 302 pos = uds_fd_table[minor].pos; 303 304 subsize = UDS_BUF - pos; 305 if (subsize > size) 306 subsize = size; 307 308 if ((r = sys_safecopyto(endpt, grant, 0, 309 (vir_bytes) &uds_fd_table[minor].buf[pos], subsize)) != OK) 310 return r; 311 312 if (subsize < size) { 313 if ((r = sys_safecopyto(endpt, grant, subsize, 314 (vir_bytes) uds_fd_table[minor].buf, 315 size - subsize)) != OK) 316 return r; 317 } 318 319 /* Advance the buffer tail. */ 320 uds_fd_table[minor].pos = (pos + size) % UDS_BUF; 321 uds_fd_table[minor].size -= size; 322 323 /* Reset position if the buffer is empty (it may save a copy call). */ 324 if (uds_fd_table[minor].size == 0) 325 uds_fd_table[minor].pos = 0; 326 327 /* See if we can wake up a blocked writer. */ 328 if (peer != -1 && uds_fd_table[peer].suspended == UDS_SUSPENDED_WRITE) 329 uds_unsuspend(peer); 330 331 /* See if we can satisfy an ongoing select. */ 332 if (peer != -1 && (uds_fd_table[peer].sel_ops & CDEV_OP_WR) && 333 uds_fd_table[minor].size < UDS_BUF) { 334 /* A write on the peer is possible now. */ 335 chardriver_reply_select(uds_fd_table[peer].sel_endpt, peer, 336 CDEV_OP_WR); 337 uds_fd_table[peer].sel_ops &= ~CDEV_OP_WR; 338 } 339 340 return size; /* number of bytes read */ 341 } 342 343 static ssize_t 344 uds_perform_write(devminor_t minor, endpoint_t endpt, cp_grant_id_t grant, 345 size_t size, int pretend) 346 { 347 size_t subsize, pos; 348 int i, r, peer; 349 350 dprintf(("UDS: uds_perform_write(%d)\n", minor)); 351 352 /* Skip writes of zero bytes. */ 353 if (size == 0) 354 return 0; 355 356 /* Check if the socket isn't shut down for writes. */ 357 if (!(uds_fd_table[minor].mode & UDS_W)) 358 return EPIPE; 359 360 /* Datagram messages must fit in the buffer entirely. */ 361 if (size > UDS_BUF && uds_fd_table[minor].type != SOCK_STREAM) 362 return EMSGSIZE; 363 364 if (uds_fd_table[minor].type == SOCK_STREAM || 365 uds_fd_table[minor].type == SOCK_SEQPACKET) { 366 /* 367 * If we're writing to a connection-oriented socket, then it 368 * needs a peer to write to. For disconnected sockets, writing 369 * is an error; for connecting sockets, writes should suspend. 370 */ 371 peer = uds_fd_table[minor].peer; 372 373 if (peer == -1) { 374 if (uds_fd_table[minor].err == ECONNRESET) { 375 if (!pretend) 376 uds_fd_table[minor].err = 0; 377 return ECONNRESET; 378 } else 379 return ENOTCONN; 380 } else if (uds_fd_table[peer].peer == -1) /* connecting */ 381 return EDONTREPLY; 382 } else /* uds_fd_table[minor].type == SOCK_DGRAM */ { 383 peer = -1; 384 385 /* Locate the "peer" we want to write to. */ 386 for (i = 0; i < NR_FDS; i++) { 387 /* 388 * Look for a SOCK_DGRAM socket that is bound on 389 * the target address. 390 */ 391 if (uds_fd_table[i].type == SOCK_DGRAM && 392 uds_fd_table[i].addr.sun_family == AF_UNIX && 393 !strncmp(uds_fd_table[minor].target.sun_path, 394 uds_fd_table[i].addr.sun_path, 395 sizeof(uds_fd_table[i].addr.sun_path))) { 396 peer = i; 397 break; 398 } 399 } 400 401 if (peer == -1) 402 return ENOENT; 403 } 404 405 /* Check if we write to a closed pipe. */ 406 if (!(uds_fd_table[peer].mode & UDS_R)) 407 return EPIPE; 408 409 /* 410 * We have to preserve the boundary for DGRAM. If there's already a 411 * packet waiting, discard it silently and pretend it was written. 412 */ 413 if (uds_fd_table[minor].type == SOCK_DGRAM && 414 uds_fd_table[peer].size > 0) 415 return size; 416 417 /* 418 * Check if the ring buffer is already full, and if the SEQPACKET 419 * message wouldn't write to an empty buffer. 420 */ 421 if (uds_fd_table[peer].size == UDS_BUF || 422 (uds_fd_table[minor].type == SOCK_SEQPACKET && 423 uds_fd_table[peer].size > 0)) { 424 if (pretend) 425 return EDONTREPLY; 426 427 if (uds_fd_table[peer].suspended == UDS_SUSPENDED_READ) 428 panic("reader blocked on full socket"); 429 430 dprintf(("UDS: suspending write request on %d\n", minor)); 431 432 /* Process is reading from an empty pipe. Suspend it. */ 433 return EDONTREPLY; 434 } 435 436 /* How much can we add to the ring buffer? */ 437 if (size > UDS_BUF - uds_fd_table[peer].size) 438 size = UDS_BUF - uds_fd_table[peer].size; 439 440 if (pretend) 441 return size; 442 443 /* Put the data at the head of the ring buffer. */ 444 pos = (uds_fd_table[peer].pos + uds_fd_table[peer].size) % UDS_BUF; 445 446 subsize = UDS_BUF - pos; 447 if (subsize > size) 448 subsize = size; 449 450 if ((r = sys_safecopyfrom(endpt, grant, 0, 451 (vir_bytes) &uds_fd_table[peer].buf[pos], subsize)) != OK) 452 return r; 453 454 if (subsize < size) { 455 if ((r = sys_safecopyfrom(endpt, grant, subsize, 456 (vir_bytes) uds_fd_table[peer].buf, size - subsize)) != OK) 457 return r; 458 } 459 460 /* Advance the buffer head. */ 461 uds_fd_table[peer].size += size; 462 463 /* Fill in the source address to be returned by recvfrom, recvmsg. */ 464 if (uds_fd_table[minor].type == SOCK_DGRAM) 465 memcpy(&uds_fd_table[peer].source, &uds_fd_table[minor].addr, 466 sizeof(struct sockaddr_un)); 467 468 /* See if we can wake up a blocked reader. */ 469 if (uds_fd_table[peer].suspended == UDS_SUSPENDED_READ) 470 uds_unsuspend(peer); 471 472 /* See if we can satisfy an ongoing select. */ 473 if ((uds_fd_table[peer].sel_ops & CDEV_OP_RD) && 474 uds_fd_table[peer].size > 0) { 475 /* A read on the peer is possible now. */ 476 chardriver_reply_select(uds_fd_table[peer].sel_endpt, peer, 477 CDEV_OP_RD); 478 uds_fd_table[peer].sel_ops &= ~CDEV_OP_RD; 479 } 480 481 return size; /* number of bytes written */ 482 } 483 484 static ssize_t 485 uds_read(devminor_t minor, u64_t position, endpoint_t endpt, 486 cp_grant_id_t grant, size_t size, int flags, cdev_id_t id) 487 { 488 ssize_t rc; 489 490 dprintf(("UDS: uds_read(%d)\n", minor)); 491 492 if (minor < 0 || minor >= NR_FDS) return ENXIO; 493 494 if (uds_fd_table[minor].state != UDS_INUSE) 495 return EINVAL; 496 497 rc = uds_perform_read(minor, endpt, grant, size, 0); 498 499 /* If the call couldn't complete, suspend the caller. */ 500 if (rc == EDONTREPLY) { 501 uds_fd_table[minor].suspended = UDS_SUSPENDED_READ; 502 uds_fd_table[minor].susp_endpt = endpt; 503 uds_fd_table[minor].susp_grant = grant; 504 uds_fd_table[minor].susp_size = size; 505 uds_fd_table[minor].susp_id = id; 506 507 /* If the call wasn't supposed to block, cancel immediately. */ 508 if (flags & CDEV_NONBLOCK) { 509 uds_cancel(minor, endpt, id); 510 511 rc = EAGAIN; 512 } 513 } 514 515 return rc; 516 } 517 518 static ssize_t 519 uds_write(devminor_t minor, u64_t position, endpoint_t endpt, 520 cp_grant_id_t grant, size_t size, int flags, cdev_id_t id) 521 { 522 ssize_t rc; 523 524 dprintf(("UDS: uds_write(%d)\n", minor)); 525 526 if (minor < 0 || minor >= NR_FDS) return ENXIO; 527 528 if (uds_fd_table[minor].state != UDS_INUSE) 529 return EINVAL; 530 531 rc = uds_perform_write(minor, endpt, grant, size, 0); 532 533 /* If the call couldn't complete, suspend the caller. */ 534 if (rc == EDONTREPLY) { 535 uds_fd_table[minor].suspended = UDS_SUSPENDED_WRITE; 536 uds_fd_table[minor].susp_endpt = endpt; 537 uds_fd_table[minor].susp_grant = grant; 538 uds_fd_table[minor].susp_size = size; 539 uds_fd_table[minor].susp_id = id; 540 541 /* If the call wasn't supposed to block, cancel immediately. */ 542 if (flags & CDEV_NONBLOCK) { 543 uds_cancel(minor, endpt, id); 544 545 rc = EAGAIN; 546 } 547 } 548 549 return rc; 550 } 551 552 static int 553 uds_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, 554 cp_grant_id_t grant, int flags, endpoint_t user_endpt, cdev_id_t id) 555 { 556 int rc, s; 557 558 dprintf(("UDS: uds_ioctl(%d, %lu)\n", minor, request)); 559 560 if (minor < 0 || minor >= NR_FDS) return ENXIO; 561 562 if (uds_fd_table[minor].state != UDS_INUSE) 563 return EINVAL; 564 565 /* Update the owner endpoint. */ 566 uds_fd_table[minor].owner = user_endpt; 567 568 /* Let the UDS ioctl subsystem handle the actual request. */ 569 rc = uds_do_ioctl(minor, request, endpt, grant); 570 571 /* If the call couldn't complete, suspend the caller. */ 572 if (rc == EDONTREPLY) { 573 /* The suspension type is already set by the IOCTL handler. */ 574 if ((s = uds_fd_table[minor].suspended) == UDS_NOT_SUSPENDED) 575 panic("IOCTL did not actually suspend?"); 576 uds_fd_table[minor].susp_endpt = endpt; 577 uds_fd_table[minor].susp_grant = grant; 578 uds_fd_table[minor].susp_size = 0; /* irrelevant */ 579 uds_fd_table[minor].susp_id = id; 580 581 /* If the call wasn't supposed to block, cancel immediately. */ 582 if (flags & CDEV_NONBLOCK) { 583 uds_cancel(minor, endpt, id); 584 if (s == UDS_SUSPENDED_CONNECT) 585 rc = EINPROGRESS; 586 else 587 rc = EAGAIN; 588 } 589 } 590 591 return rc; 592 } 593 594 void 595 uds_unsuspend(devminor_t minor) 596 { 597 int r; 598 uds_fd_t *fdp; 599 600 fdp = &uds_fd_table[minor]; 601 602 switch (fdp->suspended) { 603 case UDS_SUSPENDED_READ: 604 r = uds_perform_read(minor, fdp->susp_endpt, fdp->susp_grant, 605 fdp->susp_size, 0); 606 607 if (r == EDONTREPLY) 608 return; 609 610 break; 611 612 case UDS_SUSPENDED_WRITE: 613 r = uds_perform_write(minor, fdp->susp_endpt, fdp->susp_grant, 614 fdp->susp_size, 0); 615 616 if (r == EDONTREPLY) 617 return; 618 619 break; 620 621 case UDS_SUSPENDED_CONNECT: 622 case UDS_SUSPENDED_ACCEPT: 623 /* 624 * In both cases, the caller already set up the connection. 625 * The only thing to do here is unblock. 626 */ 627 r = fdp->err; 628 fdp->err = 0; 629 630 break; 631 632 default: 633 panic("unknown suspension type %d", fdp->suspended); 634 } 635 636 chardriver_reply_task(fdp->susp_endpt, fdp->susp_id, r); 637 638 fdp->suspended = UDS_NOT_SUSPENDED; 639 } 640 641 static int 642 uds_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id) 643 { 644 uds_fd_t *fdp; 645 int i; 646 647 dprintf(("UDS: uds_cancel(%d)\n", minor)); 648 649 if (minor < 0 || minor >= NR_FDS) return EDONTREPLY; 650 651 fdp = &uds_fd_table[minor]; 652 653 if (fdp->state != UDS_INUSE) { 654 printf("UDS: cancel request for closed minor %d\n", minor); 655 return EDONTREPLY; 656 } 657 658 /* Make sure the cancel request is for a request we're hanging on. */ 659 if (fdp->suspended == UDS_NOT_SUSPENDED || fdp->susp_endpt != endpt || 660 fdp->susp_id != id) 661 return EDONTREPLY; /* this happens. */ 662 663 /* 664 * The system call was cancelled, so the socket is not suspended 665 * anymore. 666 */ 667 switch (fdp->suspended) { 668 case UDS_SUSPENDED_ACCEPT: 669 /* A partial accept() only sets the server's child. */ 670 for (i = 0; i < NR_FDS; i++) 671 if (uds_fd_table[i].child == minor) 672 uds_fd_table[i].child = -1; 673 674 break; 675 676 case UDS_SUSPENDED_CONNECT: 677 /* Connect requests should continue asynchronously. */ 678 break; 679 680 case UDS_SUSPENDED_READ: 681 case UDS_SUSPENDED_WRITE: 682 /* Nothing more to do. */ 683 break; 684 685 default: 686 panic("unknown suspension type %d", fdp->suspended); 687 } 688 689 fdp->suspended = UDS_NOT_SUSPENDED; 690 691 return EINTR; /* reply to the original request */ 692 } 693 694 /* 695 * Initialize the server. 696 */ 697 static int 698 uds_init(int UNUSED(type), sef_init_info_t *UNUSED(info)) 699 { 700 /* Setting everything to NULL implicitly sets the state to UDS_FREE. */ 701 memset(uds_fd_table, '\0', sizeof(uds_fd_t) * NR_FDS); 702 703 uds_exit_left = 0; 704 705 /* Announce we are up! */ 706 chardriver_announce(); 707 708 return(OK); 709 } 710 711 static void 712 uds_signal(int signo) 713 { 714 int i; 715 716 /* Only check for termination signal, ignore anything else. */ 717 if (signo != SIGTERM) return; 718 719 /* Only exit once all sockets have been closed. */ 720 uds_exit_left = 0; 721 for (i = 0; i < NR_FDS; i++) 722 if (uds_fd_table[i].state == UDS_INUSE) 723 uds_exit_left++; 724 725 if (uds_exit_left == 0) 726 chardriver_terminate(); 727 } 728 729 static void 730 uds_startup(void) 731 { 732 /* Register init callbacks. */ 733 sef_setcb_init_fresh(uds_init); 734 735 /* Register signal callbacks. */ 736 sef_setcb_signal_handler(uds_signal); 737 738 /* Let SEF perform startup. */ 739 sef_startup(); 740 } 741 742 /* 743 * The UNIX domain sockets driver. 744 */ 745 int 746 main(void) 747 { 748 uds_startup(); 749 750 chardriver_task(&uds_tab); 751 752 return(OK); 753 } 754