| 564 | } |
| 565 | |
| 566 | int |
| 567 | kern_socketpair(struct thread *td, int domain, int type, int protocol, |
| 568 | int *rsv) |
| 569 | { |
| 570 | struct file *fp1, *fp2; |
| 571 | struct socket *so1, *so2; |
| 572 | int fd, error, oflag, fflag; |
| 573 | |
| 574 | AUDIT_ARG_SOCKET(domain, type, protocol); |
| 575 | |
| 576 | oflag = 0; |
| 577 | fflag = 0; |
| 578 | if ((type & SOCK_CLOEXEC) != 0) { |
| 579 | type &= ~SOCK_CLOEXEC; |
| 580 | oflag |= O_CLOEXEC; |
| 581 | } |
| 582 | if ((type & SOCK_NONBLOCK) != 0) { |
| 583 | type &= ~SOCK_NONBLOCK; |
| 584 | fflag |= FNONBLOCK; |
| 585 | } |
| 586 | #ifdef MAC |
| 587 | /* We might want to have a separate check for socket pairs. */ |
| 588 | error = mac_socket_check_create(td->td_ucred, domain, type, |
| 589 | protocol); |
| 590 | if (error != 0) |
| 591 | return (error); |
| 592 | #endif |
| 593 | error = socreate(domain, &so1, type, protocol, td->td_ucred, td); |
| 594 | if (error != 0) |
| 595 | return (error); |
| 596 | error = socreate(domain, &so2, type, protocol, td->td_ucred, td); |
| 597 | if (error != 0) |
| 598 | goto free1; |
| 599 | /* On success extra reference to `fp1' and 'fp2' is set by falloc. */ |
| 600 | error = falloc(td, &fp1, &fd, oflag); |
| 601 | if (error != 0) |
| 602 | goto free2; |
| 603 | rsv[0] = fd; |
| 604 | fp1->f_data = so1; /* so1 already has ref count */ |
| 605 | error = falloc(td, &fp2, &fd, oflag); |
| 606 | if (error != 0) |
| 607 | goto free3; |
| 608 | fp2->f_data = so2; /* so2 already has ref count */ |
| 609 | rsv[1] = fd; |
| 610 | error = soconnect2(so1, so2); |
| 611 | if (error != 0) |
| 612 | goto free4; |
| 613 | if (type == SOCK_DGRAM) { |
| 614 | /* |
| 615 | * Datagram socket connection is asymmetric. |
| 616 | */ |
| 617 | error = soconnect2(so2, so1); |
| 618 | if (error != 0) |
| 619 | goto free4; |
| 620 | } else if (so1->so_proto->pr_flags & PR_CONNREQUIRED) { |
| 621 | struct unpcb *unp, *unp2; |
| 622 | unp = sotounpcb(so1); |
| 623 | unp2 = sotounpcb(so2); |
no test coverage detected