| 321 | } |
| 322 | |
| 323 | int |
| 324 | kern_accept4(struct thread *td, int s, struct sockaddr **name, |
| 325 | socklen_t *namelen, int flags, struct file **fp) |
| 326 | { |
| 327 | struct file *headfp, *nfp = NULL; |
| 328 | struct sockaddr *sa = NULL; |
| 329 | struct socket *head, *so; |
| 330 | struct filecaps fcaps; |
| 331 | u_int fflag; |
| 332 | pid_t pgid; |
| 333 | int error, fd, tmp; |
| 334 | |
| 335 | if (name != NULL) |
| 336 | *name = NULL; |
| 337 | |
| 338 | AUDIT_ARG_FD(s); |
| 339 | error = getsock_cap(td, s, &cap_accept_rights, |
| 340 | &headfp, &fflag, &fcaps); |
| 341 | if (error != 0) |
| 342 | return (error); |
| 343 | head = headfp->f_data; |
| 344 | if ((head->so_options & SO_ACCEPTCONN) == 0) { |
| 345 | error = EINVAL; |
| 346 | goto done; |
| 347 | } |
| 348 | #ifdef MAC |
| 349 | error = mac_socket_check_accept(td->td_ucred, head); |
| 350 | if (error != 0) |
| 351 | goto done; |
| 352 | #endif |
| 353 | error = falloc_caps(td, &nfp, &fd, |
| 354 | (flags & SOCK_CLOEXEC) ? O_CLOEXEC : 0, &fcaps); |
| 355 | if (error != 0) |
| 356 | goto done; |
| 357 | SOCK_LOCK(head); |
| 358 | if (!SOLISTENING(head)) { |
| 359 | SOCK_UNLOCK(head); |
| 360 | error = EINVAL; |
| 361 | goto noconnection; |
| 362 | } |
| 363 | |
| 364 | error = solisten_dequeue(head, &so, flags); |
| 365 | if (error != 0) |
| 366 | goto noconnection; |
| 367 | |
| 368 | /* An extra reference on `nfp' has been held for us by falloc(). */ |
| 369 | td->td_retval[0] = fd; |
| 370 | |
| 371 | /* Connection has been removed from the listen queue. */ |
| 372 | KNOTE_UNLOCKED(&head->so_rdsel.si_note, 0); |
| 373 | |
| 374 | if (flags & ACCEPT4_INHERIT) { |
| 375 | pgid = fgetown(&head->so_sigio); |
| 376 | if (pgid != 0) |
| 377 | fsetown(pgid, &so->so_sigio); |
| 378 | } else { |
| 379 | fflag &= ~(FNONBLOCK | FASYNC); |
| 380 | if (flags & SOCK_NONBLOCK) |
no test coverage detected