/* * Destroy a disconnected socket. This routine is a NOP if entities * still have a reference on the socket: * * so_pcb - The protocol stack still has a reference * SS_NOFDREF - There is no longer a file pointer reference */ void sofree(struct socket *so) { struct socket *head; /* * This is a bit hackish at the moment. We need to interlock * any accept queue we are on before we potentially lose the * last reference to avoid races against a re-reference from * someone operating on the queue. */ while ((head = so->so_head) != NULL) { lwkt_getpooltoken(head); if (so->so_head == head) break; lwkt_relpooltoken(head); } /* * Arbitrage the last free. */ KKASSERT(so->so_refs > 0); if (atomic_fetchadd_int(&so->so_refs, -1) != 1) { if (head) lwkt_relpooltoken(head); return; } KKASSERT(so->so_pcb == NULL && (so->so_state & SS_NOFDREF)); KKASSERT((so->so_state & SS_ASSERTINPROG) == 0); /* * We're done, remove ourselves from the accept queue we are * on, if we are on one. */ if (head != NULL) { if (so->so_state & SS_INCOMP) { TAILQ_REMOVE(&head->so_incomp, so, so_list); head->so_incqlen--; } else if (so->so_state & SS_COMP) { /* * We must not decommission a socket that's * on the accept(2) queue. If we do, then * accept(2) may hang after select(2) indicated * that the listening socket was ready. */ lwkt_relpooltoken(head); return; } else { panic("sofree: not queued"); } soclrstate(so, SS_INCOMP); so->so_head = NULL; lwkt_relpooltoken(head); } ssb_release(&so->so_snd, so); sorflush(so); sodealloc(so); }
/* FUNCTION: soshutdown() * * PARAM1: struct socket * socket structure * PARAM2: int shutdown action * 0 = shutdown read half of connection * 1 = shutdown write half of connection * 2 = shutdown both halves of connection * * RETURNS: int 0 if successful, else error code */ int soshutdown(struct socket *so, int how) { how++; /* convert 0,1,2 into 1,2,3 */ if (how & 1) /* caller wanted READ or BOTH */ sorflush(so); if (how & 2) /* caller wanted WRITE or BOTH */ { sbflush(&so->so_snd); /* flush the socket send queue */ so->so_req = PRU_SHUTDOWN; return ((*so->so_proto->pr_usrreq)(so, (struct mbuf *)0, (struct mbuf *)0)); } return 0; }
void sofree(struct socket * so) { INET_TRACE (INETM_SOCKET|INETM_CLOSE, ("INET: sofree, so %lx so_pcb %lx so_state %x so_head %lx\n", so, so->so_pcb, so->so_state, so->so_head)); if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) return; if (so->so_head) { if (!soqremque(so, 0) && !soqremque(so, 1)) panic("sofree"); so->so_head = 0; } sbrelease(&so->so_snd); sorflush(so); #ifdef SAVE_SOCK_ENDPOINTS if (so->so_endpoint) _socket_free_entry (so); #endif /* SAVE_SOCK_ENDPOINTS */ #ifdef IP_MULTICAST /* multicast opts? */ if (so->inp_moptions) ip_freemoptions(so->inp_moptions); #endif /* IP_MULTICAST */ /* IP_TOS opts? */ if (so->so_optsPack) SOCOPT_FREE(so->so_optsPack); qdel(&soq, so); /* Delete the socket entry from the queue */ if (so_evtmap) (*so_evtmap_delete) (so); SOC_FREE(so); }