Blame SOURCES/bz2031865-add-async-connect.patch

170f08
commit de5ab3029c796e51d246bab9a83c66bbb5602e86
170f08
Author: Chrissie Caulfield <ccaulfie@redhat.com>
170f08
Date:   Wed Jan 5 10:53:09 2022 +0000
170f08
170f08
    ipcc: Add an async connect API (#450)
170f08
170f08
diff --git a/include/qb/qbipcc.h b/include/qb/qbipcc.h
170f08
index de96c72..867ba04 100644
170f08
--- a/include/qb/qbipcc.h
170f08
+++ b/include/qb/qbipcc.h
170f08
@@ -80,6 +80,36 @@ typedef struct qb_ipcc_connection qb_ipcc_connection_t;
170f08
 qb_ipcc_connection_t*
170f08
 qb_ipcc_connect(const char *name, size_t max_msg_size);
170f08
 
170f08
+/**
170f08
+ * Asynchronously connect to an IPC service
170f08
+ * @param name name of the service.
170f08
+ * @param max_msg_size biggest msg size.
170f08
+ * @param connect_fd return FD to continue connection with
170f08
+ * @return NULL (error: see errno) or a connection object.
170f08
+ *
170f08
+ * qb_ipcc_connect_async() returns a connection FD which
170f08
+ * should be used added to the application's mainloop - when it is
170f08
+ * active, qb_ipcc_connect_continue() should be called for the
170f08
+ * connection to be finalised.
170f08
+ * NOTE: This is NOT the same FD that is used for normal applicaion
170f08
+ * polling. qb_ipcc_fd_get() must still be called once the connection
170f08
+ * is established.
170f08
+ */
170f08
+qb_ipcc_connection_t *
170f08
+qb_ipcc_connect_async(const char *name, size_t max_msg_size, int *connect_fd);
170f08
+
170f08
+/**
170f08
+ * Finish up an asynchonous IPC connection
170f08
+ * @param c connection handle as returned from qb_ipcc_connect_async()
170f08
+ * @return 0 or -errno.
170f08
+ *
170f08
+ * Finishes up a connection that was initiated by qb_ipcc_connect_async(),
170f08
+ * this should only be called when the fd returned by qb_ipcc_connect_async()
170f08
+ * becomes active, usually as a callback in the application's main loop.
170f08
+ */
170f08
+int
170f08
+qb_ipcc_connect_continue(struct qb_ipcc_connection * c);
170f08
+
170f08
 /**
170f08
  * Test kernel dgram socket buffers to verify the largest size up
170f08
  * to the max_msg_size value a single msg can be. Rounds down to the
170f08
diff --git a/lib/ipc_int.h b/lib/ipc_int.h
170f08
index 03c5dab..87f1de1 100644
170f08
--- a/lib/ipc_int.h
170f08
+++ b/lib/ipc_int.h
170f08
@@ -106,7 +106,8 @@ struct qb_ipcc_connection {
170f08
 };
170f08
 
170f08
 int32_t qb_ipcc_us_setup_connect(struct qb_ipcc_connection *c,
170f08
-				   struct qb_ipc_connection_response *r);
170f08
+				 struct qb_ipc_connection_response *r);
170f08
+int qb_ipcc_setup_connect_continue(struct qb_ipcc_connection *c, struct qb_ipc_connection_response *response);
170f08
 ssize_t qb_ipc_us_send(struct qb_ipc_one_way *one_way, const void *msg, size_t len);
170f08
 ssize_t qb_ipc_us_recv(struct qb_ipc_one_way *one_way, void *msg, size_t len, int32_t timeout);
170f08
 int32_t qb_ipc_us_ready(struct qb_ipc_one_way *ow_data, struct qb_ipc_one_way *ow_conn,
170f08
diff --git a/lib/ipc_setup.c b/lib/ipc_setup.c
170f08
index c144a5e..0ef9bb6 100644
170f08
--- a/lib/ipc_setup.c
170f08
+++ b/lib/ipc_setup.c
170f08
@@ -446,9 +446,7 @@ qb_ipcc_us_setup_connect(struct qb_ipcc_connection *c,
170f08
 {
170f08
 	int32_t res;
170f08
 	struct qb_ipc_connection_request request;
170f08
-	struct ipc_auth_data *data;
170f08
 #ifdef QB_LINUX
170f08
-	int off = 0;
170f08
 	int on = 1;
170f08
 #endif
170f08
 
170f08
@@ -471,13 +469,24 @@ qb_ipcc_us_setup_connect(struct qb_ipcc_connection *c,
170f08
 		return res;
170f08
 	}
170f08
 
170f08
+	/* ... To be continued ... (when the FD is active) */
170f08
+	return 0;
170f08
+}
170f08
+
170f08
+/* Called from ipcc_connect_continue() when async connect socket is active */
170f08
+int qb_ipcc_setup_connect_continue(struct qb_ipcc_connection *c, struct qb_ipc_connection_response *r)
170f08
+{
170f08
+	struct ipc_auth_data *data;
170f08
+	int32_t res;
170f08
+#ifdef QB_LINUX
170f08
+	int off = 0;
170f08
+#endif
170f08
 	data = init_ipc_auth_data(c->setup.u.us.sock, sizeof(struct qb_ipc_connection_response));
170f08
 	if (data == NULL) {
170f08
 		qb_ipcc_us_sock_close(c->setup.u.us.sock);
170f08
 		return -ENOMEM;
170f08
 	}
170f08
 
170f08
-	qb_ipc_us_ready(&c->setup, NULL, -1, POLLIN);
170f08
 	res = qb_ipc_us_recv_msghdr(data);
170f08
 
170f08
 #ifdef QB_LINUX
170f08
@@ -498,6 +507,7 @@ qb_ipcc_us_setup_connect(struct qb_ipcc_connection *c,
170f08
 	c->server_pid = data->ugp.pid;
170f08
 
170f08
 	destroy_ipc_auth_data(data);
170f08
+
170f08
 	return r->hdr.error;
170f08
 }
170f08
 
170f08
diff --git a/lib/ipcc.c b/lib/ipcc.c
170f08
index a6cf409..c744ea1 100644
170f08
--- a/lib/ipcc.c
170f08
+++ b/lib/ipcc.c
170f08
@@ -45,6 +45,70 @@ qb_ipcc_connect(const char *name, size_t max_msg_size)
170f08
 	if (res < 0) {
170f08
 		goto disconnect_and_cleanup;
170f08
 	}
170f08
+	qb_ipc_us_ready(&c->setup, NULL, -1, POLLIN);
170f08
+	res = qb_ipcc_connect_continue(c);
170f08
+	if (res != 0) {
170f08
+		/* qb_ipcc_connect_continue() has cleaned up for us */
170f08
+		errno = -res;
170f08
+		return NULL;
170f08
+	}
170f08
+
170f08
+	return c;
170f08
+
170f08
+disconnect_and_cleanup:
170f08
+	if (c->setup.u.us.sock >= 0) {
170f08
+		qb_ipcc_us_sock_close(c->setup.u.us.sock);
170f08
+	}
170f08
+	free(c->receive_buf);
170f08
+	free(c);
170f08
+	errno = -res;
170f08
+	return NULL;
170f08
+}
170f08
+
170f08
+qb_ipcc_connection_t *
170f08
+qb_ipcc_connect_async(const char *name, size_t max_msg_size, int *connect_fd)
170f08
+{
170f08
+	int32_t res;
170f08
+	qb_ipcc_connection_t *c = NULL;
170f08
+	struct qb_ipc_connection_response response;
170f08
+
170f08
+	c = calloc(1, sizeof(struct qb_ipcc_connection));
170f08
+	if (c == NULL) {
170f08
+		return NULL;
170f08
+	}
170f08
+
170f08
+	c->setup.max_msg_size = QB_MAX(max_msg_size,
170f08
+				       sizeof(struct qb_ipc_connection_response));
170f08
+	(void)strlcpy(c->name, name, NAME_MAX);
170f08
+	res = qb_ipcc_us_setup_connect(c, &response);
170f08
+	if (res < 0) {
170f08
+		goto disconnect_and_cleanup;
170f08
+	}
170f08
+
170f08
+	*connect_fd = c->setup.u.us.sock;
170f08
+	return c;
170f08
+
170f08
+disconnect_and_cleanup:
170f08
+	if (c->setup.u.us.sock >= 0) {
170f08
+		qb_ipcc_us_sock_close(c->setup.u.us.sock);
170f08
+	}
170f08
+	free(c->receive_buf);
170f08
+	free(c);
170f08
+	errno = -res;
170f08
+	return NULL;
170f08
+}
170f08
+
170f08
+int qb_ipcc_connect_continue(struct qb_ipcc_connection * c)
170f08
+{
170f08
+	struct qb_ipc_connection_response response;
170f08
+	int32_t res;
170f08
+
170f08
+	/* Finish up the authentication part */
170f08
+	res = qb_ipcc_setup_connect_continue(c, &response);
170f08
+	if (res != 0) {
170f08
+		goto disconnect_and_cleanup;
170f08
+	}
170f08
+
170f08
 	c->response.type = response.connection_type;
170f08
 	c->request.type = response.connection_type;
170f08
 	c->event.type = response.connection_type;
170f08
@@ -79,7 +143,7 @@ qb_ipcc_connect(const char *name, size_t max_msg_size)
170f08
 		goto disconnect_and_cleanup;
170f08
 	}
170f08
 	c->is_connected = QB_TRUE;
170f08
-	return c;
170f08
+	return 0;
170f08
 
170f08
 disconnect_and_cleanup:
170f08
 	if (c->setup.u.us.sock >= 0) {
170f08
@@ -88,7 +152,8 @@ disconnect_and_cleanup:
170f08
 	free(c->receive_buf);
170f08
 	free(c);
170f08
 	errno = -res;
170f08
-	return NULL;
170f08
+	return -res;
170f08
+
170f08
 }
170f08
 
170f08
 static int32_t
170f08
diff --git a/tests/check_ipc.c b/tests/check_ipc.c
170f08
index e8f81f3..6090354 100644
170f08
--- a/tests/check_ipc.c
170f08
+++ b/tests/check_ipc.c
170f08
@@ -1007,6 +1007,62 @@ repeat_send:
170f08
 	return res;
170f08
 }
170f08
 
170f08
+
170f08
+static int32_t
170f08
+process_async_connect(int32_t fd, int32_t revents, void *data)
170f08
+{
170f08
+	qb_loop_t *cl = (qb_loop_t *)data;
170f08
+	int res;
170f08
+
170f08
+	res = qb_ipcc_connect_continue(conn);
170f08
+	ck_assert_int_eq(res, 0);
170f08
+	qb_loop_stop(cl);
170f08
+	return 0;
170f08
+}
170f08
+static void test_ipc_connect_async(void)
170f08
+{
170f08
+	struct qb_ipc_request_header req_header;
170f08
+	struct qb_ipc_response_header res_header;
170f08
+	int32_t res;
170f08
+	pid_t pid;
170f08
+	uint32_t max_size = MAX_MSG_SIZE;
170f08
+	int connect_fd;
170f08
+	struct iovec iov[1];
170f08
+	static qb_loop_t *cl;
170f08
+
170f08
+	pid = run_function_in_new_process("server", run_ipc_server, NULL);
170f08
+	ck_assert(pid != -1);
170f08
+
170f08
+	conn = qb_ipcc_connect_async(ipc_name, max_size, &connect_fd);
170f08
+	ck_assert(conn != NULL);
170f08
+
170f08
+	cl = qb_loop_create();
170f08
+	res = qb_loop_poll_add(cl, QB_LOOP_MED,
170f08
+			 connect_fd, POLLIN,
170f08
+			 cl, process_async_connect);
170f08
+	ck_assert_int_eq(res, 0);
170f08
+	qb_loop_run(cl);
170f08
+
170f08
+	/* Send some data */
170f08
+	req_header.id = IPC_MSG_REQ_TX_RX;
170f08
+	req_header.size = sizeof(struct qb_ipc_request_header);
170f08
+
170f08
+	iov[0].iov_len = req_header.size;
170f08
+	iov[0].iov_base = &req_header;
170f08
+
170f08
+	res = qb_ipcc_sendv_recv(conn, iov, 1,
170f08
+				 &res_header,
170f08
+				 sizeof(struct qb_ipc_response_header), 5000);
170f08
+
170f08
+	ck_assert_int_ge(res, 0);
170f08
+
170f08
+	request_server_exit();
170f08
+	verify_graceful_stop(pid);
170f08
+
170f08
+
170f08
+	qb_ipcc_disconnect(conn);
170f08
+}
170f08
+
170f08
 static void
170f08
 test_ipc_txrx_timeout(void)
170f08
 {
170f08
@@ -1226,6 +1282,7 @@ START_TEST(test_ipc_txrx_shm_timeout)
170f08
 }
170f08
 END_TEST
170f08
 
170f08
+
170f08
 START_TEST(test_ipc_txrx_us_timeout)
170f08
 {
170f08
 	qb_enter();
170f08
@@ -1236,6 +1293,25 @@ START_TEST(test_ipc_txrx_us_timeout)
170f08
 }
170f08
 END_TEST
170f08
 
170f08
+START_TEST(test_ipc_shm_connect_async)
170f08
+{
170f08
+	qb_enter();
170f08
+	ipc_type = QB_IPC_SHM;
170f08
+	set_ipc_name(__func__);
170f08
+	test_ipc_connect_async();
170f08
+	qb_leave();
170f08
+}
170f08
+END_TEST
170f08
+
170f08
+START_TEST(test_ipc_us_connect_async)
170f08
+{
170f08
+	qb_enter();
170f08
+	ipc_type = QB_IPC_SHM;
170f08
+	set_ipc_name(__func__);
170f08
+	test_ipc_connect_async();
170f08
+	qb_leave();
170f08
+}
170f08
+END_TEST
170f08
 
170f08
 START_TEST(test_ipc_txrx_shm_getauth)
170f08
 {
170f08
@@ -2277,6 +2353,8 @@ make_shm_suite(void)
170f08
 	TCase *tc;
170f08
 	Suite *s = suite_create("shm");
170f08
 
170f08
+	add_tcase(s, tc, test_ipc_shm_connect_async, 7);
170f08
+
170f08
 	add_tcase(s, tc, test_ipc_txrx_shm_getauth, 7);
170f08
 	add_tcase(s, tc, test_ipc_txrx_shm_timeout, 28);
170f08
 	add_tcase(s, tc, test_ipc_server_fail_shm, 7);
170f08
@@ -2308,6 +2386,8 @@ make_soc_suite(void)
170f08
 	Suite *s = suite_create("socket");
170f08
 	TCase *tc;
170f08
 
170f08
+	add_tcase(s, tc, test_ipc_us_connect_async, 7);
170f08
+
170f08
 	add_tcase(s, tc, test_ipc_txrx_us_getauth, 7);
170f08
 	add_tcase(s, tc, test_ipc_txrx_us_timeout, 28);
170f08
 /* Commented out for the moment as space in /dev/shm on the CI machines