/*
- * Copyright (c) 1982, 1986 Regents of the University of California.
- * All rights reserved. The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+ * All rights reserved.
*
- * @(#)uipc_socket.c 7.2 (Berkeley) %G%
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#)uipc_socket.c 7.14 (Berkeley) %G%
*/
#include "param.h"
-#include "systm.h"
-#include "dir.h"
#include "user.h"
#include "proc.h"
#include "file.h"
-#include "inode.h"
-#include "buf.h"
+#include "malloc.h"
#include "mbuf.h"
-#include "un.h"
#include "domain.h"
#include "protosw.h"
#include "socket.h"
#include "socketvar.h"
-#include "stat.h"
-#include "ioctl.h"
-#include "uio.h"
-#include "../net/route.h"
-#include "../netinet/in.h"
-#include "../net/if.h"
/*
* Socket operation routines.
{
register struct protosw *prp;
register struct socket *so;
- register struct mbuf *m;
register int error;
if (proto)
return (EPROTONOSUPPORT);
if (prp->pr_type != type)
return (EPROTOTYPE);
- m = m_getclr(M_WAIT, MT_SOCKET);
- so = mtod(m, struct socket *);
- so->so_options = 0;
- so->so_state = 0;
+ MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT);
+ bzero((caddr_t)so, sizeof(*so));
so->so_type = type;
if (u.u_uid == 0)
so->so_state = SS_PRIV;
}
if (backlog < 0)
backlog = 0;
- so->so_qlimit = MIN(backlog, SOMAXCONN);
+ so->so_qlimit = min(backlog, SOMAXCONN);
splx(s);
return (0);
}
register struct socket *so;
{
+ if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
+ return;
if (so->so_head) {
if (!soqremque(so, 0) && !soqremque(so, 1))
panic("sofree dq");
so->so_head = 0;
}
- if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
- return;
sbrelease(&so->so_snd);
sorflush(so);
- (void) m_free(dtom(so));
+ FREE(so, M_SOCKET);
}
/*
register struct socket *so;
{
int s = splnet(); /* conservative */
- int error;
+ int error = 0;
if (so->so_options & SO_ACCEPTCONN) {
while (so->so_q0 != so)
* inform user that this would block and do nothing.
* Otherwise, if nonblocking, send as much as possible.
*/
-sosend(so, nam, uio, flags, rights)
+sosend(so, nam, uio, flags, rights, control)
register struct socket *so;
struct mbuf *nam;
register struct uio *uio;
int flags;
- struct mbuf *rights;
+ struct mbuf *rights, *control;
{
- struct mbuf *top = 0;
- register struct mbuf *m, **mp;
- register int space;
- int len, rlen = 0, error = 0, s, dontroute, first = 1;
+ struct mbuf *top = 0, **mp;
+ register struct mbuf *m;
+ register int space, len;
+ int rlen = 0, error = 0, s, dontroute, first = 1, mlen;
+ int atomic = sosendallatonce(so);
- if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat)
+ if (atomic && uio->uio_resid > so->so_snd.sb_hiwat)
return (EMSGSIZE);
dontroute =
(flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
s = splnet();
if (so->so_state & SS_CANTSENDMORE)
snderr(EPIPE);
- if (so->so_error) {
- error = so->so_error;
- so->so_error = 0; /* ??? */
- splx(s);
- goto release;
- }
+ if (so->so_error)
+ snderr(so->so_error);
if ((so->so_state & SS_ISCONNECTED) == 0) {
- if (so->so_proto->pr_flags & PR_CONNREQUIRED)
- snderr(ENOTCONN);
- if (nam == 0)
+ if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
+ if (!uio->uio_resid && !rights && control) {
+ snderr((*so->so_proto->pr_usrreq)(so,
+ (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
+ top, (caddr_t)0, rights, control));
+ } else if (so->so_state & SS_ISCONFIRMING)
+ /* is ok */;
+ else
+ snderr(ENOTCONN);
+ } else if (nam == 0)
snderr(EDESTADDRREQ);
}
if (flags & MSG_OOB)
else {
space = sbspace(&so->so_snd);
if (space <= rlen ||
- (sosendallatonce(so) &&
- space < uio->uio_resid + rlen) ||
- (uio->uio_resid >= CLBYTES && space < CLBYTES &&
- so->so_snd.sb_cc >= CLBYTES &&
+ (atomic && space < uio->uio_resid + rlen) ||
+ (uio->uio_resid >= MCLBYTES && space < MCLBYTES &&
+ so->so_snd.sb_cc >= MCLBYTES &&
(so->so_state & SS_NBIO) == 0)) {
if (so->so_state & SS_NBIO) {
if (first)
splx(s);
mp = ⊤
space -= rlen;
- while (space > 0) {
- MGET(m, M_WAIT, MT_DATA);
- if (uio->uio_resid >= CLBYTES / 2 && space >= CLBYTES) {
- MCLGET(m);
- if (m->m_len != CLBYTES)
+ do {
+ do {
+ if (top == 0) {
+ MGETHDR(m, M_WAIT, MT_DATA);
+ mlen = MHLEN;
+ m->m_pkthdr.len = 0;
+ m->m_pkthdr.rcvif = (struct ifnet *)0;
+ } else {
+ MGET(m, M_WAIT, MT_DATA);
+ mlen = MLEN;
+ }
+ if (uio->uio_resid >= MINCLSIZE && space >= MCLBYTES) {
+ MCLGET(m, M_WAIT);
+ if ((m->m_flags & M_EXT) == 0)
goto nopages;
- len = MIN(CLBYTES, uio->uio_resid);
- space -= CLBYTES;
+ mlen = MCLBYTES;
+#ifdef MAPPED_MBUFS
+ len = min(MCLBYTES, uio->uio_resid);
+ if (len < mlen - max_hdr)
+ m->m_data += max_hdr;
+#else
+ len = min(MCLBYTES - max_hdr, uio->uio_resid);
+ m->m_data += max_hdr;
+#endif
+ space -= MCLBYTES;
} else {
nopages:
- len = MIN(MIN(MLEN, uio->uio_resid), space);
+ len = min(min(mlen, uio->uio_resid), space);
space -= len;
+ /*
+ * For datagram protocols, leave room
+ * for protocol headers in first mbuf.
+ */
+ if (atomic && top == 0 && len < mlen)
+ MH_ALIGN(m, len);
}
- error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
+ error = uiomove(mtod(m, caddr_t), len, uio);
m->m_len = len;
*mp = m;
+ top->m_pkthdr.len += len;
if (error)
goto release;
mp = &m->m_next;
- if (uio->uio_resid <= 0)
+ if (uio->uio_resid <= 0) {
+ if ((flags & MSG_EOR) && top)
+ top->m_flags |= M_EOR;
break;
- }
- if (dontroute)
- so->so_options |= SO_DONTROUTE;
- s = splnet(); /* XXX */
- error = (*so->so_proto->pr_usrreq)(so,
- (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
- top, (caddr_t)nam, rights);
- splx(s);
- if (dontroute)
- so->so_options &= ~SO_DONTROUTE;
- rights = 0;
- rlen = 0;
- top = 0;
- first = 0;
- if (error)
- break;
+ }
+ } while (space > 0 && atomic);
+ if (dontroute)
+ so->so_options |= SO_DONTROUTE;
+ s = splnet(); /* XXX */
+ error = (*so->so_proto->pr_usrreq)(so,
+ (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
+ top, (caddr_t)nam, rights, control);
+ splx(s);
+ if (dontroute)
+ so->so_options &= ~SO_DONTROUTE;
+ rights = 0;
+ rlen = 0;
+ top = 0;
+ mp = ⊤
+ first = 0;
+ if (error)
+ goto release;
+ } while (uio->uio_resid && space > 0);
} while (uio->uio_resid);
release:
* Although the sockbuf is locked, new data may still be appended,
* and thus we must maintain consistency of the sockbuf during that time.
*/
-soreceive(so, aname, uio, flags, rightsp)
+soreceive(so, aname, uio, flagsp, rightsp, controlp)
register struct socket *so;
struct mbuf **aname;
register struct uio *uio;
- int flags;
- struct mbuf **rightsp;
+ int *flagsp;
+ struct mbuf **rightsp, **controlp;
{
register struct mbuf *m;
- register int len, error = 0, s, tomark;
+ register int flags, len, error = 0, s, offset;
struct protosw *pr = so->so_proto;
struct mbuf *nextrecord;
int moff;
*rightsp = 0;
if (aname)
*aname = 0;
+ if (controlp)
+ *controlp = 0;
+ if (flagsp)
+ flags = *flagsp &~ MSG_EOR;
+ else
+ flags = 0;
if (flags & MSG_OOB) {
m = m_get(M_WAIT, MT_DATA);
error = (*pr->pr_usrreq)(so, PRU_RCVOOB,
len = uio->uio_resid;
if (len > m->m_len)
len = m->m_len;
- error =
- uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
+ error = uiomove(mtod(m, caddr_t), (int)len, uio);
m = m_free(m);
} while (uio->uio_resid && error == 0 && m);
bad:
m_freem(m);
return (error);
}
+ if (so->so_state & SS_ISCONFIRMING && uio->uio_resid)
+ (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
+ (struct mbuf *)0, (struct mbuf *)0);
restart:
sblock(&so->so_rcv);
s = splnet();
-#define rcverr(errno) { error = errno; splx(s); goto release; }
- if (so->so_rcv.sb_cc == 0) {
+ m = so->so_rcv.sb_mb;
+ if (m == 0) {
+ if (so->so_rcv.sb_cc)
+ panic("receive 1");
if (so->so_error) {
error = so->so_error;
so->so_error = 0;
- splx(s);
goto release;
}
- if (so->so_state & SS_CANTRCVMORE) {
- splx(s);
+ if (so->so_state & SS_CANTRCVMORE)
goto release;
- }
if ((so->so_state & SS_ISCONNECTED) == 0 &&
- (so->so_proto->pr_flags & PR_CONNREQUIRED))
- rcverr(ENOTCONN);
+ (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
+ error = ENOTCONN;
+ goto release;
+ }
if (uio->uio_resid == 0)
goto release;
- if (so->so_state & SS_NBIO)
- rcverr(EWOULDBLOCK);
+ if (so->so_state & SS_NBIO) {
+ error = EWOULDBLOCK;
+ goto release;
+ }
sbunlock(&so->so_rcv);
sbwait(&so->so_rcv);
splx(s);
goto restart;
}
u.u_ru.ru_msgrcv++;
- m = so->so_rcv.sb_mb;
- if (m == 0)
- panic("receive 1");
- nextrecord = m->m_act;
+if (m->m_type == 0)
+panic("receive 3a");
+ nextrecord = m->m_nextpkt;
if (pr->pr_flags & PR_ADDR) {
if (m->m_type != MT_SONAME)
panic("receive 1a");
sbfree(&so->so_rcv, m);
if (aname) {
*aname = m;
- m = m->m_next;
- (*aname)->m_next = 0;
- so->so_rcv.sb_mb = m;
+ so->so_rcv.sb_mb = m->m_next;
+ m->m_next = 0;
+ m = so->so_rcv.sb_mb;
} else {
MFREE(m, so->so_rcv.sb_mb);
m = so->so_rcv.sb_mb;
}
- if (m)
- m->m_act = nextrecord;
}
}
if (m && m->m_type == MT_RIGHTS) {
MFREE(m, so->so_rcv.sb_mb);
m = so->so_rcv.sb_mb;
}
- if (m)
- m->m_act = nextrecord;
}
}
+ if (m && m->m_type == MT_CONTROL) {
+ if (flags & MSG_PEEK) {
+ if (controlp)
+ *controlp = m_copy(m, 0, m->m_len);
+ m = m->m_next;
+ } else {
+ sbfree(&so->so_rcv, m);
+ if (controlp) {
+ *controlp = m;
+ so->so_rcv.sb_mb = m->m_next;
+ m->m_next = 0;
+ m = so->so_rcv.sb_mb;
+ } else {
+ MFREE(m, so->so_rcv.sb_mb);
+ m = so->so_rcv.sb_mb;
+ }
+ }
+ }
+ if (m)
+ m->m_nextpkt = nextrecord;
moff = 0;
- tomark = so->so_oobmark;
+ offset = 0;
while (m && uio->uio_resid > 0 && error == 0) {
- if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
+ if (m->m_type == MT_OOBDATA)
+ flags |= MSG_OOB;
+ else if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
panic("receive 3");
+ if (m->m_flags & M_EOR)
+ flags |= MSG_EOR;
len = uio->uio_resid;
so->so_state &= ~SS_RCVATMARK;
- if (tomark && len > tomark)
- len = tomark;
+ if (so->so_oobmark && len > so->so_oobmark - offset)
+ len = so->so_oobmark - offset;
if (len > m->m_len - moff)
len = m->m_len - moff;
splx(s);
- error =
- uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio);
+ error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio);
s = splnet();
if (len == m->m_len - moff) {
if (flags & MSG_PEEK) {
m = m->m_next;
moff = 0;
} else {
- nextrecord = m->m_act;
+ nextrecord = m->m_nextpkt;
sbfree(&so->so_rcv, m);
MFREE(m, so->so_rcv.sb_mb);
m = so->so_rcv.sb_mb;
if (m)
- m->m_act = nextrecord;
+ m->m_nextpkt = nextrecord;
}
} else {
if (flags & MSG_PEEK)
moff += len;
else {
- m->m_off += len;
+ m->m_data += len;
m->m_len -= len;
so->so_rcv.sb_cc -= len;
}
}
- if ((flags & MSG_PEEK) == 0 && so->so_oobmark) {
- so->so_oobmark -= len;
- if (so->so_oobmark == 0) {
- so->so_state |= SS_RCVATMARK;
- break;
- }
- }
- if (tomark) {
- tomark -= len;
- if (tomark == 0)
- break;
+ if (so->so_oobmark) {
+ if ((flags & MSG_PEEK) == 0) {
+ so->so_oobmark -= len;
+ if (so->so_oobmark == 0) {
+ so->so_state |= SS_RCVATMARK;
+ break;
+ }
+ } else
+ offset += len;
}
}
+ if (m && (flags & MSG_EOR)) {
+ flags &= ~MSG_EOR;
+ if ((flags & MSG_PEEK) == 0)
+ m->m_flags |= M_EOR;
+ }
if ((flags & MSG_PEEK) == 0) {
if (m == 0)
so->so_rcv.sb_mb = nextrecord;
- else if (pr->pr_flags & PR_ATOMIC)
+ else if (pr->pr_flags & PR_ATOMIC) {
+ flags |= MSG_TRUNC;
(void) sbdroprecord(&so->so_rcv);
+ }
if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
(*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
- (struct mbuf *)0, (struct mbuf *)0);
+ (struct mbuf *)flags, (struct mbuf *)0,
+ (struct mbuf *)0);
if (error == 0 && rightsp && *rightsp &&
pr->pr_domain->dom_externalize)
error = (*pr->pr_domain->dom_externalize)(*rightsp);
}
+ if (flagsp)
+ *flagsp |= flags;
release:
sbunlock(&so->so_rcv);
splx(s);
case SO_SNDBUF:
case SO_RCVBUF:
- if (sbreserve(optname == SO_SNDBUF ? &so->so_snd :
- &so->so_rcv, *mtod(m, int *)) == 0) {
+ if (sbreserve(optname == SO_SNDBUF ?
+ &so->so_snd : &so->so_rcv,
+ (u_long) *mtod(m, int *)) == 0) {
error = ENOBUFS;
goto bad;
}
{
struct proc *p;
- if (so->so_pgrp < 0)
- gsignal(-so->so_pgrp, SIGURG);
- else if (so->so_pgrp > 0 && (p = pfind(so->so_pgrp)) != 0)
+ if (so->so_pgid < 0)
+ gsignal(-so->so_pgid, SIGURG);
+ else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0)
psignal(p, SIGURG);
if (so->so_rcv.sb_sel) {
selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL);