| 3964 | } |
| 3965 | |
| 3966 | void |
| 3967 | soisconnected(struct socket *so) |
| 3968 | { |
| 3969 | |
| 3970 | SOCK_LOCK(so); |
| 3971 | so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING); |
| 3972 | so->so_state |= SS_ISCONNECTED; |
| 3973 | |
| 3974 | if (so->so_qstate == SQ_INCOMP) { |
| 3975 | struct socket *head = so->so_listen; |
| 3976 | int ret; |
| 3977 | |
| 3978 | KASSERT(head, ("%s: so %p on incomp of NULL", __func__, so)); |
| 3979 | /* |
| 3980 | * Promoting a socket from incomplete queue to complete, we |
| 3981 | * need to go through reverse order of locking. We first do |
| 3982 | * trylock, and if that doesn't succeed, we go the hard way |
| 3983 | * leaving a reference and rechecking consistency after proper |
| 3984 | * locking. |
| 3985 | */ |
| 3986 | if (__predict_false(SOLISTEN_TRYLOCK(head) == 0)) { |
| 3987 | soref(head); |
| 3988 | SOCK_UNLOCK(so); |
| 3989 | SOLISTEN_LOCK(head); |
| 3990 | SOCK_LOCK(so); |
| 3991 | if (__predict_false(head != so->so_listen)) { |
| 3992 | /* |
| 3993 | * The socket went off the listen queue, |
| 3994 | * should be lost race to close(2) of sol. |
| 3995 | * The socket is about to soabort(). |
| 3996 | */ |
| 3997 | SOCK_UNLOCK(so); |
| 3998 | sorele(head); |
| 3999 | return; |
| 4000 | } |
| 4001 | /* Not the last one, as so holds a ref. */ |
| 4002 | refcount_release(&head->so_count); |
| 4003 | } |
| 4004 | again: |
| 4005 | if ((so->so_options & SO_ACCEPTFILTER) == 0) { |
| 4006 | TAILQ_REMOVE(&head->sol_incomp, so, so_list); |
| 4007 | head->sol_incqlen--; |
| 4008 | TAILQ_INSERT_TAIL(&head->sol_comp, so, so_list); |
| 4009 | head->sol_qlen++; |
| 4010 | so->so_qstate = SQ_COMP; |
| 4011 | SOCK_UNLOCK(so); |
| 4012 | solisten_wakeup(head); /* unlocks */ |
| 4013 | } else { |
| 4014 | SOCKBUF_LOCK(&so->so_rcv); |
| 4015 | soupcall_set(so, SO_RCV, |
| 4016 | head->sol_accept_filter->accf_callback, |
| 4017 | head->sol_accept_filter_arg); |
| 4018 | so->so_options &= ~SO_ACCEPTFILTER; |
| 4019 | ret = head->sol_accept_filter->accf_callback(so, |
| 4020 | head->sol_accept_filter_arg, M_NOWAIT); |
| 4021 | if (ret == SU_ISCONNECTED) { |
| 4022 | soupcall_clear(so, SO_RCV); |
| 4023 | SOCKBUF_UNLOCK(&so->so_rcv); |
no test coverage detected