session udp: shared local endpoints
[vpp.git] / src / vcl / vppcom.c
index 39d665b..cb450d9 100644 (file)
@@ -231,7 +231,10 @@ vcl_send_session_connect (vcl_worker_t * wrk, vcl_session_t * s)
   clib_memcpy_fast (&mp->ip, &s->transport.rmt_ip, sizeof (mp->ip));
   clib_memcpy_fast (&mp->lcl_ip, &s->transport.lcl_ip, sizeof (mp->lcl_ip));
   mp->port = s->transport.rmt_port;
+  mp->lcl_port = s->transport.lcl_port;
   mp->proto = s->session_type;
+  if (s->flags & VCL_SESSION_F_CONNECTED)
+    mp->flags |= TRANSPORT_CFG_F_CONNECTED;
   app_send_ctrl_evt_to_vpp (mq, app_evt);
 }
 
@@ -442,7 +445,7 @@ vcl_session_connected_handler (vcl_worker_t * wrk,
   if (mp->retval)
     {
       VDBG (0, "ERROR: session index %u: connect failed! %U",
-           session_index, format_api_error, ntohl (mp->retval));
+           session_index, format_session_error, mp->retval);
       session->session_state = STATE_DETACHED | STATE_DISCONNECT;
       session->vpp_handle = mp->handle;
       return session_index;
@@ -562,7 +565,7 @@ vcl_session_bound_handler (vcl_worker_t * wrk, session_bound_msg_t * mp)
   if (mp->retval)
     {
       VERR ("session %u [0x%llx]: bind failed: %U", sid, mp->handle,
-           format_api_error, mp->retval);
+           format_session_error, mp->retval);
       if (session)
        {
          session->session_state = STATE_DETACHED;
@@ -612,15 +615,25 @@ vcl_session_unlisten_reply_handler (vcl_worker_t * wrk, void *data)
   vcl_session_t *s;
 
   s = vcl_session_get_w_vpp_handle (wrk, mp->handle);
-  if (!s || s->session_state != STATE_DISCONNECT)
+  if (!s)
     {
       VDBG (0, "Unlisten reply with wrong handle %llx", mp->handle);
       return;
     }
+  if (s->session_state != STATE_DISCONNECT)
+    {
+      /* Connected udp listener */
+      if (s->session_type == VPPCOM_PROTO_UDP
+         && s->session_state == STATE_CLOSED)
+       return;
+
+      VDBG (0, "Unlisten session in wrong state %llx", mp->handle);
+      return;
+    }
 
   if (mp->retval)
     VDBG (0, "ERROR: session %u [0xllx]: unlisten failed: %U",
-         s->session_index, mp->handle, format_api_error, ntohl (mp->retval));
+         s->session_index, mp->handle, format_session_error, mp->retval);
 
   if (mp->context != wrk->wrk_index)
     VDBG (0, "wrong context");
@@ -643,6 +656,7 @@ vcl_session_migrated_handler (vcl_worker_t * wrk, void *data)
     }
 
   s->vpp_thread_index = mp->vpp_thread_index;
+  s->vpp_handle = mp->new_handle;
   s->vpp_evt_q = uword_to_pointer (mp->vpp_evt_q, svm_msg_q_t *);
 
   vec_validate (wrk->vpp_event_queues, s->vpp_thread_index);
@@ -656,7 +670,8 @@ vcl_session_migrated_handler (vcl_worker_t * wrk, void *data)
     app_send_io_evt_to_vpp (s->vpp_evt_q, s->tx_fifo->master_session_index,
                            SESSION_IO_EVT_TX, SVM_Q_WAIT);
 
-  VDBG (0, "Migrated 0x%x to thread %u", mp->handle, s->vpp_thread_index);
+  VDBG (0, "Migrated 0x%lx to thread %u 0x%lx", mp->handle,
+       s->vpp_thread_index, mp->new_handle);
 }
 
 static vcl_session_t *
@@ -679,6 +694,7 @@ vcl_session_accepted (vcl_worker_t * wrk, session_accepted_msg_t * msg)
     }
 
   clib_fifo_add2 (session->accept_evts_fifo, vcl_msg);
+  vcl_msg->flags = 0;
   vcl_msg->accepted_msg = *msg;
   /* Session handle points to listener until fully accepted by app */
   vcl_session_table_add_vpp_handle (wrk, msg->handle, session->session_index);
@@ -1529,10 +1545,6 @@ vppcom_unformat_proto (uint8_t * proto, char *proto_str)
     *proto = VPPCOM_PROTO_UDPC;
   else if (!strcmp (proto_str, "udpc"))
     *proto = VPPCOM_PROTO_UDPC;
-  else if (!strcmp (proto_str, "SCTP"))
-    *proto = VPPCOM_PROTO_SCTP;
-  else if (!strcmp (proto_str, "sctp"))
-    *proto = VPPCOM_PROTO_SCTP;
   else if (!strcmp (proto_str, "TLS"))
     *proto = VPPCOM_PROTO_TLS;
   else if (!strcmp (proto_str, "tls"))
@@ -1655,25 +1667,6 @@ handle:
   return vcl_session_handle (client_session);
 }
 
-static void
-vcl_ip_copy_from_ep (ip46_address_t * ip, vppcom_endpt_t * ep)
-{
-  if (ep->is_ip4)
-    clib_memcpy_fast (&ip->ip4, ep->ip, sizeof (ip4_address_t));
-  else
-    clib_memcpy_fast (&ip->ip6, ep->ip, sizeof (ip6_address_t));
-}
-
-void
-vcl_ip_copy_to_ep (ip46_address_t * ip, vppcom_endpt_t * ep, u8 is_ip4)
-{
-  ep->is_ip4 = is_ip4;
-  if (is_ip4)
-    clib_memcpy_fast (ep->ip, &ip->ip4, sizeof (ip4_address_t));
-  else
-    clib_memcpy_fast (ep->ip, &ip->ip6, sizeof (ip6_address_t));
-}
-
 int
 vppcom_session_connect (uint32_t session_handle, vppcom_endpt_t * server_ep)
 {
@@ -1708,13 +1701,24 @@ vppcom_session_connect (uint32_t session_handle, vppcom_endpt_t * server_ep)
       return VPPCOM_OK;
     }
 
+  /* Attempt to connect a connectionless listener */
+  if (PREDICT_FALSE (session->session_state & STATE_LISTEN))
+    {
+      if (session->session_type != VPPCOM_PROTO_UDP)
+       return VPPCOM_EINVAL;
+      vcl_send_session_unlisten (wrk, session);
+      session->session_state = STATE_CLOSED;
+    }
+
   session->transport.is_ip4 = server_ep->is_ip4;
   vcl_ip_copy_from_ep (&session->transport.rmt_ip, server_ep);
   session->transport.rmt_port = server_ep->port;
   session->parent_handle = VCL_INVALID_SESSION_HANDLE;
+  session->flags |= VCL_SESSION_F_CONNECTED;
 
-  VDBG (0, "session handle %u: connecting to server %s %U "
+  VDBG (0, "session handle %u (%s): connecting to peer %s %U "
        "port %d proto %s", session_handle,
+       vppcom_session_state_str (session->session_state),
        session->transport.is_ip4 ? "IPv4" : "IPv6",
        format_ip46_address,
        &session->transport.rmt_ip, session->transport.is_ip4 ?
@@ -3196,7 +3200,8 @@ vppcom_session_attr (uint32_t session_handle, uint32_t op,
 
          /* VPP-TBD */
          *(size_t *) buffer = (session->sndbuf_size ? session->sndbuf_size :
-                               session->tx_fifo ? session->tx_fifo->nitems :
+                               session->tx_fifo ?
+                               svm_fifo_size (session->tx_fifo) :
                                vcm->cfg.tx_fifo_size);
          *buflen = sizeof (u32);
 
@@ -3227,7 +3232,8 @@ vppcom_session_attr (uint32_t session_handle, uint32_t op,
 
          /* VPP-TBD */
          *(size_t *) buffer = (session->rcvbuf_size ? session->rcvbuf_size :
-                               session->rx_fifo ? session->rx_fifo->nitems :
+                               session->rx_fifo ?
+                               svm_fifo_size (session->rx_fifo) :
                                vcm->cfg.rx_fifo_size);
          *buflen = sizeof (u32);
 
@@ -3569,20 +3575,8 @@ vppcom_session_recvfrom (uint32_t session_handle, void *buffer,
                         uint32_t buflen, int flags, vppcom_endpt_t * ep)
 {
   vcl_worker_t *wrk = vcl_worker_get_current ();
+  vcl_session_t *session;
   int rv = VPPCOM_OK;
-  vcl_session_t *session = 0;
-
-  if (ep)
-    {
-      session = vcl_session_get_w_handle (wrk, session_handle);
-      if (PREDICT_FALSE (!session))
-       {
-         VDBG (0, "sh 0x%llx is closed!", session_handle);
-         return VPPCOM_EBADFD;
-       }
-      ep->is_ip4 = session->transport.is_ip4;
-      ep->port = session->transport.rmt_port;
-    }
 
   if (flags == 0)
     rv = vppcom_session_read (session_handle, buffer, buflen);
@@ -3594,14 +3588,17 @@ vppcom_session_recvfrom (uint32_t session_handle, void *buffer,
       return VPPCOM_EAFNOSUPPORT;
     }
 
-  if (ep)
+  if (ep && rv > 0)
     {
+      session = vcl_session_get_w_handle (wrk, session_handle);
       if (session->transport.is_ip4)
        clib_memcpy_fast (ep->ip, &session->transport.rmt_ip.ip4,
                          sizeof (ip4_address_t));
       else
        clib_memcpy_fast (ep->ip, &session->transport.rmt_ip.ip6,
                          sizeof (ip6_address_t));
+      ep->is_ip4 = session->transport.is_ip4;
+      ep->port = session->transport.rmt_port;
     }
 
   return rv;
@@ -3616,8 +3613,28 @@ vppcom_session_sendto (uint32_t session_handle, void *buffer,
 
   if (ep)
     {
-      // TBD
-      return VPPCOM_EINVAL;
+      vcl_worker_t *wrk = vcl_worker_get_current ();
+      vcl_session_t *s;
+
+      s = vcl_session_get_w_handle (wrk, session_handle);
+      if (!s)
+       return VPPCOM_EBADFD;
+
+      if (s->session_type != VPPCOM_PROTO_UDP
+         || (s->flags & VCL_SESSION_F_CONNECTED))
+       return VPPCOM_EINVAL;
+
+      /* Session not connected/bound in vpp. Create it by 'connecting' it */
+      if (PREDICT_FALSE (s->session_state == STATE_CLOSED))
+       {
+         vcl_send_session_connect (wrk, s);
+       }
+      else
+       {
+         s->transport.is_ip4 = ep->is_ip4;
+         s->transport.rmt_port = ep->port;
+         vcl_ip_copy_from_ep (&s->transport.rmt_ip, ep);
+       }
     }
 
   if (flags)