+ * Ask transport to open connection to remote transport endpoint.
+ *
+ * Stores handle for matching request with reply since the call can be
+ * asynchronous. For instance, for TCP the 3-way handshake must complete
+ * before reply comes. Session is only created once connection is established.
+ *
+ * @param app_index Index of the application requesting the connect
+ * @param st Session type requested.
+ * @param tep Remote transport endpoint
+ * @param opaque Opaque data (typically, api_context) the application expects
+ * on open completion.
+ */
+int
+session_open (u32 app_index, session_endpoint_t * rmt, u32 opaque)
+{
+ transport_service_type_t tst = tp_vfts[rmt->transport_proto].service_type;
+ return session_open_srv_fns[tst] (app_index, rmt, opaque);
+}
+
+int
+session_listen_vc (stream_session_t * s, session_endpoint_t * sep)
+{
+ transport_connection_t *tc;
+ u32 tci;
+
+ /* Transport bind/listen */
+ tci = tp_vfts[sep->transport_proto].bind (s->session_index,
+ session_endpoint_to_transport
+ (sep));
+
+ if (tci == (u32) ~ 0)
+ return -1;
+
+ /* Attach transport to session */
+ s->connection_index = tci;
+ tc = tp_vfts[sep->transport_proto].get_listener (tci);
+
+ /* Weird but handle it ... */
+ if (tc == 0)
+ return -1;
+
+ /* Add to the main lookup table */
+ session_lookup_add_connection (tc, s->session_index);
+ return 0;
+}
+
+int
+session_listen_cl (stream_session_t * s, session_endpoint_t * sep)
+{
+ transport_connection_t *tc;
+ application_t *server;
+ segment_manager_t *sm;
+ u32 tci;
+
+ /* Transport bind/listen */
+ tci = tp_vfts[sep->transport_proto].bind (s->session_index,
+ session_endpoint_to_transport
+ (sep));
+
+ if (tci == (u32) ~ 0)
+ return -1;
+
+ /* Attach transport to session */
+ s->connection_index = tci;
+ tc = tp_vfts[sep->transport_proto].get_listener (tci);
+
+ /* Weird but handle it ... */
+ if (tc == 0)
+ return -1;
+
+ server = application_get (s->app_index);
+ sm = application_get_listen_segment_manager (server, s);
+ if (session_alloc_fifos (sm, s))
+ return -1;
+
+ /* Add to the main lookup table */
+ session_lookup_add_connection (tc, s->session_index);
+ return 0;
+}
+
+int
+session_listen_app (stream_session_t * s, session_endpoint_t * sep)
+{
+ session_endpoint_extended_t esep;
+ clib_memcpy (&esep, sep, sizeof (*sep));
+ esep.app_index = s->app_index;
+
+ return tp_vfts[sep->transport_proto].bind (s->session_index,
+ (transport_endpoint_t *) & esep);
+}
+
+typedef int (*session_listen_service_fn) (stream_session_t *,
+ session_endpoint_t *);
+
+/* *INDENT-OFF* */
+static session_listen_service_fn
+session_listen_srv_fns[TRANSPORT_N_SERVICES] = {
+ session_listen_vc,
+ session_listen_cl,
+ session_listen_app,
+};
+/* *INDENT-ON* */
+
+/**
+ * Ask transport to listen on local transport endpoint.
+ *
+ * @param s Session for which listen will be called. Note that unlike
+ * established sessions, listen sessions are not associated to a
+ * thread.
+ * @param tep Local endpoint to be listened on.
+ */
+int
+stream_session_listen (stream_session_t * s, session_endpoint_t * sep)
+{
+ transport_service_type_t tst = tp_vfts[sep->transport_proto].service_type;
+ return session_listen_srv_fns[tst] (s, sep);
+}
+
+/**
+ * Ask transport to stop listening on local transport endpoint.
+ *
+ * @param s Session to stop listening on. It must be in state LISTENING.
+ */
+int
+stream_session_stop_listen (stream_session_t * s)
+{
+ transport_proto_t tp = session_get_transport_proto (s);
+ transport_connection_t *tc;
+ if (s->session_state != SESSION_STATE_LISTENING)
+ {
+ clib_warning ("not a listening session");
+ return -1;
+ }
+
+ tc = tp_vfts[tp].get_listener (s->connection_index);
+ if (!tc)
+ {
+ clib_warning ("no transport");
+ return VNET_API_ERROR_ADDRESS_NOT_IN_USE;
+ }
+
+ session_lookup_del_connection (tc);
+ tp_vfts[tp].unbind (s->connection_index);
+ return 0;
+}
+
+/**
+ * Initialize session disconnect.
+ *
+ * Request is always sent to session node to ensure that all outstanding
+ * requests are served before transport is notified.