marc's changes: malloc uio if too large, ktrace
[unix-history] / usr / src / sys / kern / uipc_socket2.c
index 850a3ca..21cca21 100644 (file)
@@ -1,4 +1,21 @@
-/*     uipc_socket2.c  6.6     84/11/14        */
+/*
+ * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * 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_socket2.c      7.7 (Berkeley) %G%
+ */
 
 #include "param.h"
 #include "systm.h"
 
 #include "param.h"
 #include "systm.h"
@@ -8,6 +25,7 @@
 #include "file.h"
 #include "inode.h"
 #include "buf.h"
 #include "file.h"
 #include "inode.h"
 #include "buf.h"
+#include "malloc.h"
 #include "mbuf.h"
 #include "protosw.h"
 #include "socket.h"
 #include "mbuf.h"
 #include "protosw.h"
 #include "socket.h"
@@ -123,7 +141,8 @@ sonewconn(head)
        so->so_state = head->so_state | SS_NOFDREF;
        so->so_proto = head->so_proto;
        so->so_timeo = head->so_timeo;
        so->so_state = head->so_state | SS_NOFDREF;
        so->so_proto = head->so_proto;
        so->so_timeo = head->so_timeo;
-       so->so_pgrp = head->so_pgrp;
+       so->so_pgid = head->so_pgid;
+       (void) soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat);
        soqinsque(head, so, 0);
        if ((*so->so_proto->pr_usrreq)(so, PRU_ATTACH,
            (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)) {
        soqinsque(head, so, 0);
        if ((*so->so_proto->pr_usrreq)(so, PRU_ATTACH,
            (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)) {
@@ -217,7 +236,7 @@ socantrcvmore(so)
 sbselqueue(sb)
        struct sockbuf *sb;
 {
 sbselqueue(sb)
        struct sockbuf *sb;
 {
-       register struct proc *p;
+       struct proc *p;
 
        if ((p = sb->sb_sel) && p->p_wchan == (caddr_t)&selwait)
                sb->sb_flags |= SB_COLL;
 
        if ((p = sb->sb_sel) && p->p_wchan == (caddr_t)&selwait)
                sb->sb_flags |= SB_COLL;
@@ -238,10 +257,14 @@ sbwait(sb)
 
 /*
  * Wakeup processes waiting on a socket buffer.
 
 /*
  * Wakeup processes waiting on a socket buffer.
+ * Do asynchronous notification via SIGIO
+ * if the socket has the SS_ASYNC flag set.
  */
  */
-sbwakeup(sb)
+sowakeup(so, sb)
+       register struct socket *so;
        register struct sockbuf *sb;
 {
        register struct sockbuf *sb;
 {
+       register struct proc *p;
 
        if (sb->sb_sel) {
                selwakeup(sb->sb_sel, sb->sb_flags & SB_COLL);
 
        if (sb->sb_sel) {
                selwakeup(sb->sb_sel, sb->sb_flags & SB_COLL);
@@ -252,26 +275,10 @@ sbwakeup(sb)
                sb->sb_flags &= ~SB_WAIT;
                wakeup((caddr_t)&sb->sb_cc);
        }
                sb->sb_flags &= ~SB_WAIT;
                wakeup((caddr_t)&sb->sb_cc);
        }
-}
-
-/*
- * Wakeup socket readers and writers.
- * Do asynchronous notification via SIGIO
- * if the socket has the SS_ASYNC flag set.
- */
-sowakeup(so, sb)
-       register struct socket *so;
-       struct sockbuf *sb;
-{
-       register struct proc *p;
-
-       sbwakeup(sb);
        if (so->so_state & SS_ASYNC) {
        if (so->so_state & SS_ASYNC) {
-               if (so->so_pgrp == 0)
-                       return;
-               else if (so->so_pgrp > 0)
-                       gsignal(so->so_pgrp, SIGIO);
-               else if ((p = pfind(-so->so_pgrp)) != 0)
+               if (so->so_pgid < 0)
+                       gsignal(-so->so_pgid, SIGIO);
+               else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0)
                        psignal(p, SIGIO);
        }
 }
                        psignal(p, SIGIO);
        }
 }
@@ -287,7 +294,7 @@ sowakeup(so, sb)
  *
  * Data stored in a socket buffer is maintained as a list of records.
  * Each record is a list of mbufs chained together with the m_next
  *
  * Data stored in a socket buffer is maintained as a list of records.
  * Each record is a list of mbufs chained together with the m_next
- * field.  Records are chained together with the m_act field. The upper
+ * field.  Records are chained together with the m_nextpkt field. The upper
  * level routine soreceive() expects the following conventions to be
  * observed when placing information in the receive buffer:
  *
  * level routine soreceive() expects the following conventions to be
  * observed when placing information in the receive buffer:
  *
@@ -302,34 +309,15 @@ sowakeup(so, sb)
  *    a data record, perhaps of zero length.
  *
  * Before using a new socket structure it is first necessary to reserve
  *    a data record, perhaps of zero length.
  *
  * Before using a new socket structure it is first necessary to reserve
- * buffer space to the socket, by calling sbreserve().  This commits
+ * buffer space to the socket, by calling sbreserve().  This should commit
  * some of the available buffer space in the system buffer pool for the
  * some of the available buffer space in the system buffer pool for the
- * socket.  The space should be released by calling sbrelease() when the
- * socket is destroyed.
- *
- * The routines sbappend() or sbappendrecord() are normally called to
- * append new mbufs to a socket buffer, after checking that adequate
- * space is available, comparing the function sbspace() with the amount
- * of data to be added.  sbappendrecord() differs from sbappend() in
- * that data supplied is treated as the beginning of a new record.
- * Data is normally removed from a socket buffer in a protocol by
- * first calling m_copy on the socket buffer mbuf chain and sending this
- * to a peer, and then removing the data from the socket buffer with
- * sbdrop() or sbdroprecord() when the data is acknowledged by the peer
- * (or immediately in the case of unreliable protocols.)
- *
- * To place a sender's name, optionally, access rights, and data in a
- * socket buffer sbappendaddr() should be used.  To place access rights
- * and data in a socket buffer sbappendrights() should be used.  Note
- * that unlike sbappend() and sbappendrecord(), these routines check
- * for the caller that there will be enough space to store the data.
- * Each fails if there is not enough space, or if it cannot find mbufs
- * to store additional information in.
+ * socket (currently, it does nothing but enforce limits).  The space
+ * should be released by calling sbrelease() when the socket is destroyed.
  */
 
 soreserve(so, sndcc, rcvcc)
        register struct socket *so;
  */
 
 soreserve(so, sndcc, rcvcc)
        register struct socket *so;
-       int sndcc, rcvcc;
+       u_long sndcc, rcvcc;
 {
 
        if (sbreserve(&so->so_snd, sndcc) == 0)
 {
 
        if (sbreserve(&so->so_snd, sndcc) == 0)
@@ -345,17 +333,18 @@ bad:
 
 /*
  * Allot mbufs to a sockbuf.
 
 /*
  * Allot mbufs to a sockbuf.
+ * Attempt to scale cc so that mbcnt doesn't become limiting
+ * if buffering efficiency is near the normal case.
  */
 sbreserve(sb, cc)
        struct sockbuf *sb;
  */
 sbreserve(sb, cc)
        struct sockbuf *sb;
+       u_long cc;
 {
 
 {
 
-       if ((unsigned) cc > SB_MAX)
+       if (cc > (u_long)SB_MAX * MCLBYTES / (2 * MSIZE + MCLBYTES))
                return (0);
                return (0);
-       /* someday maybe this routine will fail... */
        sb->sb_hiwat = cc;
        sb->sb_hiwat = cc;
-       /* * 2 implies names can be no more than 1 mbuf each */
-       sb->sb_mbmax = MAX(cc * 2, SB_MAX);
+       sb->sb_mbmax = MIN(cc * 2, SB_MAX);
        return (1);
 }
 
        return (1);
 }
 
@@ -373,6 +362,26 @@ sbrelease(sb)
 /*
  * Routines to add and remove
  * data from an mbuf queue.
 /*
  * Routines to add and remove
  * data from an mbuf queue.
+ *
+ * The routines sbappend() or sbappendrecord() are normally called to
+ * append new mbufs to a socket buffer, after checking that adequate
+ * space is available, comparing the function sbspace() with the amount
+ * of data to be added.  sbappendrecord() differs from sbappend() in
+ * that data supplied is treated as the beginning of a new record.
+ * To place a sender's address, optional access rights, and data in a
+ * socket receive buffer, sbappendaddr() should be used.  To place
+ * access rights and data in a socket receive buffer, sbappendrights()
+ * should be used.  In either case, the new data begins a new record.
+ * Note that unlike sbappend() and sbappendrecord(), these routines check
+ * for the caller that there will be enough space to store the data.
+ * Each fails if there is not enough space, or if it cannot find mbufs
+ * to store additional information in.
+ *
+ * Reliable protocols may use the socket send buffer to hold data
+ * awaiting acknowledgement.  Data is normally copied from a socket
+ * send buffer in a protocol with m_copy for output to a peer,
+ * and then removing the data from the socket buffer with sbdrop()
+ * or sbdroprecord() when the data is acknowledged by the peer.
  */
 
 /*
  */
 
 /*
@@ -390,8 +399,8 @@ sbappend(sb, m)
        if (m == 0)
                return;
        if (n = sb->sb_mb) {
        if (m == 0)
                return;
        if (n = sb->sb_mb) {
-               while (n->m_act)
-                       n = n->m_act;
+               while (n->m_nextpkt)
+                       n = n->m_nextpkt;
                while (n->m_next)
                        n = n->m_next;
        }
                while (n->m_next)
                        n = n->m_next;
        }
@@ -411,15 +420,15 @@ sbappendrecord(sb, m0)
        if (m0 == 0)
                return;
        if (m = sb->sb_mb)
        if (m0 == 0)
                return;
        if (m = sb->sb_mb)
-               while (m->m_act)
-                       m = m->m_act;
+               while (m->m_nextpkt)
+                       m = m->m_nextpkt;
        /*
         * Put the first mbuf on the queue.
         * Note this permits zero length records.
         */
        sballoc(sb, m0);
        if (m)
        /*
         * Put the first mbuf on the queue.
         * Note this permits zero length records.
         */
        sballoc(sb, m0);
        if (m)
-               m->m_act = m0;
+               m->m_nextpkt = m0;
        else
                sb->sb_mb = m0;
        m = m0->m_next;
        else
                sb->sb_mb = m0;
        m = m0->m_next;
@@ -429,74 +438,64 @@ sbappendrecord(sb, m0)
 
 /*
  * Append address and data, and optionally, rights
 
 /*
  * Append address and data, and optionally, rights
- * to the receive queue of a socket.  Return 0 if
+ * to the receive queue of a socket.  If present,
+ * m0 Return 0 if
  * no space in sockbuf or insufficient mbufs.
  */
  * no space in sockbuf or insufficient mbufs.
  */
-sbappendaddr(sb, asa, m0, rights0)             /* XXX */
+sbappendaddr(sb, asa, m0, rights0)
        register struct sockbuf *sb;
        struct sockaddr *asa;
        register struct sockbuf *sb;
        struct sockaddr *asa;
-       struct mbuf *rights0, *m0;
+       struct mbuf *m0, *rights0;
 {
        register struct mbuf *m, *n;
        int space = sizeof (*asa);
 
 {
        register struct mbuf *m, *n;
        int space = sizeof (*asa);
 
-       m = m0;
-       if (m == 0)
-               panic("sbappendaddr");
-       do {
-               space += m->m_len;
-               m = m->m_next;
-       } while (m);
+if (m0 && (m0->m_flags & M_PKTHDR) == 0)
+panic("sbappendaddr");
+       if (m0)
+               space += m0->m_pkthdr.len;
        if (rights0)
                space += rights0->m_len;
        if (space > sbspace(sb))
                return (0);
        if (rights0)
                space += rights0->m_len;
        if (space > sbspace(sb))
                return (0);
-       m = m_get(M_DONTWAIT, MT_SONAME);
+       MGET(m, M_DONTWAIT, MT_SONAME);
        if (m == 0)
                return (0);
        *mtod(m, struct sockaddr *) = *asa;
        m->m_len = sizeof (*asa);
        if (m == 0)
                return (0);
        *mtod(m, struct sockaddr *) = *asa;
        m->m_len = sizeof (*asa);
-       if (rights0) {
-               m->m_act = m_copy(rights0, 0, rights0->m_len);
-               if (m->m_act == 0) {
+       if (rights0 && rights0->m_len) {
+               m->m_next = m_copy(rights0, 0, rights0->m_len);
+               if (m->m_next == 0) {
                        m_freem(m);
                        return (0);
                }
                        m_freem(m);
                        return (0);
                }
-               sballoc(sb, m);
-               sballoc(sb, m->m_act);
-       } else
-               sballoc(sb, m);
+               sballoc(sb, m->m_next);
+       }
+       sballoc(sb, m);
        if (n = sb->sb_mb) {
        if (n = sb->sb_mb) {
-               while (n->m_act)
-                       n = n->m_act;
-               n->m_act = m;
+               while (n->m_nextpkt)
+                       n = n->m_nextpkt;
+               n->m_nextpkt = m;
        } else
                sb->sb_mb = m;
        } else
                sb->sb_mb = m;
-       if (m->m_act)
-               m = m->m_act;
-       sballoc(sb, m0);
-       m->m_act = m0;
-       m = m0->m_next;
-       m0->m_next = 0;
-       sbcompress(sb, m, m0);
+       if (m->m_next)
+               m = m->m_next;
+       if (m0)
+               sbcompress(sb, m0, m);
        return (1);
 }
 
        return (1);
 }
 
-#ifdef notdef
-sbappendrights(sb, rights, m0)
+sbappendrights(sb, m0, rights)
        struct sockbuf *sb;
        struct sockbuf *sb;
-       struct mbuf *rights, *m;
+       struct mbuf *rights, *m0;
 {
        register struct mbuf *m, *n;
        int space = 0;
 
 {
        register struct mbuf *m, *n;
        int space = 0;
 
-       m = m0;
-       if (m == 0 || rights == 0)
+       if (rights == 0)
                panic("sbappendrights");
                panic("sbappendrights");
-       do {
+       for (m = m0; m; m = m->m_next)
                space += m->m_len;
                space += m->m_len;
-               m = m->m_next;
-       } while (m);
        space += rights->m_len;
        if (space > sbspace(sb))
                return (0);
        space += rights->m_len;
        if (space > sbspace(sb))
                return (0);
@@ -505,19 +504,15 @@ sbappendrights(sb, rights, m0)
                return (0);
        sballoc(sb, m);
        if (n = sb->sb_mb) {
                return (0);
        sballoc(sb, m);
        if (n = sb->sb_mb) {
-               while (n->m_act)
-                       n = n->m_act;
-               n->m_act = m;
+               while (n->m_nextpkt)
+                       n = n->m_nextpkt;
+               n->m_nextpkt = m;
        } else
        } else
-               n->m_act = m;
-       sballoc(sb, m0);
-       m->m_act = m0;
-       m = m0->m_next;
-       m0->m_next = 0;
-       sbcompress(sb, m, m0);
+               sb->sb_mb = m;
+       if (m0)
+               sbcompress(sb, m0, m);
        return (1);
 }
        return (1);
 }
-#endif
 
 /*
  * Compress mbuf chain m into the socket
 
 /*
  * Compress mbuf chain m into the socket
@@ -534,8 +529,9 @@ sbcompress(sb, m, n)
                        m = m_free(m);
                        continue;
                }
                        m = m_free(m);
                        continue;
                }
-               if (n && n->m_off <= MMAXOFF && m->m_off <= MMAXOFF &&
-                   (n->m_off + n->m_len + m->m_len) <= MMAXOFF) {
+               if (n && (n->m_flags & M_EXT) == 0 &&
+                   (n->m_data + n->m_len + m->m_len) < &n->m_dat[MLEN] &&
+                   n->m_type == m->m_type) {
                        bcopy(mtod(m, caddr_t), mtod(n, caddr_t) + n->m_len,
                            (unsigned)m->m_len);
                        n->m_len += m->m_len;
                        bcopy(mtod(m, caddr_t), mtod(n, caddr_t) + n->m_len,
                            (unsigned)m->m_len);
                        n->m_len += m->m_len;
@@ -564,8 +560,8 @@ sbflush(sb)
 
        if (sb->sb_flags & SB_LOCK)
                panic("sbflush");
 
        if (sb->sb_flags & SB_LOCK)
                panic("sbflush");
-       if (sb->sb_cc)
-               sbdrop(sb, sb->sb_cc);
+       while (sb->sb_mbcnt)
+               sbdrop(sb, (int)sb->sb_cc);
        if (sb->sb_cc || sb->sb_mbcnt || sb->sb_mb)
                panic("sbflush 2");
 }
        if (sb->sb_cc || sb->sb_mbcnt || sb->sb_mb)
                panic("sbflush 2");
 }
@@ -573,7 +569,6 @@ sbflush(sb)
 /*
  * Drop data from (the front of) a sockbuf.
  */
 /*
  * Drop data from (the front of) a sockbuf.
  */
-struct mbuf *
 sbdrop(sb, len)
        register struct sockbuf *sb;
        register int len;
 sbdrop(sb, len)
        register struct sockbuf *sb;
        register int len;
@@ -581,18 +576,18 @@ sbdrop(sb, len)
        register struct mbuf *m, *mn;
        struct mbuf *next;
 
        register struct mbuf *m, *mn;
        struct mbuf *next;
 
-       next = (m = sb->sb_mb) ? m->m_act : 0;
+       next = (m = sb->sb_mb) ? m->m_nextpkt : 0;
        while (len > 0) {
                if (m == 0) {
                        if (next == 0)
                                panic("sbdrop");
                        m = next;
        while (len > 0) {
                if (m == 0) {
                        if (next == 0)
                                panic("sbdrop");
                        m = next;
-                       next = m->m_act;
+                       next = m->m_nextpkt;
                        continue;
                }
                if (m->m_len > len) {
                        m->m_len -= len;
                        continue;
                }
                if (m->m_len > len) {
                        m->m_len -= len;
-                       m->m_off += len;
+                       m->m_data += len;
                        sb->sb_cc -= len;
                        break;
                }
                        sb->sb_cc -= len;
                        break;
                }
@@ -602,22 +597,21 @@ sbdrop(sb, len)
                m = mn;
        }
        while (m && m->m_len == 0) {
                m = mn;
        }
        while (m && m->m_len == 0) {
+               sbfree(sb, m);
                MFREE(m, mn);
                m = mn;
        }
        if (m) {
                sb->sb_mb = m;
                MFREE(m, mn);
                m = mn;
        }
        if (m) {
                sb->sb_mb = m;
-               m->m_act = next;
+               m->m_nextpkt = next;
        } else
                sb->sb_mb = next;
        } else
                sb->sb_mb = next;
-       return (sb->sb_mb);
 }
 
 /*
  * Drop a record off the front of a sockbuf
  * and move the next record to the front.
  */
 }
 
 /*
  * Drop a record off the front of a sockbuf
  * and move the next record to the front.
  */
-struct mbuf *
 sbdroprecord(sb)
        register struct sockbuf *sb;
 {
 sbdroprecord(sb)
        register struct sockbuf *sb;
 {
@@ -625,11 +619,10 @@ sbdroprecord(sb)
 
        m = sb->sb_mb;
        if (m) {
 
        m = sb->sb_mb;
        if (m) {
-               sb->sb_mb = m->m_act;
+               sb->sb_mb = m->m_nextpkt;
                do {
                        sbfree(sb, m);
                        MFREE(m, mn);
                } while (m = mn);
        }
                do {
                        sbfree(sb, m);
                        MFREE(m, mn);
                } while (m = mn);
        }
-       return (sb->sb_mb);
 }
 }