vcl: improve shutdown()
[vpp.git] / src / vcl / vppcom.c
index 0713a7b..d378f40 100644 (file)
@@ -471,8 +471,8 @@ vcl_session_accepted_handler (vcl_worker_t * wrk, session_accepted_msg_t * mp,
                    sizeof (ip46_address_t));
 
   vcl_session_table_add_vpp_handle (wrk, mp->handle, session->session_index);
-  session->transport.lcl_port = listen_session->transport.lcl_port;
-  session->transport.lcl_ip = listen_session->transport.lcl_ip;
+  session->transport.lcl_port = mp->lcl.port;
+  session->transport.lcl_ip = mp->lcl.ip;
   session->session_type = listen_session->session_type;
   session->is_dgram = vcl_proto_is_dgram (session->session_type);
   session->listener_index = listen_session->session_index;
@@ -807,7 +807,7 @@ vcl_session_disconnected_handler (vcl_worker_t * wrk,
 }
 
 int
-vppcom_session_shutdown (uint32_t session_handle)
+vppcom_session_shutdown (uint32_t session_handle, int how)
 {
   vcl_worker_t *wrk = vcl_worker_get_current ();
   vcl_session_t *session;
@@ -830,13 +830,20 @@ vppcom_session_shutdown (uint32_t session_handle)
       return VPPCOM_EBADFD;
     }
 
+  if (how == SHUT_RD || how == SHUT_RDWR)
+    {
+      session->flags |= VCL_SESSION_F_RD_SHUTDOWN;
+      if (how == SHUT_RD)
+       return VPPCOM_OK;
+    }
+  session->flags |= VCL_SESSION_F_WR_SHUTDOWN;
+
   if (PREDICT_TRUE (state == VCL_STATE_READY))
     {
       VDBG (1, "session %u [0x%llx]: sending shutdown...",
            session->session_index, vpp_handle);
 
       vcl_send_session_shutdown (wrk, session);
-      session->flags |= VCL_SESSION_F_SHUTDOWN;
     }
 
   return VPPCOM_OK;
@@ -1666,6 +1673,10 @@ vppcom_unformat_proto (uint8_t * proto, char *proto_str)
     *proto = VPPCOM_PROTO_DTLS;
   else if (!strcmp (proto_str, "dtls"))
     *proto = VPPCOM_PROTO_DTLS;
+  else if (!strcmp (proto_str, "SRTP"))
+    *proto = VPPCOM_PROTO_SRTP;
+  else if (!strcmp (proto_str, "srtp"))
+    *proto = VPPCOM_PROTO_SRTP;
   else
     return 1;
   return 0;
@@ -1944,6 +1955,18 @@ vppcom_session_read_internal (uint32_t session_handle, void *buf, int n,
       return vcl_session_closed_error (s);
     }
 
+  if (PREDICT_FALSE (s->flags & VCL_SESSION_F_RD_SHUTDOWN))
+    {
+      /* Vpp would ack the incoming data and enqueue it for reading.
+       * So even if SHUT_RD is set, we can still read() the data if
+       * the session is ready.
+       */
+      if (!vcl_session_read_ready (s))
+       {
+         return 0;
+       }
+    }
+
   is_nonblocking = vcl_session_has_attr (s, VCL_SESS_ATTR_NONBLOCK);
   is_ct = vcl_session_is_ct (s);
   mq = wrk->app_event_queue;
@@ -1983,6 +2006,10 @@ read_again:
     rv = app_recv_stream_raw (rx_fifo, buf, n, 0, peek);
 
   ASSERT (rv >= 0);
+
+  if (peek)
+    return rv;
+
   n_read += rv;
 
   if (svm_fifo_is_empty_cons (rx_fifo))
@@ -2144,8 +2171,12 @@ vppcom_session_write_inline (vcl_worker_t * wrk, vcl_session_t * s, void *buf,
   svm_msg_q_t *mq;
   u8 is_ct;
 
-  if (PREDICT_FALSE (!buf || n == 0))
-    return VPPCOM_EINVAL;
+  /* Accept zero length writes but just return */
+  if (PREDICT_FALSE (!n))
+    return VPPCOM_OK;
+
+  if (PREDICT_FALSE (!buf))
+    return VPPCOM_EFAULT;
 
   if (PREDICT_FALSE (s->flags & VCL_SESSION_F_IS_VEP))
     {
@@ -2154,8 +2185,7 @@ vppcom_session_write_inline (vcl_worker_t * wrk, vcl_session_t * s, void *buf,
       return VPPCOM_EBADFD;
     }
 
-  if (PREDICT_FALSE (!vcl_session_is_open (s) ||
-                    s->flags & VCL_SESSION_F_SHUTDOWN))
+  if (PREDICT_FALSE (!vcl_session_is_open (s)))
     {
       VDBG (1, "session %u [0x%llx]: is not open! state 0x%x (%s)",
            s->session_index, s->vpp_handle, s->session_state,
@@ -2163,6 +2193,14 @@ vppcom_session_write_inline (vcl_worker_t * wrk, vcl_session_t * s, void *buf,
       return vcl_session_closed_error (s);;
     }
 
+  if (PREDICT_FALSE (s->flags & VCL_SESSION_F_WR_SHUTDOWN))
+    {
+      VDBG (1, "session %u [0x%llx]: is shutdown! state 0x%x (%s)",
+           s->session_index, s->vpp_handle, s->session_state,
+           vppcom_session_state_str (s->session_state));
+      return VPPCOM_EPIPE;
+    }
+
   is_ct = vcl_session_is_ct (s);
   tx_fifo = is_ct ? s->ct_tx_fifo : s->tx_fifo;
   is_nonblocking = vcl_session_has_attr (s, VCL_SESS_ATTR_NONBLOCK);
@@ -2709,6 +2747,12 @@ vppcom_epoll_ctl (uint32_t vep_handle, int op, uint32_t session_handle,
          VDBG (0, "EPOLL_CTL_ADD: NULL pointer to epoll_event structure!");
          return VPPCOM_EINVAL;
        }
+      if (s->flags & VCL_SESSION_F_IS_VEP_SESSION)
+       {
+         VDBG (0, "EPOLL_CTL_ADD: %u already epolled!", s->session_index);
+         rv = VPPCOM_EEXIST;
+         goto done;
+       }
       if (vep_session->vep.next_sh != ~0)
        {
          vcl_session_t *next_session;
@@ -2767,7 +2811,7 @@ vppcom_epoll_ctl (uint32_t vep_handle, int op, uint32_t session_handle,
       else if (PREDICT_FALSE (!(s->flags & VCL_SESSION_F_IS_VEP_SESSION)))
        {
          VDBG (0, "sh %u EPOLL_CTL_MOD: not a vep session!", session_handle);
-         rv = VPPCOM_EINVAL;
+         rv = VPPCOM_ENOENT;
          goto done;
        }
       else if (PREDICT_FALSE (s->vep.vep_sh != vep_handle))
@@ -2778,15 +2822,24 @@ vppcom_epoll_ctl (uint32_t vep_handle, int op, uint32_t session_handle,
          goto done;
        }
 
-      /* Generate EPOLLOUT when tx_fifo/ct_tx_fifo not full */
-      if ((event->events & EPOLLOUT) &&
-         !(s->vep.ev.events & EPOLLOUT) && (vcl_session_write_ready (s) > 0))
+      /* Generate EPOLLOUT if session write ready nd event was not on */
+      if ((event->events & EPOLLOUT) && !(s->vep.ev.events & EPOLLOUT) &&
+         (vcl_session_write_ready (s) > 0))
        {
          session_event_t e = { 0 };
          e.event_type = SESSION_IO_EVT_TX;
          e.session_index = s->session_index;
          vec_add1 (wrk->unhandled_evts_vector, e);
        }
+      /* Generate EPOLLIN if session read ready and event was not on */
+      if ((event->events & EPOLLIN) && !(s->vep.ev.events & EPOLLIN) &&
+         (vcl_session_read_ready (s) > 0))
+       {
+         session_event_t e = { 0 };
+         e.event_type = SESSION_IO_EVT_RX;
+         e.session_index = s->session_index;
+         vec_add1 (wrk->unhandled_evts_vector, e);
+       }
       s->vep.et_mask = VEP_DEFAULT_ET_MASK;
       s->vep.ev = *event;
       txf = vcl_session_is_ct (s) ? s->ct_tx_fifo : s->tx_fifo;
@@ -2805,7 +2858,7 @@ vppcom_epoll_ctl (uint32_t vep_handle, int op, uint32_t session_handle,
       if (PREDICT_FALSE (!(s->flags & VCL_SESSION_F_IS_VEP_SESSION)))
        {
          VDBG (0, "EPOLL_CTL_DEL: %u not a vep session!", session_handle);
-         rv = VPPCOM_EINVAL;
+         rv = VPPCOM_ENOENT;
          goto done;
        }
       else if (PREDICT_FALSE (s->vep.vep_sh != vep_handle))
@@ -2851,9 +2904,12 @@ vppcom_epoll_ctl (uint32_t vep_handle, int op, uint32_t session_handle,
       s->vep.vep_sh = ~0;
       s->flags &= ~VCL_SESSION_F_IS_VEP_SESSION;
 
-      txf = vcl_session_is_ct (s) ? s->ct_tx_fifo : s->tx_fifo;
-      if (txf)
-       svm_fifo_del_want_deq_ntf (txf, SVM_FIFO_WANT_DEQ_NOTIF_IF_FULL);
+      if (vcl_session_is_open (s))
+       {
+         txf = vcl_session_is_ct (s) ? s->ct_tx_fifo : s->tx_fifo;
+         if (txf)
+           svm_fifo_del_want_deq_ntf (txf, SVM_FIFO_WANT_DEQ_NOTIF_IF_FULL);
+       }
 
       VDBG (1, "EPOLL_CTL_DEL: vep_idx %u, sh %u!", vep_handle,
            session_handle);
@@ -3179,7 +3235,7 @@ vppcom_session_attr (uint32_t session_handle, uint32_t op,
                     void *buffer, uint32_t * buflen)
 {
   vcl_worker_t *wrk = vcl_worker_get_current ();
-  u32 *flags = buffer, tmp_flags = 0;
+  u32 *flags = buffer;
   vppcom_endpt_t *ep = buffer;
   transport_endpt_attr_t tea;
   vcl_session_t *session;
@@ -3717,27 +3773,6 @@ vppcom_session_attr (uint32_t session_handle, uint32_t op,
            *buflen);
       break;
 
-    case VPPCOM_ATTR_SET_SHUT:
-      if (*flags == SHUT_RD || *flags == SHUT_RDWR)
-       vcl_session_set_attr (session, VCL_SESS_ATTR_SHUT_RD);
-      if (*flags == SHUT_WR || *flags == SHUT_RDWR)
-       vcl_session_set_attr (session, VCL_SESS_ATTR_SHUT_WR);
-      break;
-
-    case VPPCOM_ATTR_GET_SHUT:
-      if (vcl_session_has_attr (session, VCL_SESS_ATTR_SHUT_RD))
-       tmp_flags = 1;
-      if (vcl_session_has_attr (session, VCL_SESS_ATTR_SHUT_WR))
-       tmp_flags |= 2;
-      if (tmp_flags == 1)
-       *(int *) buffer = SHUT_RD;
-      else if (tmp_flags == 2)
-       *(int *) buffer = SHUT_WR;
-      else if (tmp_flags == 3)
-       *(int *) buffer = SHUT_RDWR;
-      *buflen = sizeof (int);
-      break;
-
     case VPPCOM_ATTR_SET_CONNECTED:
       session->flags |= VCL_SESSION_F_CONNECTED;
       break;
@@ -3866,12 +3901,9 @@ vppcom_session_sendto (uint32_t session_handle, void *buffer,
   vcl_session_t *s;
 
   s = vcl_session_get_w_handle (wrk, session_handle);
-  if (!s)
+  if (PREDICT_FALSE (!s))
     return VPPCOM_EBADFD;
 
-  if (!buffer)
-    return VPPCOM_EINVAL;
-
   if (ep)
     {
       if (!vcl_session_is_cl (s))
@@ -4128,6 +4160,9 @@ vppcom_proto_str (vppcom_proto_t proto)
     case VPPCOM_PROTO_DTLS:
       proto_str = "DTLS";
       break;
+    case VPPCOM_PROTO_SRTP:
+      proto_str = "SRTP";
+      break;
     default:
       proto_str = "UNKNOWN";
       break;