Author: jhb
Date: Mon Jan 13 21:29:34 2014
New Revision: 260606
URL: http://svnweb.freebsd.org/changeset/base/260606

Log:
  MFC 197775,197777-197779,197781,197794,243152,243313,255478:
  First cut at implementing SOCK_SEQPACKET support for UNIX (local) domain
  sockets.  This allows for reliable bi-directional datagram communication
  over UNIX domain sockets, in contrast to SOCK_DGRAM (M:N, unreliable) or
  SOCK_STERAM (bi-directional bytestream).  Largely, this reuses existing
  UNIX domain socket code.  This allows applications requiring record-
  oriented semantics to do so reliably via local IPC.

Added:
  stable/8/tools/regression/sockets/unix_seqpacket/
     - copied from r197781, head/tools/regression/sockets/unix_seqpacket/
     - copied from r197781, 
head/tools/regression/sockets/unix_seqpacket_exercise/
Directory Properties:
  stable/8/tools/regression/sockets/unix_seqpacket_exercise/   (props changed)
Modified:
  stable/8/share/man/man4/unix.4
  stable/8/sys/kern/uipc_usrreq.c
  
stable/8/tools/regression/sockets/unix_seqpacket_exercise/unix_seqpacket_exercise.c
  stable/8/usr.bin/netstat/main.c   (contents, props changed)
  stable/8/usr.bin/netstat/netstat.h   (contents, props changed)
  stable/8/usr.bin/netstat/unix.c   (contents, props changed)
Directory Properties:
  stable/8/share/man/man4/   (props changed)
  stable/8/sys/   (props changed)
  stable/8/sys/kern/   (props changed)
  stable/8/tools/regression/sockets/   (props changed)
  stable/8/usr.bin/netstat/   (props changed)

Modified: stable/8/share/man/man4/unix.4
==============================================================================
--- stable/8/share/man/man4/unix.4      Mon Jan 13 20:55:15 2014        
(r260605)
+++ stable/8/share/man/man4/unix.4      Mon Jan 13 21:29:34 2014        
(r260606)
@@ -32,7 +32,7 @@
 .\"     @(#)unix.4     8.1 (Berkeley) 6/9/93
 .\" $FreeBSD$
 .\"
-.Dd July 15, 2001
+.Dd October 5, 2009
 .Dt UNIX 4
 .Os
 .Sh NAME
@@ -52,7 +52,8 @@ mechanisms.
 The
 .Ux Ns -domain
 family supports the
-.Dv SOCK_STREAM
+.Dv SOCK_STREAM ,
+.Dv SOCK_SEQPACKET ,
 and
 .Dv SOCK_DGRAM
 socket types and uses
@@ -127,11 +128,14 @@ The
 .Ux Ns -domain
 protocol family is comprised of simple
 transport protocols that support the
-.Dv SOCK_STREAM
+.Dv SOCK_STREAM ,
+.Dv SOCK_SEQPACKET ,
 and
 .Dv SOCK_DGRAM
 abstractions.
 .Dv SOCK_STREAM
+and
+.Dv SOCK_SEQPACKET
 sockets also support the communication of
 .Ux
 file descriptors through the use of the
@@ -206,8 +210,9 @@ and tested with
 .Xr getsockopt 2 :
 .Bl -tag -width ".Dv LOCAL_CONNWAIT"
 .It Dv LOCAL_CREDS
-This option may be enabled on a
-.Dv SOCK_DGRAM
+This option may be enabled on
+.Dv SOCK_DGRAM ,
+.Dv SOCK_SEQPACKET ,
 or a
 .Dv SOCK_STREAM
 socket.

Modified: stable/8/sys/kern/uipc_usrreq.c
==============================================================================
--- stable/8/sys/kern/uipc_usrreq.c     Mon Jan 13 20:55:15 2014        
(r260605)
+++ stable/8/sys/kern/uipc_usrreq.c     Mon Jan 13 21:29:34 2014        
(r260606)
@@ -50,7 +50,8 @@
  * garbage collector to find and tear down cycles of disconnected sockets.
  *
  * TODO:
- *     SEQPACKET, RDM
+ *     RDM
+ *     distinguish datagram size limits from flow control limits in SEQPACKET
  *     rethink name space problems
  *     need a proper out-of-band
  */
@@ -113,6 +114,7 @@ static ino_t                unp_ino;        /* Prototype 
for 
 static int             unp_rights;     /* (g) File descriptors in flight. */
 static struct unp_head unp_shead;      /* (l) List of stream sockets. */
 static struct unp_head unp_dhead;      /* (l) List of datagram sockets. */
+static struct unp_head unp_sphead;     /* (l) List of seqpacket sockets. */
 
 struct unp_defer {
        SLIST_ENTRY(unp_defer) ud_link;
@@ -154,10 +156,14 @@ static u_long     unpst_sendspace = PIPSIZ;
 static u_long  unpst_recvspace = PIPSIZ;
 static u_long  unpdg_sendspace = 2*1024;       /* really max datagram size */
 static u_long  unpdg_recvspace = 4*1024;
+static u_long  unpsp_sendspace = PIPSIZ;       /* really max datagram size */
+static u_long  unpsp_recvspace = PIPSIZ;
 
 SYSCTL_NODE(_net, PF_LOCAL, local, CTLFLAG_RW, 0, "Local domain");
 SYSCTL_NODE(_net_local, SOCK_STREAM, stream, CTLFLAG_RW, 0, "SOCK_STREAM");
 SYSCTL_NODE(_net_local, SOCK_DGRAM, dgram, CTLFLAG_RW, 0, "SOCK_DGRAM");
+SYSCTL_NODE(_net_local, SOCK_SEQPACKET, seqpacket, CTLFLAG_RW, 0,
+    "SOCK_SEQPACKET");
 
 SYSCTL_ULONG(_net_local_stream, OID_AUTO, sendspace, CTLFLAG_RW,
           &unpst_sendspace, 0, "Default stream send space.");
@@ -167,6 +173,10 @@ SYSCTL_ULONG(_net_local_dgram, OID_AUTO,
           &unpdg_sendspace, 0, "Default datagram send space.");
 SYSCTL_ULONG(_net_local_dgram, OID_AUTO, recvspace, CTLFLAG_RW,
           &unpdg_recvspace, 0, "Default datagram receive space.");
+SYSCTL_ULONG(_net_local_seqpacket, OID_AUTO, maxseqpacket, CTLFLAG_RW,
+          &unpsp_sendspace, 0, "Default seqpacket send space.");
+SYSCTL_ULONG(_net_local_seqpacket, OID_AUTO, recvspace, CTLFLAG_RW,
+          &unpsp_recvspace, 0, "Default seqpacket receive space.");
 SYSCTL_INT(_net_local, OID_AUTO, inflight, CTLFLAG_RD, &unp_rights, 0,
     "File descriptors in flight.");
 SYSCTL_INT(_net_local, OID_AUTO, deferred, CTLFLAG_RD,
@@ -282,6 +292,7 @@ static void unp_process_defers(void * __
  */
 static struct domain localdomain;
 static struct pr_usrreqs uipc_usrreqs_dgram, uipc_usrreqs_stream;
+static struct pr_usrreqs uipc_usrreqs_seqpacket;
 static struct protosw localsw[] = {
 {
        .pr_type =              SOCK_STREAM,
@@ -296,6 +307,20 @@ static struct protosw localsw[] = {
        .pr_flags =             PR_ATOMIC|PR_ADDR|PR_RIGHTS,
        .pr_usrreqs =           &uipc_usrreqs_dgram
 },
+{
+       .pr_type =              SOCK_SEQPACKET,
+       .pr_domain =            &localdomain,
+
+       /*
+        * XXXRW: For now, PR_ADDR because soreceive will bump into them
+        * due to our use of sbappendaddr.  A new sbappend variants is needed
+        * that supports both atomic record writes and control data.
+        */
+       .pr_flags =             PR_ADDR|PR_ATOMIC|PR_CONNREQUIRED|PR_WANTRCVD|
+                                   PR_RIGHTS,
+       .pr_ctloutput =         &uipc_ctloutput,
+       .pr_usrreqs =           &uipc_usrreqs_seqpacket,
+},
 };
 
 static struct domain localdomain = {
@@ -378,6 +403,11 @@ uipc_attach(struct socket *so, int proto
                        recvspace = unpdg_recvspace;
                        break;
 
+               case SOCK_SEQPACKET:
+                       sendspace = unpsp_sendspace;
+                       recvspace = unpsp_recvspace;
+                       break;
+
                default:
                        panic("uipc_attach");
                }
@@ -397,8 +427,22 @@ uipc_attach(struct socket *so, int proto
        UNP_LIST_LOCK();
        unp->unp_gencnt = ++unp_gencnt;
        unp_count++;
-       LIST_INSERT_HEAD(so->so_type == SOCK_DGRAM ? &unp_dhead : &unp_shead,
-           unp, unp_link);
+       switch (so->so_type) {
+       case SOCK_STREAM:
+               LIST_INSERT_HEAD(&unp_shead, unp, unp_link);
+               break;
+
+       case SOCK_DGRAM:
+               LIST_INSERT_HEAD(&unp_dhead, unp, unp_link);
+               break;
+
+       case SOCK_SEQPACKET:
+               LIST_INSERT_HEAD(&unp_sphead, unp, unp_link);
+               break;
+
+       default:
+               panic("uipc_attach");
+       }
        UNP_LIST_UNLOCK();
 
        return (0);
@@ -732,11 +776,8 @@ uipc_rcvd(struct socket *so, int flags)
        unp = sotounpcb(so);
        KASSERT(unp != NULL, ("uipc_rcvd: unp == NULL"));
 
-       if (so->so_type == SOCK_DGRAM)
-               panic("uipc_rcvd DGRAM?");
-
-       if (so->so_type != SOCK_STREAM)
-               panic("uipc_rcvd unknown socktype");
+       if (so->so_type != SOCK_STREAM && so->so_type != SOCK_SEQPACKET)
+               panic("uipc_rcvd socktype %d", so->so_type);
 
        /*
         * Adjust backpressure on sender and wakeup any waiting to write.
@@ -851,6 +892,7 @@ uipc_send(struct socket *so, int flags, 
                break;
        }
 
+       case SOCK_SEQPACKET:
        case SOCK_STREAM:
                if ((so->so_state & SS_ISCONNECTED) == 0) {
                        if (nam != NULL) {
@@ -893,7 +935,8 @@ uipc_send(struct socket *so, int flags, 
                SOCKBUF_LOCK(&so2->so_rcv);
                if (unp2->unp_flags & UNP_WANTCRED) {
                        /*
-                        * Credentials are passed only once on SOCK_STREAM.
+                        * Credentials are passed only once on SOCK_STREAM
+                        * and SOCK_SEQPACKET.
                         */
                        unp2->unp_flags &= ~UNP_WANTCRED;
                        control = unp_addsockcred(td, control);
@@ -902,11 +945,33 @@ uipc_send(struct socket *so, int flags, 
                 * Send to paired receive port, and then reduce send buffer
                 * hiwater marks to maintain backpressure.  Wake up readers.
                 */
-               if (control != NULL) {
-                       if (sbappendcontrol_locked(&so2->so_rcv, m, control))
+               switch (so->so_type) {
+               case SOCK_STREAM:
+                       if (control != NULL) {
+                               if (sbappendcontrol_locked(&so2->so_rcv, m,
+                                   control))
+                                       control = NULL;
+                       } else
+                               sbappend_locked(&so2->so_rcv, m);
+                       break;
+
+               case SOCK_SEQPACKET: {
+                       const struct sockaddr *from;
+
+                       from = &sun_noname;
+                       if (sbappendaddr_locked(&so2->so_rcv, from, m,
+                           control))
                                control = NULL;
-               } else
-                       sbappend_locked(&so2->so_rcv, m);
+                       break;
+                       }
+               }
+
+               /*
+                * XXXRW: While fine for SOCK_STREAM, this conflates maximum
+                * datagram size and back-pressure for SOCK_SEQPACKET, which
+                * can lead to undesired return of EMSGSIZE on send instead
+                * of more desirable blocking.
+                */
                mbcnt_delta = so2->so_rcv.sb_mbcnt - unp2->unp_mbcnt;
                unp2->unp_mbcnt = so2->so_rcv.sb_mbcnt;
                sbcc = so2->so_rcv.sb_cc;
@@ -969,7 +1034,8 @@ uipc_sense(struct socket *so, struct sta
        UNP_LINK_RLOCK();
        UNP_PCB_LOCK(unp);
        unp2 = unp->unp_conn;
-       if (so->so_type == SOCK_STREAM && unp2 != NULL) {
+       if ((so->so_type == SOCK_STREAM || so->so_type == SOCK_SEQPACKET) &&
+           unp2 != NULL) {
                so2 = unp2->unp_socket;
                sb->st_blksize += so2->so_rcv.sb_cc;
        }
@@ -1039,6 +1105,26 @@ static struct pr_usrreqs uipc_usrreqs_dg
        .pru_close =            uipc_close,
 };
 
+static struct pr_usrreqs uipc_usrreqs_seqpacket = {
+       .pru_abort =            uipc_abort,
+       .pru_accept =           uipc_accept,
+       .pru_attach =           uipc_attach,
+       .pru_bind =             uipc_bind,
+       .pru_connect =          uipc_connect,
+       .pru_connect2 =         uipc_connect2,
+       .pru_detach =           uipc_detach,
+       .pru_disconnect =       uipc_disconnect,
+       .pru_listen =           uipc_listen,
+       .pru_peeraddr =         uipc_peeraddr,
+       .pru_rcvd =             uipc_rcvd,
+       .pru_send =             uipc_send,
+       .pru_sense =            uipc_sense,
+       .pru_shutdown =         uipc_shutdown,
+       .pru_sockaddr =         uipc_sockaddr,
+       .pru_soreceive =        soreceive_generic,      /* XXX: or...? */
+       .pru_close =            uipc_close,
+};
+
 static struct pr_usrreqs uipc_usrreqs_stream = {
        .pru_abort =            uipc_abort,
        .pru_accept =           uipc_accept,
@@ -1340,6 +1426,7 @@ unp_connect2(struct socket *so, struct s
                break;
 
        case SOCK_STREAM:
+       case SOCK_SEQPACKET:
                unp2->unp_conn = unp;
                if (req == PRU_CONNECT &&
                    ((unp->unp_flags | unp2->unp_flags) & UNP_CONNWAIT))
@@ -1377,6 +1464,7 @@ unp_disconnect(struct unpcb *unp, struct
                break;
 
        case SOCK_STREAM:
+       case SOCK_SEQPACKET:
                soisdisconnected(unp->unp_socket);
                unp2->unp_conn = NULL;
                soisdisconnected(unp2->unp_socket);
@@ -1402,7 +1490,22 @@ unp_pcblist(SYSCTL_HANDLER_ARGS)
        struct unp_head *head;
        struct xunpcb *xu;
 
-       head = ((intptr_t)arg1 == SOCK_DGRAM ? &unp_dhead : &unp_shead);
+       switch ((intptr_t)arg1) {
+       case SOCK_STREAM:
+               head = &unp_shead;
+               break;
+
+       case SOCK_DGRAM:
+               head = &unp_dhead;
+               break;
+
+       case SOCK_SEQPACKET:
+               head = &unp_sphead;
+               break;
+
+       default:
+               panic("unp_pcblist: arg1 %d", (int)(intptr_t)arg1);
+       }
 
        /*
         * The process of preparing the PCB list is too time-consuming and
@@ -1515,6 +1618,9 @@ SYSCTL_PROC(_net_local_dgram, OID_AUTO, 
 SYSCTL_PROC(_net_local_stream, OID_AUTO, pcblist, CTLFLAG_RD,
            (caddr_t)(long)SOCK_STREAM, 0, unp_pcblist, "S,xunpcb",
            "List of active local stream sockets");
+SYSCTL_PROC(_net_local_seqpacket, OID_AUTO, pcblist, CTLFLAG_RD,
+           (caddr_t)(long)SOCK_SEQPACKET, 0, unp_pcblist, "S,xunpcb",
+           "List of active local seqpacket sockets");
 
 static void
 unp_shutdown(struct unpcb *unp)
@@ -1526,7 +1632,8 @@ unp_shutdown(struct unpcb *unp)
        UNP_PCB_LOCK_ASSERT(unp);
 
        unp2 = unp->unp_conn;
-       if (unp->unp_socket->so_type == SOCK_STREAM && unp2 != NULL) {
+       if ((unp->unp_socket->so_type == SOCK_STREAM ||
+           (unp->unp_socket->so_type == SOCK_SEQPACKET)) && unp2 != NULL) {
                so = unp2->unp_socket;
                if (so != NULL)
                        socantrcvmore(so);
@@ -1692,6 +1799,7 @@ unp_init(void)
            NULL, EVENTHANDLER_PRI_ANY);
        LIST_INIT(&unp_dhead);
        LIST_INIT(&unp_shead);
+       LIST_INIT(&unp_sphead);
        SLIST_INIT(&unp_defers);
        TASK_INIT(&unp_gc_task, 0, unp_gc, NULL);
        TASK_INIT(&unp_defer_task, 0, unp_process_defers, NULL);
@@ -2065,7 +2173,8 @@ SYSCTL_INT(_net_local, OID_AUTO, taskcou
 static void
 unp_gc(__unused void *arg, int pending)
 {
-       struct unp_head *heads[] = { &unp_dhead, &unp_shead, NULL };
+       struct unp_head *heads[] = { &unp_dhead, &unp_shead, &unp_sphead,
+                                   NULL };
        struct unp_head **head;
        struct file *f, **unref;
        struct unpcb *unp;

Modified: 
stable/8/tools/regression/sockets/unix_seqpacket_exercise/unix_seqpacket_exercise.c
==============================================================================
--- 
head/tools/regression/sockets/unix_seqpacket_exercise/unix_seqpacket_exercise.c 
    Mon Oct  5 15:27:01 2009        (r197781)
+++ 
stable/8/tools/regression/sockets/unix_seqpacket_exercise/unix_seqpacket_exercise.c
 Mon Jan 13 21:29:34 2014        (r260606)
@@ -50,21 +50,21 @@ __FBSDID("$FreeBSD$");
 #define        SEQPACKET_SNDBUF        (131072-16)
 
 #define        FAILERR(str)            err(-1, "%s: %s", __func__, str)
-#define        FAILNERR(str, n)        err(-1, "%s %d: %s", __func__, n, str)
-#define        FAILNMERR(str, n, m)    err(-1, "%s %d %d: %s", __func__, n, m, 
str)
+#define        FAILNERR(str, n)        err(-1, "%s %zd: %s", __func__, n, str)
+#define        FAILNMERR(str, n, m)    err(-1, "%s %zd %d: %s", __func__, n, 
m, str)
 #define        FAILERRX(str)           errx(-1, "%s: %s", __func__, str)
-#define        FAILNERRX(str, n)       errx(-1, "%s %d: %s", __func__, n, str)
-#define        FAILNMERRX(str, n, m)   errx(-1, "%s %d %d: %s", __func__, n, 
m, str)
+#define        FAILNERRX(str, n)       errx(-1, "%s %zd: %s", __func__, n, str)
+#define        FAILNMERRX(str, n, m)   errx(-1, "%s %zd %d: %s", __func__, n, 
m, str)
 
 static int ann = 0;
 
 #define        ANN()           (ann ? warnx("%s: start", __func__) : 0)
-#define        ANNN(n)         (ann ? warnx("%s %d: start", __func__, (n)) : 0)
-#define        ANNNM(n, m)     (ann ? warnx("%s %d %d: start", __func__, (n), 
(m)) : 0)
+#define        ANNN(n)         (ann ? warnx("%s %zd: start", __func__, (n)) : 
0)
+#define        ANNNM(n, m)     (ann ? warnx("%s %zd %d: start", __func__, (n), 
(m)):0)
 
 #define        OK()            warnx("%s: ok", __func__)
-#define        OKN(n)          warnx("%s %d: ok", __func__, (n))
-#define        OKNM(n, m)      warnx("%s %d %d: ok", __func__, (n), (m))
+#define        OKN(n)          warnx("%s %zd: ok", __func__, (n))
+#define        OKNM(n, m)      warnx("%s %zd %d: ok", __func__, (n), (m))
 
 #ifdef SO_NOSIGPIPE
 #define        NEW_SOCKET(s) do {                                              
\
@@ -168,7 +168,7 @@ server(int s_listen)
                                        break;
                                }
                                if (ssize_send != ssize_recv)
-                                       warnx("server: recv %d sent %d",
+                                       warnx("server: recv %zd sent %zd",
                                            ssize_recv, ssize_send);
                        } while (1);
                        close(s_accept);

Modified: stable/8/usr.bin/netstat/main.c
==============================================================================
--- stable/8/usr.bin/netstat/main.c     Mon Jan 13 20:55:15 2014        
(r260605)
+++ stable/8/usr.bin/netstat/main.c     Mon Jan 13 21:29:34 2014        
(r260606)
@@ -186,6 +186,8 @@ static struct nlist nl[] = {
        { .n_name = "_mfctablesize" },
 #define N_ARPSTAT       55
        { .n_name = "_arpstat" },
+#define        N_UNP_SPHEAD    56
+       { .n_name = "unp_sphead" },
        { .n_name = NULL },
 };
 
@@ -627,7 +629,8 @@ main(int argc, char *argv[])
 #endif /* NETGRAPH */
        if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
                unixpr(nl[N_UNP_COUNT].n_value, nl[N_UNP_GENCNT].n_value,
-                   nl[N_UNP_DHEAD].n_value, nl[N_UNP_SHEAD].n_value);
+                   nl[N_UNP_DHEAD].n_value, nl[N_UNP_SHEAD].n_value,
+                   nl[N_UNP_SPHEAD].n_value);
        exit(0);
 }
 

Modified: stable/8/usr.bin/netstat/netstat.h
==============================================================================
--- stable/8/usr.bin/netstat/netstat.h  Mon Jan 13 20:55:15 2014        
(r260605)
+++ stable/8/usr.bin/netstat/netstat.h  Mon Jan 13 21:29:34 2014        
(r260606)
@@ -158,7 +158,7 @@ void        ddp_stats(u_long, const char *, int
 void   netgraphprotopr(u_long, const char *, int, int);
 #endif
 
-void   unixpr(u_long, u_long, u_long, u_long);
+void   unixpr(u_long, u_long, u_long, u_long, u_long);
 
 void   esis_stats(u_long, const char *, int, int);
 void   clnp_stats(u_long, const char *, int, int);

Modified: stable/8/usr.bin/netstat/unix.c
==============================================================================
--- stable/8/usr.bin/netstat/unix.c     Mon Jan 13 20:55:15 2014        
(r260605)
+++ stable/8/usr.bin/netstat/unix.c     Mon Jan 13 21:29:34 2014        
(r260606)
@@ -193,21 +193,37 @@ fail:
 }
 
 void
-unixpr(u_long count_off, u_long gencnt_off, u_long dhead_off, u_long shead_off)
+unixpr(u_long count_off, u_long gencnt_off, u_long dhead_off, u_long shead_off,
+    u_long sphead_off)
 {
        char    *buf;
        int     ret, type;
        struct  xsocket *so;
        struct  xunpgen *xug, *oxug;
        struct  xunpcb *xunp;
+       u_long  head_off;
 
        for (type = SOCK_STREAM; type <= SOCK_SEQPACKET; type++) {
                if (live)
                        ret = pcblist_sysctl(type, &buf);
-               else
-                       ret = pcblist_kvm(count_off, gencnt_off,
-                           type == SOCK_STREAM ? shead_off :
-                           (type == SOCK_DGRAM ? dhead_off : 0), &buf);
+               else {
+                       head_off = 0;
+                       switch (type) {
+                       case SOCK_STREAM:
+                               head_off = shead_off;
+                               break;
+
+                       case SOCK_DGRAM:
+                               head_off = dhead_off;
+                               break;
+
+                       case SOCK_SEQPACKET:
+                               head_off = sphead_off;
+                               break;
+                       }
+                       ret = pcblist_kvm(count_off, gencnt_off, head_off,
+                           &buf);
+               }
                if (ret == -1)
                        continue;
                if (ret < 0)
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to