vcl: wait for sendto to connect if needed
[vpp.git] / src / vcl / vppcom.c
index dd50df1..229a251 100644 (file)
@@ -784,9 +784,22 @@ vcl_session_cleanup_handler (vcl_worker_t * wrk, void *data)
       /* Transport was cleaned up before we confirmed close. Probably the
        * app is still waiting for some data that cannot be delivered.
        * Confirm close to make sure everything is cleaned up */
-      if (session->session_state == VCL_STATE_VPP_CLOSING)
-       vcl_session_cleanup (wrk, session, vcl_session_handle (session),
-                            1 /* do_disconnect */ );
+      if (session->session_state == VCL_STATE_VPP_CLOSING
+         || session->session_state == VCL_STATE_DISCONNECT)
+       {
+         vcl_session_cleanup (wrk, session, vcl_session_handle (session),
+                              1 /* do_disconnect */ );
+         /* Move to undetermined state to ensure that the session is not
+          * removed before both vpp and the app cleanup.
+          * - If the app closes first, the session is moved to CLOSED state
+          *   and the session cleanup notification from vpp removes the
+          *   session.
+          * - If vpp cleans up the session first, the session is moved to
+          *   DETACHED state lower and subsequently the close from the app
+          *   frees the session
+          */
+         session->session_state = VCL_STATE_UPDATED;
+       }
       return;
     }
 
@@ -3670,21 +3683,28 @@ vppcom_session_sendto (uint32_t session_handle, void *buffer,
 
   if (ep)
     {
-      if (s->session_type != VPPCOM_PROTO_UDP
-         || (s->flags & VCL_SESSION_F_CONNECTED))
+      if (!vcl_session_is_cl (s))
        return VPPCOM_EINVAL;
 
       /* Session not connected/bound in vpp. Create it by 'connecting' it */
       if (PREDICT_FALSE (s->session_state == VCL_STATE_CLOSED))
        {
+         u32 session_index = s->session_index;
+         f64 timeout = vcm->cfg.session_timeout;
+         int rv;
+
          vcl_send_session_connect (wrk, s);
+         rv = vppcom_wait_for_session_state_change (session_index,
+                                                    VCL_STATE_READY,
+                                                    timeout);
+         if (rv < 0)
+           return rv;
+         s = vcl_session_get (wrk, session_index);
        }
-      else
-       {
-         s->transport.is_ip4 = ep->is_ip4;
-         s->transport.rmt_port = ep->port;
-         vcl_ip_copy_from_ep (&s->transport.rmt_ip, ep);
-       }
+
+      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)