int ofp_accept(int sockfd, struct ofp_sockaddr *addr, ofp_socklen_t *addrlen) { struct ofp_sockaddr *sa = NULL; struct socket *so, *head = ofp_get_sock_by_fd(sockfd); if (!head) { ofp_errno = OFP_EBADF; return -1; } if ((head->so_options & OFP_SO_ACCEPTCONN) == 0) { ofp_errno = OFP_EINVAL; return -1; } ACCEPT_LOCK(); if ((head->so_state & SS_NBIO) && OFP_TAILQ_EMPTY(&head->so_comp)) { ACCEPT_UNLOCK(); ofp_errno = OFP_EWOULDBLOCK; return -1; } while (OFP_TAILQ_EMPTY(&head->so_comp) && head->so_error == 0) { if (head->so_rcv.sb_state & SBS_CANTRCVMORE) { head->so_error = OFP_ECONNABORTED; break; } if (ofp_msleep(&head->so_timeo, ofp_accept_mtx(), 0, "accept", 0)) { ACCEPT_UNLOCK(); return -1; } } if (head->so_error) { ofp_errno = head->so_error; head->so_error = 0; ACCEPT_UNLOCK(); return -1; } so = OFP_TAILQ_FIRST(&head->so_comp); KASSERT(!(so->so_qstate & SQ_INCOMP), ("accept1: so SQ_INCOMP")); KASSERT(so->so_qstate & SQ_COMP, ("accept1: so not SQ_COMP")); /* * Before changing the flags on the socket, we have to bump the * reference count. Otherwise, if the protocol calls ofp_sofree(), * the socket will be released due to a zero refcount. */ OFP_SOCK_LOCK(so); /* soref() and so_state update */ soref(so); /* file descriptor reference */ OFP_TAILQ_REMOVE(&head->so_comp, so, so_list); head->so_qlen--; so->so_state |= (head->so_state & SS_NBIO); so->so_qstate &= ~SQ_COMP; so->so_head = NULL; OFP_SOCK_UNLOCK(so); ACCEPT_UNLOCK(); /* connection has been removed from the listen queue */ /*KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0);*/ sa = 0; ofp_errno = ofp_soaccept(so, &sa); if (ofp_errno) { /* * return a namelen of zero for older code which might * ignore the return value from accept. */ if (addr) *addrlen = 0; return -1; } if (sa == NULL) { if (addr) *addrlen = 0; return so->so_number; } if (addr) { /* check sa_len before it is destroyed */ if (*addrlen > sa->sa_len) *addrlen = sa->sa_len; memcpy(addr, sa, *addrlen); } free(sa); return so->so_number; }
static inline int is_accepting_socket_readable(struct socket *so) { return !(OFP_TAILQ_EMPTY(&so->so_comp)); }