From 6ea1e9b996c7f2f8298d4388a4548680a5736255 Mon Sep 17 00:00:00 2001 From: Jeffrey Hsu Date: Sat, 27 Mar 2004 11:48:48 +0000 Subject: [PATCH] Give UDP its own sosend() function. --- sys/kern/uipc_socket.c | 96 +++++++++++++++++++++++++++++++++++++--- sys/netinet/udp_usrreq.c | 7 +-- sys/sys/socketvar.h | 5 ++- 3 files changed, 95 insertions(+), 13 deletions(-) diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index 2a4ead0f86..44cca05cd6 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2004 Jeffrey M. Hsu. All rights reserved. * Copyright (c) 1982, 1986, 1988, 1990, 1993 * The Regents of the University of California. All rights reserved. * @@ -32,7 +33,7 @@ * * @(#)uipc_socket.c 8.3 (Berkeley) 4/15/94 * $FreeBSD: src/sys/kern/uipc_socket.c,v 1.68.2.24 2003/11/11 17:18:18 silby Exp $ - * $DragonFly: src/sys/kern/uipc_socket.c,v 1.15 2004/03/05 16:57:15 hsu Exp $ + * $DragonFly: src/sys/kern/uipc_socket.c,v 1.16 2004/03/27 11:48:48 hsu Exp $ */ #include "opt_inet.h" @@ -473,7 +474,7 @@ sosend(struct socket *so, struct sockaddr *addr, struct uio *uio, td->td_proc->p_stats->p_ru.ru_msgsnd++; if (control) clen = control->m_len; -#define snderr(errno) { error = errno; splx(s); goto release; } +#define gotoerr(errno) { error = errno; splx(s); goto release; } restart: error = sblock(&so->so_snd, SBLOCKWAIT(flags)); @@ -482,7 +483,7 @@ restart: do { s = splnet(); if (so->so_state & SS_CANTSENDMORE) - snderr(EPIPE); + gotoerr(EPIPE); if (so->so_error) { error = so->so_error; so->so_error = 0; @@ -500,9 +501,9 @@ restart: (so->so_proto->pr_flags & PR_IMPLOPCL) == 0) { if ((so->so_state & SS_ISCONFIRMING) == 0 && !(resid == 0 && clen != 0)) - snderr(ENOTCONN); + gotoerr(ENOTCONN); } else if (addr == 0) - snderr(so->so_proto->pr_flags & PR_CONNREQUIRED ? + gotoerr(so->so_proto->pr_flags & PR_CONNREQUIRED ? ENOTCONN : EDESTADDRREQ); } space = sbspace(&so->so_snd); @@ -510,11 +511,11 @@ restart: space += 1024; if ((atomic && resid > so->so_snd.sb_hiwat) || clen > so->so_snd.sb_hiwat) - snderr(EMSGSIZE); + gotoerr(EMSGSIZE); if (space < resid + clen && uio && (atomic || space < so->so_snd.sb_lowat || space < clen)) { if (so->so_state & SS_NBIO) - snderr(EWOULDBLOCK); + gotoerr(EWOULDBLOCK); sbunlock(&so->so_snd); error = sbwait(&so->so_snd); splx(s); @@ -634,6 +635,87 @@ out: return (error); } +/* + * A specialization of sosend() for UDP based on protocol-specific knowledge: + * so->so_proto->pr_flags has the PR_ATOMIC field set. This means that + * sosendallatonce() returns true, + * the "atomic" variable is true, + * and sosendudp() blocks until space is available for the entire send. + * so->so_proto->pr_flags does not have the PR_CONNREQUIRED or + * PR_IMPLOPCL flags set. + * UDP has no out-of-band data. + * UDP has no control data. + * UDP does not support MSG_EOR. + */ +int +sosendudp(struct socket *so, struct sockaddr *addr, struct uio *uio, + struct mbuf *top, struct mbuf *control, int flags, struct thread *td) +{ + int resid, error, s; + boolean_t dontroute; /* temporary SO_DONTROUTE setting */ + + if (td->td_proc && td->td_proc->p_stats) + td->td_proc->p_stats->p_ru.ru_msgsnd++; + if (control) + m_freem(control); + + KASSERT((uio && !top) || (top && !uio), ("bad arguments to sosendudp")); + resid = uio ? uio->uio_resid : top->m_pkthdr.len; + +restart: + error = sblock(&so->so_snd, SBLOCKWAIT(flags)); + if (error) + goto out; + + s = splnet(); + if (so->so_state & SS_CANTSENDMORE) + gotoerr(EPIPE); + if (so->so_error) { + error = so->so_error; + so->so_error = 0; + splx(s); + goto release; + } + if (!(so->so_state & SS_ISCONNECTED) && addr == NULL) + gotoerr(EDESTADDRREQ); + if (resid > so->so_snd.sb_hiwat) + gotoerr(EMSGSIZE); + if (uio && sbspace(&so->so_snd) < resid) { + if (so->so_state & SS_NBIO) + gotoerr(EWOULDBLOCK); + sbunlock(&so->so_snd); + error = sbwait(&so->so_snd); + splx(s); + if (error) + goto out; + goto restart; + } + splx(s); + + if (uio) { + top = m_uiomove(uio, M_WAIT, 0); + if (top == NULL) + goto release; + } + + dontroute = (flags & MSG_DONTROUTE) && !(so->so_options & SO_DONTROUTE); + if (dontroute) + so->so_options |= SO_DONTROUTE; + + error = so_pru_send(so, 0, top, addr, NULL, td); + top = NULL; /* sent or freed in lower layer */ + + if (dontroute) + so->so_options &= ~SO_DONTROUTE; + +release: + sbunlock(&so->so_snd); +out: + if (top) + m_freem(top); + return (error); +} + /* * Implement receive operations on a socket. * We depend on the way that records are added to the sockbuf diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index f9de94ad9b..eec87a446d 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -33,7 +33,7 @@ * * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95 * $FreeBSD: src/sys/netinet/udp_usrreq.c,v 1.64.2.18 2003/01/24 05:11:34 sam Exp $ - * $DragonFly: src/sys/netinet/udp_usrreq.c,v 1.17 2004/03/22 06:38:17 hsu Exp $ + * $DragonFly: src/sys/netinet/udp_usrreq.c,v 1.18 2004/03/27 11:48:48 hsu Exp $ */ #include "opt_ipsec.h" @@ -721,9 +721,6 @@ udp_output(inp, m, dstaddr, control, td) struct sockaddr_in *sin; /* really is initialized before use */ int error = 0; - if (control) - m_freem(control); /* XXX */ - if (len + sizeof(struct udpiphdr) > IP_MAXPACKET) { error = EMSGSIZE; goto release; @@ -1009,6 +1006,6 @@ struct pr_usrreqs udp_usrreqs = { pru_connect2_notsupp, in_control, udp_detach, udp_disconnect, pru_listen_notsupp, in_setpeeraddr, pru_rcvd_notsupp, pru_rcvoob_notsupp, udp_send, pru_sense_null, udp_shutdown, - in_setsockaddr, sosend, soreceive, sopoll + in_setsockaddr, sosendudp, soreceive, sopoll }; diff --git a/sys/sys/socketvar.h b/sys/sys/socketvar.h index e554977100..184dc177aa 100644 --- a/sys/sys/socketvar.h +++ b/sys/sys/socketvar.h @@ -32,7 +32,7 @@ * * @(#)socketvar.h 8.3 (Berkeley) 2/19/95 * $FreeBSD: src/sys/sys/socketvar.h,v 1.46.2.10 2003/08/24 08:24:39 hsu Exp $ - * $DragonFly: src/sys/sys/socketvar.h,v 1.10 2004/03/08 23:52:51 dillon Exp $ + * $DragonFly: src/sys/sys/socketvar.h,v 1.11 2004/03/27 11:48:48 hsu Exp $ */ #ifndef _SYS_SOCKETVAR_H_ @@ -386,6 +386,9 @@ void sorflush (struct socket *so); int sosend (struct socket *so, struct sockaddr *addr, struct uio *uio, struct mbuf *top, struct mbuf *control, int flags, struct thread *td); +int sosendudp (struct socket *so, struct sockaddr *addr, struct uio *uio, + struct mbuf *top, struct mbuf *control, int flags, + struct thread *td); int sosetopt (struct socket *so, struct sockopt *sopt); int soshutdown (struct socket *so, int how); void sotoxsocket (struct socket *so, struct xsocket *xso); -- 2.41.0