int soconnect(struct socket *so, struct sockaddr *nam, struct thread *td) { int error; if (so->so_options & SO_ACCEPTCONN) return (EOPNOTSUPP); /* * If protocol is connection-based, can only connect once. * Otherwise, if connected, try to disconnect first. * This allows user to disconnect by connecting to, e.g., * a null address. */ if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && ((so->so_proto->pr_flags & PR_CONNREQUIRED) || (error = sodisconnect(so)))) { error = EISCONN; } else { /* * Prevent accumulated error from previous connection * from biting us. */ so->so_error = 0; error = so_pru_connect(so, nam, td); } return (error); }
int so_pru_connect_async(struct socket *so, struct sockaddr *nam, struct thread *td) { struct netmsg_pru_connect *msg; int error, flags; KASSERT(so->so_proto->pr_usrreqs->pru_preconnect != NULL, ("async pru_connect is not supported")); /* NOTE: sockaddr immediately follows netmsg */ msg = kmalloc(sizeof(*msg) + nam->sa_len, M_LWKTMSG, M_WAITOK | M_NULLOK); if (msg == NULL) { /* * Fail to allocate message; fallback to * synchronized pru_connect. */ return so_pru_connect(so, nam, td); } error = so->so_proto->pr_usrreqs->pru_preconnect(so, nam, td); if (error) { kfree(msg, M_LWKTMSG); return error; } flags = PRUC_ASYNC; if (td != NULL && (so->so_proto->pr_flags & PR_ACONN_HOLDTD)) { lwkt_hold(td); flags |= PRUC_HELDTD; } netmsg_init(&msg->base, so, &netisr_afree_rport, 0, so->so_proto->pr_usrreqs->pru_connect); msg->nm_nam = (struct sockaddr *)(msg + 1); memcpy(msg->nm_nam, nam, nam->sa_len); msg->nm_td = td; msg->nm_m = NULL; msg->nm_sndflags = 0; msg->nm_flags = flags; lwkt_sendmsg(so->so_port, &msg->base.lmsg); return 0; }