summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeith Burns (alagalah) <alagalah@gmail.com>2018-03-06 15:55:22 -0800
committerDave Wallace <dwallacelf@gmail.com>2018-03-09 19:40:39 +0000
commit0d2b0d5497b61afb5c964373c7bed974d78762a0 (patch)
treef72eb2722844201871caddea65bb02c2895a70a1
parent51c52c0adc9bf79ca6508ee1327d3b972e80b5c6 (diff)
VCL API for external callback for listener/connect event
Change-Id: Ic59355683b581945d10a2df97d9b2deae87a998e Signed-off-by: Keith Burns (alagalah) <alagalah@gmail.com>
-rw-r--r--src/vcl.am12
-rw-r--r--src/vcl/test_vcl_listener_client.c58
-rw-r--r--src/vcl/test_vcl_listener_server.c102
-rw-r--r--src/vcl/vcl_event.c5
-rw-r--r--src/vcl/vcl_event.h5
-rw-r--r--src/vcl/vppcom.c123
-rw-r--r--src/vcl/vppcom.h41
7 files changed, 323 insertions, 23 deletions
diff --git a/src/vcl.am b/src/vcl.am
index 9f1325ecaa2..89e18416b1e 100644
--- a/src/vcl.am
+++ b/src/vcl.am
@@ -49,11 +49,21 @@ noinst_PROGRAMS += \
vcl_test_server \
vcl_test_client \
sock_test_server \
- sock_test_client
+ sock_test_client \
+ test_vcl_listener_server \
+ test_vcl_listener_client
+
+
+test_vcl_listener_server_SOURCES = vcl/test_vcl_listener_server.c
+test_vcl_listener_server_LDADD = libvppcom.la
+
+test_vcl_listener_client_SOURCES = vcl/test_vcl_listener_client.c
+test_vcl_listener_client_LDADD = libvppcom.la
vcl_test_server_SOURCES = vcl/vcl_test_server.c
vcl_test_server_LDADD = libvppcom.la
+
vcl_test_client_SOURCES = vcl/vcl_test_client.c
# Link libvcl_ldpreload.la instead of vppcom.la
diff --git a/src/vcl/test_vcl_listener_client.c b/src/vcl/test_vcl_listener_client.c
new file mode 100644
index 00000000000..dcf93cdef8b
--- /dev/null
+++ b/src/vcl/test_vcl_listener_client.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <vcl/vppcom.h>
+
+int main(){
+ int client_session;
+ char buffer[1024];
+ struct sockaddr_in server_address;
+ vppcom_endpt_t endpt;
+ int rv;
+
+ rv = vppcom_app_create ("test_vcl_listener_client");
+ if (rv) return rv;
+
+ client_session = vppcom_session_create(VPPCOM_PROTO_TCP, 0);
+
+ memset(&server_address, 0, sizeof(server_address));
+ server_address.sin_family = AF_INET;
+ server_address.sin_port = htons(9995);
+ server_address.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+ endpt.is_ip4 = (server_address.sin_family == AF_INET);
+ endpt.ip = (uint8_t *) & server_address.sin_addr;
+ endpt.port = (uint16_t) server_address.sin_port;
+
+
+ vppcom_session_connect(client_session, &endpt);
+
+ /*---- Read the message from the server into the buffer ----*/
+ vppcom_session_read (client_session, buffer, 1024);
+
+ /*---- Print the received message ----*/
+ printf("Data received: %s",buffer);
+
+ printf("Press ENTER key to Continue\n");
+ getchar();
+
+ return 0;
+}
diff --git a/src/vcl/test_vcl_listener_server.c b/src/vcl/test_vcl_listener_server.c
new file mode 100644
index 00000000000..bebef250f22
--- /dev/null
+++ b/src/vcl/test_vcl_listener_server.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+
+#include <vcl/vppcom.h>
+#include <unistd.h>
+
+char MESSAGE[] = "Hello, World!\n";
+
+static const int PORT = 9995;
+
+void
+listener_cb (uint32_t new_session_index, vppcom_endpt_t *ep, void *stuff)
+{
+
+ vppcom_session_write (new_session_index, &MESSAGE, sizeof (MESSAGE));
+ printf ("\n Heard from port: %d\n", ep->port);
+}
+
+
+typedef struct vppcomm_listener_main_
+{
+ int new_fd;
+
+ struct event *event;
+
+} vppcomm_listener_main_t;
+
+vppcomm_listener_main_t _vlm_main;
+vppcomm_listener_main_t *vlm = &_vlm_main;
+
+
+int
+main (int argc, char **argv)
+{
+
+ int rv;
+ struct sockaddr_in sin;
+ uint32_t listen_fd;
+ vppcom_endpt_t endpt;
+
+ //Address stuff
+ memset (&sin, 0, sizeof (sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons (PORT);
+ //sin.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+ endpt.is_ip4 = (sin.sin_family == AF_INET);
+ endpt.ip = (uint8_t *) & sin.sin_addr;
+ endpt.port = (uint16_t) sin.sin_port;
+
+ //VCL stuff
+ rv = vppcom_app_create ("test_vcl_listener_server");
+ if (rv) return rv;
+
+ listen_fd = vppcom_session_create (VPPCOM_PROTO_TCP,
+ 0 /* is_nonblocking */ );
+
+ rv = vppcom_session_bind (listen_fd, &endpt);
+
+ //Make a listener and dispatch
+ rv = vppcom_session_register_listener (listen_fd, listener_cb, 0,
+ 0, 0, &MESSAGE);
+
+ if (rv)
+ {
+ fprintf (stderr, "Could not create a listener!\n");
+ return 1;
+ }
+
+ while (1)
+ {
+ sleep (3);
+ }
+
+ printf ("done\n");
+ return 0;
+}
+
+
diff --git a/src/vcl/vcl_event.c b/src/vcl/vcl_event.c
index 64f55b9fb0b..f6e20de2769 100644
--- a/src/vcl/vcl_event.c
+++ b/src/vcl/vcl_event.c
@@ -96,7 +96,7 @@ vce_get_event_handler (vce_event_thread_t *evt, vce_event_key_t *evk)
vce_event_handler_reg_t *
vce_register_handler (vce_event_thread_t *evt, vce_event_key_t *evk,
- vce_event_callback_t cb)
+ vce_event_callback_t cb, void *cb_args)
{
vce_event_handler_reg_t *handler;
vce_event_handler_reg_t *old_handler = 0;
@@ -135,6 +135,7 @@ vce_register_handler (vce_event_thread_t *evt, vce_event_key_t *evk,
handler->replaced_handler_idx = (p) ? p[0] : ~0;
handler->ev_idx = ~0; //This will be set by the event thread if event happens
handler->evk = evk->as_u64;
+ handler->handler_fn_args = cb_args;
hash_set (evt->handlers_index_by_event_key, evk->as_u64, handler_index);
@@ -275,4 +276,4 @@ vce_start_event_thread (vce_event_thread_t *evt, u8 max_events)
return pthread_create (&(evt->thread), NULL /* attr */ ,
vce_event_thread_fn, evt);
-} \ No newline at end of file
+}
diff --git a/src/vcl/vcl_event.h b/src/vcl/vcl_event.h
index a2e247e8d7c..f2a85a0f1d2 100644
--- a/src/vcl/vcl_event.h
+++ b/src/vcl/vcl_event.h
@@ -53,6 +53,7 @@ typedef struct vce_event_handler_reg_
u32 ev_idx;
u64 evk; //Event key
u32 replaced_handler_idx;
+ void *handler_fn_args;
} vce_event_handler_reg_t;
typedef struct vce_event_thread_
@@ -121,12 +122,14 @@ vce_event_handler_reg_t * vce_get_event_handler (vce_event_thread_t *evt,
* @param evk - vce_event_key_t current an eventID from enum in consumer and
* sessionID
* @param cb - vce_event_callback_t function to handle event
+ * @param cb_args - args that the callback needs passed back to it.
* @return vce_handler_reg_t - the function that needs event notification
* needs to block on a condvar mutex to reduce spin. That is in here.
*/
vce_event_handler_reg_t * vce_register_handler (vce_event_thread_t *evt,
vce_event_key_t *evk,
- vce_event_callback_t cb);
+ vce_event_callback_t cb,
+ void *cb_args);
/**
* @brief vce_unregister_handler
diff --git a/src/vcl/vppcom.c b/src/vcl/vppcom.c
index c0b09e833d7..58de9aeea22 100644
--- a/src/vcl/vppcom.c
+++ b/src/vcl/vppcom.c
@@ -203,6 +203,13 @@ typedef struct vce_event_connect_request_
u32 accepted_session_index;
} vce_event_connect_request_t;
+typedef struct vppcom_session_listener
+{
+ vppcom_session_listener_cb user_cb;
+ vppcom_session_listener_errcb user_errcb;
+ void *user_cb_data;
+} vppcom_session_listener_t;
+
typedef struct vppcom_main_t_
{
u8 init;
@@ -436,10 +443,69 @@ write_elog (void)
}
+static inline void
+vppcom_send_accept_session_reply (u64 handle, u32 context, int retval)
+{
+ vl_api_accept_session_reply_t *rmp;
+
+ rmp = vl_msg_api_alloc (sizeof (*rmp));
+ memset (rmp, 0, sizeof (*rmp));
+ rmp->_vl_msg_id = ntohs (VL_API_ACCEPT_SESSION_REPLY);
+ rmp->retval = htonl (retval);
+ rmp->context = context;
+ rmp->handle = handle;
+ vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp);
+}
+
/*
* VPPCOM Event Functions
*/
+void
+vce_registered_listener_connect_handler_fn (void *arg)
+{
+ vce_event_handler_reg_t *reg = (vce_event_handler_reg_t *) arg;
+ vce_event_connect_request_t *ecr;
+ vce_event_t *ev;
+ vppcom_endpt_t ep;
+
+ session_t *new_session;
+ int rv;
+
+ vppcom_session_listener_t *session_listener =
+ (vppcom_session_listener_t *) reg->handler_fn_args;
+
+ ev = vce_get_event_from_index (&vcm->event_thread, reg->ev_idx);
+
+ ecr = (vce_event_connect_request_t *) ev->data;
+ VCL_LOCK_AND_GET_SESSION (ecr->accepted_session_index, &new_session);
+
+
+ ep.is_ip4 = new_session->peer_addr.is_ip4;
+ ep.port = new_session->peer_port;
+ if (new_session->peer_addr.is_ip4)
+ clib_memcpy (&ep.ip, &new_session->peer_addr.ip46.ip4,
+ sizeof (ip4_address_t));
+ else
+ clib_memcpy (&ep.ip, &new_session->peer_addr.ip46.ip6,
+ sizeof (ip6_address_t));
+
+ vppcom_send_accept_session_reply (new_session->vpp_handle,
+ new_session->client_context,
+ 0 /* retval OK */ );
+ clib_spinlock_unlock (&vcm->sessions_lockp);
+
+ (session_listener->user_cb) (ecr->accepted_session_index, &ep,
+ session_listener->user_cb_data);
+
+ /*TODO - Unregister check in close for this listener */
+
+ return;
+
+done:
+ ASSERT (0); // If we can't get a lock or accepted session fails, lets blow up.
+}
+
/**
* * @brief vce_connect_request_handler_fn
* - used for listener sessions
@@ -1250,20 +1316,6 @@ format_ip46_address (u8 * s, va_list * args)
format (s, "%U", format_ip6_address, &ip46->ip6);
}
-static inline void
-vppcom_send_accept_session_reply (u64 handle, u32 context, int retval)
-{
- vl_api_accept_session_reply_t *rmp;
-
- rmp = vl_msg_api_alloc (sizeof (*rmp));
- memset (rmp, 0, sizeof (*rmp));
- rmp->_vl_msg_id = ntohs (VL_API_ACCEPT_SESSION_REPLY);
- rmp->retval = htonl (retval);
- rmp->context = context;
- rmp->handle = handle;
- vl_msg_api_send_shmem (vcm->vl_input_queue, (u8 *) & rmp);
-}
-
static void
vl_api_accept_session_t_handler (vl_api_accept_session_t * mp)
{
@@ -2682,6 +2734,39 @@ done:
}
int
+vppcom_session_register_listener (uint32_t session_index,
+ vppcom_session_listener_cb cb,
+ vppcom_session_listener_errcb
+ errcb, uint8_t flags, int q_len, void *ptr)
+{
+ int rv = VPPCOM_OK;
+ vce_event_key_t evk;
+ vppcom_session_listener_t *listener_args;
+
+ rv = vppcom_session_listen (session_index, q_len);
+ if (rv)
+ {
+ goto done;
+ }
+
+
+ /* Register handler for connect_request event on listen_session_index */
+ listener_args = clib_mem_alloc (sizeof (vppcom_session_listener_t));
+ listener_args->user_cb = cb;
+ listener_args->user_cb_data = ptr;
+ listener_args->user_errcb = errcb;
+
+ evk.session_index = session_index;
+ evk.eid = VCL_EVENT_CONNECT_REQ_ACCEPTED;
+ (void) vce_register_handler (&vcm->event_thread, &evk,
+ vce_registered_listener_connect_handler_fn,
+ listener_args);
+
+done:
+ return rv;
+}
+
+int
validate_args_session_accept_ (session_t * listen_session)
{
u32 listen_session_index = listen_session - vcm->sessions;
@@ -2752,10 +2837,8 @@ vppcom_session_accept (uint32_t listen_session_index, vppcom_endpt_t * ep,
evk.session_index = listen_session_index;
evk.eid = VCL_EVENT_CONNECT_REQ_ACCEPTED;
reg = vce_register_handler (&vcm->event_thread, &evk,
- vce_connect_request_handler_fn);
-
+ vce_connect_request_handler_fn, 0);
ev = vce_get_event_from_index (&vcm->event_thread, reg->ev_idx);
-
pthread_mutex_lock (&reg->handler_lock);
while (!ev)
{
@@ -3477,7 +3560,8 @@ vppcom_select (unsigned long n_bits, unsigned long *read_map,
reg = vce_get_event_handler (&vcm->event_thread, &evk);
if (!reg)
reg = vce_register_handler (&vcm->event_thread, &evk,
- vce_poll_wait_connect_request_handler_fn);
+ vce_poll_wait_connect_request_handler_fn,
+ 0 /* No callback args */);
rv = vppcom_session_read_ready (session, session_index);
if (rv > 0)
{
@@ -3796,7 +3880,8 @@ vppcom_epoll_ctl (uint32_t vep_idx, int op, uint32_t session_index,
evk.eid = VCL_EVENT_CONNECT_REQ_ACCEPTED;
vep_session->poll_reg =
vce_register_handler (&vcm->event_thread, &evk,
- vce_poll_wait_connect_request_handler_fn);
+ vce_poll_wait_connect_request_handler_fn,
+ 0 /* No callback args */ );
}
if (VPPCOM_DEBUG > 1)
clib_warning ("VCL<%d>: EPOLL_CTL_ADD: vep_idx %u, "
diff --git a/src/vcl/vppcom.h b/src/vcl/vppcom.h
index 9d09f060b8b..34a69b2c2ec 100644
--- a/src/vcl/vppcom.h
+++ b/src/vcl/vppcom.h
@@ -210,6 +210,46 @@ vppcom_retval_str (int retval)
return st;
}
+/**
+ * User registered callback for when connection arrives on listener created
+ * with vppcom_session_register_listener()
+ * @param uint32_t - newly accepted session_index
+ * @param vppcom_endpt_t* - ip/port information of remote
+ * @param void* - user passed arg to pass back
+ */
+typedef void (*vppcom_session_listener_cb) (uint32_t, vppcom_endpt_t *,
+ void *);
+
+/**
+ * User registered ERROR callback for any errors associated with
+ * handling vppcom_session_register_listener() and connections
+ * @param void* - user passed arg to pass back
+ */
+typedef void (*vppcom_session_listener_errcb) (void *);
+
+/**
+ * @brief vppcom_session_register_listener accepts a bound session_index, and
+ * listens for connections.
+ *
+ * On successful connection, calls registered callback (cb) with new
+ * session_index.
+ *
+ * On error, calls registered error callback (errcb).
+ *
+ * @param session_index - bound session_index to create listener on
+ * @param cb - on new accepted session callback
+ * @param errcb - on failure callback
+ * @param flags - placeholder for future use. Must be ZERO
+ * @param q_len - max listener connection backlog
+ * @param ptr - user data
+ * @return
+ */
+extern int vppcom_session_register_listener (uint32_t session_index,
+ vppcom_session_listener_cb cb,
+ vppcom_session_listener_errcb
+ errcb, uint8_t flags, int q_len,
+ void *ptr);
+
/* TBD: make these constructor/destructor function */
extern int vppcom_app_create (char *app_name);
extern void vppcom_app_destroy (void);
@@ -219,6 +259,7 @@ extern int vppcom_session_close (uint32_t session_index);
extern int vppcom_session_bind (uint32_t session_index, vppcom_endpt_t * ep);
extern int vppcom_session_listen (uint32_t session_index, uint32_t q_len);
+
extern int vppcom_session_accept (uint32_t session_index,
vppcom_endpt_t * client_ep, uint32_t flags);