]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/uipc_socket2.c
xnu-3789.51.2.tar.gz
[apple/xnu.git] / bsd / kern / uipc_socket2.c
index f8b94b90469b28646301a04dfc9591179bc54b01..45c15184826def5e3193e479ae7e5bcebd0af570 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 1998-2017 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
 #define        DBG_FNC_SBDROP          NETDBG_CODE(DBG_NETSOCK, 4)
 #define        DBG_FNC_SBAPPEND        NETDBG_CODE(DBG_NETSOCK, 5)
 
+extern char *proc_best_name(proc_t p);
+
 SYSCTL_DECL(_kern_ipc);
 
 __private_extern__ u_int32_t net_io_policy_throttle_best_effort = 0;
@@ -136,8 +138,8 @@ u_int32_t   high_sb_max = SB_MAX;
 
 static u_int32_t sb_efficiency = 8;    /* parameter for sbreserve() */
 int32_t total_sbmb_cnt __attribute__((aligned(8))) = 0;
+int32_t total_sbmb_cnt_floor __attribute__((aligned(8))) = 0;
 int32_t total_sbmb_cnt_peak __attribute__((aligned(8))) = 0;
-int32_t total_snd_byte_count __attribute__((aligned(8))) = 0;
 int64_t sbmb_limreached __attribute__((aligned(8))) = 0;
 
 /* Control whether to throttle sockets eligible to be throttled */
@@ -181,7 +183,6 @@ u_int32_t net_io_policy_uuid = 1;   /* enable UUID socket policy */
 void
 soisconnecting(struct socket *so)
 {
-
        so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING);
        so->so_state |= SS_ISCONNECTING;
 
@@ -191,8 +192,6 @@ soisconnecting(struct socket *so)
 void
 soisconnected(struct socket *so)
 {
-       struct socket *head = so->so_head;
-
        so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING);
        so->so_state |= SS_ISCONNECTED;
 
@@ -200,22 +199,44 @@ soisconnected(struct socket *so)
 
        sflt_notify(so, sock_evt_connected, NULL);
 
-       if (head && (so->so_state & SS_INCOMP)) {
-               so->so_state &= ~SS_INCOMP;
-               so->so_state |= SS_COMP;
+       if (so->so_head != NULL && (so->so_state & SS_INCOMP)) {
+               struct socket *head = so->so_head;
+               int locked = 0;
+
+               /*
+                * Enforce lock order when the protocol has per socket locks
+                */
                if (head->so_proto->pr_getlock != NULL) {
-                       socket_unlock(so, 0);
                        socket_lock(head, 1);
+                       so_acquire_accept_list(head, so);
+                       locked = 1;
                }
-               postevent(head, 0, EV_RCONN);
-               TAILQ_REMOVE(&head->so_incomp, so, so_list);
-               head->so_incqlen--;
-               TAILQ_INSERT_TAIL(&head->so_comp, so, so_list);
-               sorwakeup(head);
-               wakeup_one((caddr_t)&head->so_timeo);
-               if (head->so_proto->pr_getlock != NULL) {
+               if (so->so_head == head && (so->so_state & SS_INCOMP)) {
+                       so->so_state &= ~SS_INCOMP;
+                       so->so_state |= SS_COMP;
+                       TAILQ_REMOVE(&head->so_incomp, so, so_list);
+                       TAILQ_INSERT_TAIL(&head->so_comp, so, so_list);
+                       head->so_incqlen--;
+
+                       /*
+                        * We have to release the accept list in
+                        * case a socket callback calls sock_accept()
+                        */
+                       if (locked != 0) {
+                               so_release_accept_list(head);
+                               socket_unlock(so, 0);
+                       }
+                       postevent(head, 0, EV_RCONN);
+                       sorwakeup(head);
+                       wakeup_one((caddr_t)&head->so_timeo);
+
+                       if (locked != 0) {
+                               socket_unlock(head, 1);
+                               socket_lock(so, 0);
+               }
+               } else if (locked != 0) {
+                       so_release_accept_list(head);
                        socket_unlock(head, 1);
-                       socket_lock(so, 0);
                }
        } else {
                postevent(so, 0, EV_WCONN);
@@ -233,7 +254,6 @@ socanwrite(struct socket *so)
        return ((so->so_state & SS_ISCONNECTED) ||
               !(so->so_proto->pr_flags & PR_CONNREQUIRED) ||
               (so->so_flags1 & SOF1_PRECONNECT_DATA));
-
 }
 
 void
@@ -377,8 +397,8 @@ sonewconn_internal(struct socket *head, int connstatus)
 #endif
 
        /* inherit traffic management properties of listener */
-       so->so_traffic_mgt_flags =
-           head->so_traffic_mgt_flags & (TRAFFIC_MGT_SO_BACKGROUND);
+       so->so_flags1 |=
+           head->so_flags1 & (SOF1_TRAFFIC_MGT_SO_BACKGROUND);
        so->so_background_thread = head->so_background_thread;
        so->so_traffic_class = head->so_traffic_class;
 
@@ -418,6 +438,8 @@ sonewconn_internal(struct socket *head, int connstatus)
        atomic_add_32(&so->so_proto->pr_domain->dom_refs, 1);
 
        /* Insert in head appropriate lists */
+       so_acquire_accept_list(head, NULL);
+
        so->so_head = head;
 
        /*
@@ -439,6 +461,8 @@ sonewconn_internal(struct socket *head, int connstatus)
        }
        head->so_qlen++;
 
+       so_release_accept_list(head);
+
        /* Attach socket filters for this protocol */
        sflt_initsock(so);
 
@@ -514,6 +538,18 @@ sbwait(struct sockbuf *sb)
                /* NOTREACHED */
        }
 
+       if ((so->so_state & SS_DRAINING) || (so->so_flags & SOF_DEFUNCT)) {
+               error = EBADF;
+               if (so->so_flags & SOF_DEFUNCT) {
+                       SODEFUNCTLOG("%s[%d, %s]: defunct so 0x%llx [%d,%d] "
+                           "(%d)\n", __func__, proc_selfpid(),
+                           proc_best_name(current_proc()),
+                           (uint64_t)VM_KERNEL_ADDRPERM(so),
+                           SOCK_DOM(so), SOCK_TYPE(so), error);
+               }
+               return (error);
+       }
+
        if (so->so_proto->pr_getlock != NULL)
                mutex_held = (*so->so_proto->pr_getlock)(so, 0);
        else
@@ -544,10 +580,11 @@ sbwait(struct sockbuf *sb)
        if ((so->so_state & SS_DRAINING) || (so->so_flags & SOF_DEFUNCT)) {
                error = EBADF;
                if (so->so_flags & SOF_DEFUNCT) {
-                       SODEFUNCTLOG(("%s[%d]: defunct so 0x%llx [%d,%d] "
+                       SODEFUNCTLOG("%s[%d, %s]: defunct so 0x%llx [%d,%d] "
                            "(%d)\n", __func__, proc_selfpid(),
+                           proc_best_name(current_proc()),
                            (uint64_t)VM_KERNEL_ADDRPERM(so),
-                           SOCK_DOM(so), SOCK_TYPE(so), error));
+                           SOCK_DOM(so), SOCK_TYPE(so), error);
                }
        }
 
@@ -570,11 +607,12 @@ void
 sowakeup(struct socket *so, struct sockbuf *sb)
 {
        if (so->so_flags & SOF_DEFUNCT) {
-               SODEFUNCTLOG(("%s[%d]: defunct so 0x%llx [%d,%d] si 0x%x, "
+               SODEFUNCTLOG("%s[%d, %s]: defunct so 0x%llx [%d,%d] si 0x%x, "
                    "fl 0x%x [%s]\n", __func__, proc_selfpid(),
+                   proc_best_name(current_proc()),
                    (uint64_t)VM_KERNEL_ADDRPERM(so), SOCK_DOM(so),
                    SOCK_TYPE(so), (uint32_t)sb->sb_sel.si_flags, sb->sb_flags,
-                   (sb->sb_flags & SB_RECV) ? "rcv" : "snd"));
+                   (sb->sb_flags & SB_RECV) ? "rcv" : "snd");
        }
 
        sb->sb_flags &= ~SB_SEL;
@@ -663,7 +701,6 @@ sowakeup(struct socket *so, struct sockbuf *sb)
 int
 soreserve(struct socket *so, u_int32_t sndcc, u_int32_t rcvcc)
 {
-
        if (sbreserve(&so->so_snd, sndcc) == 0)
                goto bad;
        else
@@ -1691,6 +1728,14 @@ sbcompress(struct sockbuf *sb, struct mbuf *m, struct mbuf *n)
                                /* XXX: Probably don't need */
                                sb->sb_ctl += m->m_len;
                        }
+
+                       /* update send byte count */
+                       if (sb->sb_flags & SB_SNDBYTE_CNT) {
+                               inp_incr_sndbytes_total(sb->sb_so,
+                                   m->m_len);
+                               inp_incr_sndbytes_unsent(sb->sb_so,
+                                   m->m_len);
+                       }
                        m = m_free(m);
                        continue;
                }
@@ -1749,9 +1794,6 @@ sbflush(struct sockbuf *sb)
 {
        void *lr_saved = __builtin_return_address(0);
        struct socket *so = sb->sb_so;
-#ifdef notyet
-       lck_mtx_t *mutex_held;
-#endif
        u_int32_t i;
 
        /* so_usecount may be 0 if we get here from sofreelastref() */
@@ -1765,19 +1807,6 @@ sbflush(struct sockbuf *sb)
                    so->so_usecount, lr_saved, solockhistory_nr(so));
                /* NOTREACHED */
        }
-#ifdef notyet
-       /*
-        * XXX: This code is currently commented out, because we may get here
-        * as part of sofreelastref(), and at that time, pr_getlock() may no
-        * longer be able to return us the lock; this will be fixed in future.
-        */
-       if (so->so_proto->pr_getlock != NULL)
-               mutex_held = (*so->so_proto->pr_getlock)(so, 0);
-       else
-               mutex_held = so->so_proto->pr_domain->dom_mtx;
-
-       lck_mtx_assert(mutex_held, LCK_MTX_ASSERT_OWNED);
-#endif
 
        /*
         * Obtain lock on the socket buffer (SB_LOCK).  This is required
@@ -1839,7 +1868,7 @@ sbdrop(struct sockbuf *sb, int len)
            ((SOCK_CHECK_DOM(sb->sb_so, PF_MULTIPATH)) &&
            (SOCK_CHECK_PROTO(sb->sb_so, IPPROTO_TCP)))) &&
            (!(sb->sb_so->so_flags1 & SOF1_POST_FALLBACK_SYNC))) {
-               mptcp_preproc_sbdrop(m, (unsigned int)len);
+               mptcp_preproc_sbdrop(sb->sb_so, m, (unsigned int)len);
        }
 #endif /* MPTCP */
        KERNEL_DEBUG((DBG_FNC_SBDROP | DBG_FUNC_START), sb, len, 0, 0, 0);
@@ -1848,8 +1877,8 @@ sbdrop(struct sockbuf *sb, int len)
        ml = (struct mbuf *)0;
 
        while (len > 0) {
-               if (m == 0) {
-                       if (next == 0) {
+               if (m == NULL) {
+                       if (next == NULL) {
                                /*
                                 * temporarily replacing this panic with printf
                                 * because it occurs occasionally when closing
@@ -1881,6 +1910,9 @@ sbdrop(struct sockbuf *sb, int len)
                        m->m_len -= len;
                        m->m_data += len;
                        sb->sb_cc -= len;
+                       /* update the send byte count */
+                       if (sb->sb_flags & SB_SNDBYTE_CNT)
+                                inp_decr_sndbytes_total(sb->sb_so, len);
                        if (m->m_type != MT_DATA && m->m_type != MT_HEADER &&
                            m->m_type != MT_OOBDATA)
                                sb->sb_ctl -= len;
@@ -2060,12 +2092,12 @@ pru_connect2_notsupp(struct socket *so1, struct socket *so2)
 }
 
 int
-pru_connectx_notsupp(struct socket *so, struct sockaddr_list **src_sl,
-    struct sockaddr_list **dst_sl, struct proc *p, uint32_t ifscope,
+pru_connectx_notsupp(struct socket *so, struct sockaddr *src,
+    struct sockaddr *dst, struct proc *p, uint32_t ifscope,
     sae_associd_t aid, sae_connid_t *pcid, uint32_t flags, void *arg,
     uint32_t arglen, struct uio *uio, user_ssize_t *bytes_written)
 {
-#pragma unused(so, src_sl, dst_sl, p, ifscope, aid, pcid, flags, arg, arglen, uio, bytes_written)
+#pragma unused(so, src, dst, p, ifscope, aid, pcid, flags, arg, arglen, uio, bytes_written)
        return (EOPNOTSUPP);
 }
 
@@ -2197,7 +2229,7 @@ pru_soreceive_notsupp(struct socket *so, struct sockaddr **paddr,
 }
 
 int
-pru_soreceive_list_notsupp(struct socket *so, 
+pru_soreceive_list_notsupp(struct socket *so,
     struct recv_msg_elem *recv_msg_array, u_int uiocnt, int *flagsp)
 {
 #pragma unused(so, recv_msg_array, uiocnt, flagsp)
@@ -2426,11 +2458,13 @@ sballoc(struct sockbuf *sb, struct mbuf *m)
                total_sbmb_cnt_peak = total_sbmb_cnt;
 
        /*
-        * If data is being appended to the send socket buffer,
+        * If data is being added to the send socket buffer,
         * update the send byte count
         */
-       if (!(sb->sb_flags & SB_RECV))
-               OSAddAtomic(cnt, &total_snd_byte_count);
+       if (sb->sb_flags & SB_SNDBYTE_CNT) {
+               inp_incr_sndbytes_total(sb->sb_so, m->m_len);
+               inp_incr_sndbytes_unsent(sb->sb_so, m->m_len);
+       }
 }
 
 /* adjust counters in sb reflecting freeing of m */
@@ -2450,14 +2484,15 @@ sbfree(struct sockbuf *sb, struct mbuf *m)
        }
        OSAddAtomic(cnt, &total_sbmb_cnt);
        VERIFY(total_sbmb_cnt >= 0);
+       if (total_sbmb_cnt < total_sbmb_cnt_floor)
+               total_sbmb_cnt_floor = total_sbmb_cnt;
 
        /*
         * If data is being removed from the send socket buffer,
         * update the send byte count
         */
-       if (!(sb->sb_flags & SB_RECV)) {
-               OSAddAtomic(cnt, &total_snd_byte_count);
-       }
+       if (sb->sb_flags & SB_SNDBYTE_CNT)
+               inp_decr_sndbytes_total(sb->sb_so, m->m_len);
 }
 
 /*
@@ -2550,10 +2585,11 @@ sblock(struct sockbuf *sb, uint32_t flags)
                if (error == 0 && (so->so_flags & SOF_DEFUNCT) &&
                    !(flags & SBL_IGNDEFUNCT)) {
                        error = EBADF;
-                       SODEFUNCTLOG(("%s[%d]: defunct so 0x%llx [%d,%d] "
+                       SODEFUNCTLOG("%s[%d, %s]: defunct so 0x%llx [%d,%d] "
                            "(%d)\n", __func__, proc_selfpid(),
+                           proc_best_name(current_proc()),
                            (uint64_t)VM_KERNEL_ADDRPERM(so),
-                           SOCK_DOM(so), SOCK_TYPE(so), error));
+                           SOCK_DOM(so), SOCK_TYPE(so), error);
                }
 
                if (error != 0)
@@ -2629,7 +2665,7 @@ sbunlock(struct sockbuf *sb, boolean_t keeplocked)
 
                lck_mtx_assert(mutex_held, LCK_MTX_ASSERT_OWNED);
 
-               VERIFY(so->so_usecount != 0);
+               VERIFY(so->so_usecount > 0);
                so->so_usecount--;
                so->unlock_lr[so->next_unlock_lr] = lr_saved;
                so->next_unlock_lr = (so->next_unlock_lr + 1) % SO_LCKDBG_MAX;
@@ -2863,7 +2899,7 @@ soisthrottled(struct socket *so)
         * application, as we're missing the system wide "decision maker"
         */
        return (
-               (so->so_traffic_mgt_flags & TRAFFIC_MGT_SO_BACKGROUND));
+               (so->so_flags1 & SOF1_TRAFFIC_MGT_SO_BACKGROUND));
 }
 
 inline int
@@ -2875,7 +2911,7 @@ soisprivilegedtraffic(struct socket *so)
 inline int
 soissrcbackground(struct socket *so)
 {
-       return ((so->so_traffic_mgt_flags & TRAFFIC_MGT_SO_BACKGROUND) ||
+       return ((so->so_flags1 & SOF1_TRAFFIC_MGT_SO_BACKGROUND) ||
                IS_SO_TC_BACKGROUND(so->so_traffic_class));
 }
 
@@ -2940,8 +2976,8 @@ sysctl_io_policy_throttled SYSCTL_HANDLER_ARGS
                return (err);
 
        if (i != net_io_policy_throttled)
-               SOTHROTTLELOG(("throttle: network IO policy throttling is "
-                   "now %s\n", i ? "ON" : "OFF"));
+               SOTHROTTLELOG("throttle: network IO policy throttling is "
+                   "now %s\n", i ? "ON" : "OFF");
 
        net_io_policy_throttled = i;
 
@@ -2971,6 +3007,16 @@ SYSCTL_INT(_kern_ipc, KIPC_SOQLIMITCOMPAT, soqlimitcompat,
 SYSCTL_INT(_kern_ipc, OID_AUTO, soqlencomp, CTLFLAG_RW | CTLFLAG_LOCKED,
        &soqlencomp, 0, "Listen backlog represents only complete queue");
 
+SYSCTL_INT(_kern_ipc, OID_AUTO, sbmb_cnt, CTLFLAG_RD | CTLFLAG_LOCKED,
+       &total_sbmb_cnt, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, sbmb_cnt_peak, CTLFLAG_RD | CTLFLAG_LOCKED,
+       &total_sbmb_cnt_peak, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, sbmb_cnt_floor, CTLFLAG_RD | CTLFLAG_LOCKED,
+       &total_sbmb_cnt_floor, 0, "");
+SYSCTL_QUAD(_kern_ipc, OID_AUTO, sbmb_limreached, CTLFLAG_RD | CTLFLAG_LOCKED,
+       &sbmb_limreached, "");
+
+
 SYSCTL_NODE(_kern_ipc, OID_AUTO, io_policy, CTLFLAG_RW, 0, "network IO policy");
 
 SYSCTL_PROC(_kern_ipc_io_policy, OID_AUTO, throttled,