Просмотр исходного кода

qnetd: Migrate main loop to pr-poll-loop

Signed-off-by: Jan Friesse <jfriesse@redhat.com>
Jan Friesse 5 лет назад
Родитель
Сommit
6f55a0649f

+ 4 - 3
qdevices/Makefile.am

@@ -1,4 +1,4 @@
-# Copyright (c) 2012-2019 Red Hat, Inc.
+# Copyright (c) 2012-2020 Red Hat, Inc.
 #
 # Authors: Jan Friesse (jfriesse@redhat.com)
 #          Fabio M. Di Nitto (fdinitto@redhat.com)
@@ -70,8 +70,9 @@ corosync_qnetd_SOURCES	= corosync-qnetd.c \
                           unix-socket-client.c unix-socket-client.h \
                           unix-socket-client-list.c unix-socket-client-list.h \
                           unix-socket.c unix-socket.h qnetd-ipc-cmd.c qnetd-ipc-cmd.h \
-                          qnetd-poll-array-user-data.h qnet-config.h dynar-getopt-lex.c \
-                          dynar-getopt-lex.h qnetd-advanced-settings.c qnetd-advanced-settings.h
+                          qnet-config.h dynar-getopt-lex.c \
+                          dynar-getopt-lex.h qnetd-advanced-settings.c qnetd-advanced-settings.h \
+                          pr-poll-loop.c pr-poll-loop.h
 
 corosync_qnetd_tool_SOURCES = corosync-qnetd-tool.c unix-socket.c unix-socket.h dynar.c dynar.h \
                               dynar-str.c dynar-str.h utils.c utils.h

+ 48 - 216
qdevices/corosync-qnetd.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2019 Red Hat, Inc.
+ * Copyright (c) 2015-2020 Red Hat, Inc.
  *
  * All rights reserved.
  *
@@ -53,7 +53,6 @@
 #include "qnetd-ipc.h"
 #include "qnetd-client-net.h"
 #include "qnetd-client-msg-received.h"
-#include "qnetd-poll-array-user-data.h"
 #include "utils.h"
 #include "msg.h"
 
@@ -90,230 +89,43 @@ qnetd_warn_nss(void)
 	log_nss(LOG_WARNING, "NSS warning");
 }
 
-static PRPollDesc *
-qnetd_pr_poll_array_create(struct qnetd_instance *instance)
+static int
+server_socket_poll_loop_read_cb(PRFileDesc *prfd, void *user_data1, void *user_data2)
 {
-	struct pr_poll_array *poll_array;
-	const struct qnetd_client_list *client_list;
-	struct qnetd_client *client;
-	PRPollDesc *poll_desc;
-	struct qnetd_poll_array_user_data *user_data;
-	const struct unix_socket_client_list *ipc_client_list;
-	struct unix_socket_client *ipc_client;
-
-	poll_array = &instance->poll_array;
-	client_list = &instance->clients;
-	ipc_client_list = &instance->local_ipc.clients;
-
-	pr_poll_array_clean(poll_array);
-
-	if (pr_poll_array_add(poll_array, &poll_desc, (void **)&user_data) < 0) {
-		return (NULL);
-	}
-
-	poll_desc->fd = instance->server.socket;
-	poll_desc->in_flags = PR_POLL_READ;
-
-	user_data->type = QNETD_POLL_ARRAY_USER_DATA_TYPE_SOCKET;
-
-	if (qnetd_ipc_is_closed(instance)) {
-		log(LOG_DEBUG, "Listening socket is closed");
-
-		return (NULL);
-	}
-
-	if (pr_poll_array_add(poll_array, &poll_desc, (void **)&user_data) < 0) {
-		return (NULL);
-	}
-
-	poll_desc->fd = instance->ipc_socket_poll_fd;
-	poll_desc->in_flags = PR_POLL_READ;
-	user_data->type = QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET;
-
-	TAILQ_FOREACH(client, client_list, entries) {
-		if (pr_poll_array_add(poll_array, &poll_desc, (void **)&user_data) < 0) {
-			return (NULL);
-		}
-		poll_desc->fd = client->socket;
-		poll_desc->in_flags = PR_POLL_READ;
-
-		if (!send_buffer_list_empty(&client->send_buffer_list)) {
-			poll_desc->in_flags |= PR_POLL_WRITE;
-		}
-
-		user_data->type = QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT;
-		user_data->client = client;
-	}
-
-	TAILQ_FOREACH(ipc_client, ipc_client_list, entries) {
-		if (!ipc_client->reading_line && !ipc_client->writing_buffer) {
-			continue;
-		}
-
-		if (pr_poll_array_add(poll_array, &poll_desc, (void **)&user_data) < 0) {
-			return (NULL);
-		}
+	struct qnetd_instance *instance = (struct qnetd_instance *)user_data1;
 
-		poll_desc->fd = ((struct qnetd_ipc_user_data *)ipc_client->user_data)->nspr_poll_fd;
-		if (ipc_client->reading_line) {
-			poll_desc->in_flags |= PR_POLL_READ;
-		}
+	qnetd_client_net_accept(instance);
 
-		if (ipc_client->writing_buffer) {
-			poll_desc->in_flags |= PR_POLL_WRITE;
-		}
+	return (0);
+}
 
-		user_data->type = QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT;
-		user_data->ipc_client = ipc_client;
-	}
+static int
+server_socket_poll_loop_write_cb(PRFileDesc *prfd, void *user_data1, void *user_data2)
+{
 
-	pr_poll_array_gc(poll_array);
+	/*
+	 * Poll write on listen socket -> fatal error
+	 */
+	log(LOG_CRIT, "POLL_WRITE on listening socket");
 
-	return (poll_array->array);
+	return (-1);
 }
 
 static int
-qnetd_poll(struct qnetd_instance *instance)
+server_socket_poll_loop_err_cb(PRFileDesc *prfd, short revents, void *user_data1, void *user_data2)
 {
-	struct qnetd_client *client;
-	PRPollDesc *pfds;
-	PRInt32 poll_res;
-	ssize_t i;
-	int client_disconnect;
-	struct qnetd_poll_array_user_data *user_data;
-	struct unix_socket_client *ipc_client;
-
-	client = NULL;
-	client_disconnect = 0;
-
-	pfds = qnetd_pr_poll_array_create(instance);
-	if (pfds == NULL) {
-		return (-1);
-	}
-
-	if ((poll_res = PR_Poll(pfds, pr_poll_array_size(&instance->poll_array),
-	    timer_list_time_to_expire(&instance->main_timer_list))) >= 0) {
-		timer_list_expire(&instance->main_timer_list);
 
+	if (revents != POLLNVAL) {
 		/*
-		 * Walk thru pfds array and process events
+		 * Poll ERR on listening socket is fatal error.
+		 * POLL_NVAL is used as a signal to quit poll loop.
 		 */
-		for (i = 0; i < pr_poll_array_size(&instance->poll_array); i++) {
-			user_data = pr_poll_array_get_user_data(&instance->poll_array, i);
-
-			client = NULL;
-			ipc_client = NULL;
-			client_disconnect = 0;
-
-			switch (user_data->type) {
-			case QNETD_POLL_ARRAY_USER_DATA_TYPE_SOCKET:
-				break;
-			case QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT:
-				client = user_data->client;
-				client_disconnect = client->schedule_disconnect;
-				break;
-			case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET:
-				break;
-			case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT:
-				ipc_client = user_data->ipc_client;
-				client_disconnect = ipc_client->schedule_disconnect;
-			}
-
-			if (!client_disconnect && poll_res > 0 &&
-			    pfds[i].out_flags & PR_POLL_READ) {
-				switch (user_data->type) {
-				case QNETD_POLL_ARRAY_USER_DATA_TYPE_SOCKET:
-					qnetd_client_net_accept(instance);
-					break;
-				case QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT:
-					if (qnetd_client_net_read(instance, client) == -1) {
-						client_disconnect = 1;
-					}
-					break;
-				case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET:
-					qnetd_ipc_accept(instance, &ipc_client);
-					break;
-				case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT:
-					qnetd_ipc_io_read(instance, ipc_client);
-					break;
-				}
-			}
-
-			if (!client_disconnect && poll_res > 0 &&
-			    pfds[i].out_flags & PR_POLL_WRITE) {
-				switch (user_data->type) {
-				case QNETD_POLL_ARRAY_USER_DATA_TYPE_SOCKET:
-					/*
-					 * Poll write on listen socket -> fatal error
-					 */
-					log(LOG_CRIT, "POLL_WRITE on listening socket");
-
-					return (-1);
-					break;
-				case QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT:
-					if (qnetd_client_net_write(instance, client) == -1) {
-						client_disconnect = 1;
-					}
-					break;
-				case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET:
-					log(LOG_CRIT, "POLL_WRITE on listening IPC socket");
-					return (-1);
-					break;
-				case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT:
-					qnetd_ipc_io_write(instance, ipc_client);
-					break;
-				}
-			}
-
-			if (!client_disconnect && poll_res > 0 &&
-			    (pfds[i].out_flags & (PR_POLL_ERR|PR_POLL_NVAL|PR_POLL_HUP|PR_POLL_EXCEPT)) &&
-			    !(pfds[i].out_flags & (PR_POLL_READ|PR_POLL_WRITE))) {
-				switch (user_data->type) {
-				case QNETD_POLL_ARRAY_USER_DATA_TYPE_SOCKET:
-				case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET:
-					if (pfds[i].out_flags != PR_POLL_NVAL) {
-						/*
-						 * Poll ERR on listening socket is fatal error.
-						 * POLL_NVAL is used as a signal to quit poll loop.
-						 */
-						 log(LOG_CRIT, "POLL_ERR (%u) on listening "
-						    "socket", pfds[i].out_flags);
-					} else {
-						log(LOG_DEBUG, "Listening socket is closed");
-					}
-
-					return (-1);
-					break;
-				case QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT:
-					log(LOG_DEBUG, "POLL_ERR (%u) on client socket. "
-					    "Disconnecting.", pfds[i].out_flags);
-
-					client_disconnect = 1;
-					break;
-				case QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT:
-					log(LOG_DEBUG, "POLL_ERR (%u) on ipc client socket."
-					    " Disconnecting.", pfds[i].out_flags);
-
-					client_disconnect = 1;
-					break;
-				}
-			}
-
-			/*
-			 * If client is scheduled for disconnect, disconnect it
-			 */
-			if (user_data->type == QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT &&
-			    client_disconnect) {
-				qnetd_instance_client_disconnect(instance, client, 0);
-			} else if (user_data->type == QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT &&
-			    (client_disconnect || ipc_client->schedule_disconnect)) {
-				qnetd_ipc_client_disconnect(instance, ipc_client);
-			}
-		}
+		log(LOG_CRIT, "POLL_ERR (%u) on listening socket", revents);
+	} else {
+		log(LOG_DEBUG, "Listening socket is closed");
 	}
 
-
-	return (0);
+	return (-1);
 }
 
 static void
@@ -530,6 +342,7 @@ main(int argc, char * const argv[])
 	int lock_file;
 	int another_instance_running;
 	int log_target;
+	int poll_res;
 
 	if (qnetd_advanced_settings_init(&advanced_settings) != 0) {
 		errx(1, "Can't alloc memory for advanced settings");
@@ -557,7 +370,7 @@ main(int argc, char * const argv[])
 	    advanced_settings.nss_db_dir : NULL)) != 0) {
 		log_err(LOG_ERR, "Can't open NSS DB directory");
 
-		exit (1);
+		return (1);
 	}
 
 	/*
@@ -575,7 +388,7 @@ main(int argc, char * const argv[])
 			log_err(LOG_ERR, "Can't acquire lock");
 		}
 
-		exit(1);
+		return (1);
 	}
 
 	log(LOG_DEBUG, "Initializing nss");
@@ -591,7 +404,7 @@ main(int argc, char * const argv[])
 	if (qnetd_instance_init(&instance, tls_supported, client_cert_required,
 	    max_clients, &advanced_settings) == -1) {
 		log(LOG_ERR, "Can't initialize qnetd");
-		exit(1);
+		return (1);
 	}
 	instance.host_addr = host_addr;
 	instance.host_port = host_port;
@@ -621,12 +434,23 @@ main(int argc, char * const argv[])
 		qnetd_err_nss();
 	}
 
+	if (pr_poll_loop_add_prfd(&instance.main_poll_loop, instance.server.socket, POLLIN,
+	    NULL,
+	    server_socket_poll_loop_read_cb,
+	    server_socket_poll_loop_write_cb,
+	    server_socket_poll_loop_err_cb,
+	    &instance, NULL) != 0) {
+		log(LOG_ERR, "Can't add server socket to main poll loop");
+
+		return (1);
+	}
+
 	global_instance = &instance;
 	signal_handlers_register();
 
 	log(LOG_DEBUG, "Registering algorithms");
 	if (qnetd_algorithm_register_all() != 0) {
-		exit(1);
+		return (1);
 	}
 
 	log(LOG_DEBUG, "QNetd ready to provide service");
@@ -638,14 +462,21 @@ main(int argc, char * const argv[])
 	/*
 	 * MAIN LOOP
 	 */
-	while (qnetd_poll(&instance) == 0) {
+	while ((poll_res = pr_poll_loop_exec(&instance.main_poll_loop)) == 0) {
+	}
+
+	if (poll_res == -2) {
+		log(LOG_CRIT, "pr_poll_loop_exec returned -2 - internal error");
+		return (1);
 	}
 
 	/*
 	 * Cleanup
 	 */
+	log(LOG_DEBUG, "Destroying qnetd ipc");
 	qnetd_ipc_destroy(&instance);
 
+	log(LOG_DEBUG, "Closing server socket");
 	if (PR_Close(instance.server.socket) != PR_SUCCESS) {
 		qnetd_warn_nss();
 	}
@@ -669,6 +500,7 @@ main(int argc, char * const argv[])
 		qnetd_warn_nss();
 	}
 
+	log(LOG_DEBUG, "Closing log");
 	log_close();
 
 	return (0);

+ 86 - 2
qdevices/qnetd-client-net.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2019 Red Hat, Inc.
+ * Copyright (c) 2015-2020 Red Hat, Inc.
  *
  * All rights reserved.
  *
@@ -56,6 +56,78 @@ qnetd_client_net_write_finished(struct qnetd_instance *instance, struct qnetd_cl
 	return (0);
 }
 
+static int
+qnetd_client_net_socket_poll_loop_set_events_cb(PRFileDesc *prfd, short *events,
+    void *user_data1, void *user_data2)
+{
+	struct qnetd_instance *instance = (struct qnetd_instance *)user_data1;
+	struct qnetd_client *client = (struct qnetd_client *)user_data2;
+
+	if (client->schedule_disconnect) {
+		qnetd_instance_client_disconnect(instance, client, 0);
+
+		if (pr_poll_loop_del_prfd(&instance->main_poll_loop, prfd) == -1) {
+			log(LOG_CRIT, "pr_poll_loop_del_prfd for client socket failed");
+
+			return (-2);
+		}
+
+		return (-1);
+	}
+
+	if (!send_buffer_list_empty(&client->send_buffer_list)) {
+		*events |= POLLOUT;
+	}
+
+	return (0);
+}
+
+
+static int
+qnetd_client_net_socket_poll_loop_read_cb(PRFileDesc *prfd, void *user_data1, void *user_data2)
+{
+	struct qnetd_instance *instance = (struct qnetd_instance *)user_data1;
+	struct qnetd_client *client = (struct qnetd_client *)user_data2;
+
+	if (!client->schedule_disconnect) {
+		if (qnetd_client_net_read(instance, client) == -1) {
+			client->schedule_disconnect = 1;
+		}
+	}
+
+	return (0);
+}
+
+static int
+qnetd_client_net_socket_poll_loop_write_cb(PRFileDesc *prfd, void *user_data1, void *user_data2)
+{
+	struct qnetd_instance *instance = (struct qnetd_instance *)user_data1;
+	struct qnetd_client *client = (struct qnetd_client *)user_data2;
+
+	if (!client->schedule_disconnect) {
+		if (qnetd_client_net_write(instance, client) == -1) {
+			client->schedule_disconnect = 1;
+		}
+	}
+
+	return (0);
+}
+
+static int
+qnetd_client_net_socket_poll_loop_err_cb(PRFileDesc *prfd, short revents, void *user_data1, void *user_data2)
+{
+	struct qnetd_client *client = (struct qnetd_client *)user_data2;
+
+	if (!client->schedule_disconnect) {
+		log(LOG_DEBUG, "POLL_ERR (%u) on client socket. "
+		    "Disconnecting.", revents);
+
+		client->schedule_disconnect = 1;
+	}
+
+	return (0);
+}
+
 int
 qnetd_client_net_write(struct qnetd_instance *instance, struct qnetd_client *client)
 {
@@ -231,13 +303,25 @@ qnetd_client_net_accept(struct qnetd_instance *instance)
 	    client_addr_str,
 	    instance->advanced_settings->max_client_receive_size,
 	    instance->advanced_settings->max_client_send_buffers,
-	    instance->advanced_settings->max_client_send_size, &instance->main_timer_list);
+	    instance->advanced_settings->max_client_send_size,
+	    pr_poll_loop_get_timer_list(&instance->main_poll_loop));
 	if (client == NULL) {
 		log(LOG_ERR, "Can't add client to list");
 		res_err = -2;
 		goto exit_close;
 	}
 
+	if (pr_poll_loop_add_prfd(&instance->main_poll_loop, client_socket, POLLIN,
+	    qnetd_client_net_socket_poll_loop_set_events_cb,
+	    qnetd_client_net_socket_poll_loop_read_cb,
+	    qnetd_client_net_socket_poll_loop_write_cb,
+	    qnetd_client_net_socket_poll_loop_err_cb,
+	    instance, client) == -1) {
+		log_err(LOG_CRIT, "Can't add client to main poll loop");
+		res_err = -2;
+		goto exit_close;
+	}
+
 	return (0);
 
 exit_close:

+ 3 - 3
qdevices/qnetd-dpd-timer.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016 Red Hat, Inc.
+ * Copyright (c) 2015-2020 Red Hat, Inc.
  *
  * All rights reserved.
  *
@@ -75,7 +75,7 @@ qnetd_dpd_timer_init(struct qnetd_instance *instance)
 		return (0);
 	}
 
-	instance->dpd_timer = timer_list_add(&instance->main_timer_list,
+	instance->dpd_timer = timer_list_add(pr_poll_loop_get_timer_list(&instance->main_poll_loop),
 	    instance->advanced_settings->dpd_interval,
 	    qnetd_dpd_timer_cb, (void *)instance, NULL);
 	if (instance->dpd_timer == NULL) {
@@ -92,7 +92,7 @@ qnetd_dpd_timer_destroy(struct qnetd_instance *instance)
 {
 
 	if (instance->dpd_timer != NULL) {
-		timer_list_delete(&instance->main_timer_list, instance->dpd_timer);
+		timer_list_delete(pr_poll_loop_get_timer_list(&instance->main_poll_loop), instance->dpd_timer);
 		instance->dpd_timer = NULL;
 	}
 }

+ 4 - 6
qdevices/qnetd-instance.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2019 Red Hat, Inc.
+ * Copyright (c) 2015-2020 Red Hat, Inc.
  *
  * All rights reserved.
  *
@@ -40,7 +40,6 @@
 #include "qnetd-algorithm.h"
 #include "qnetd-log-debug.h"
 #include "qnetd-dpd-timer.h"
-#include "qnetd-poll-array-user-data.h"
 #include "qnetd-client-algo-timer.h"
 
 int
@@ -53,7 +52,6 @@ qnetd_instance_init(struct qnetd_instance *instance,
 
 	instance->advanced_settings = advanced_settings;
 
-	pr_poll_array_init(&instance->poll_array, sizeof(struct qnetd_poll_array_user_data));
 	qnetd_client_list_init(&instance->clients);
 	qnetd_cluster_list_init(&instance->clusters);
 
@@ -62,7 +60,7 @@ qnetd_instance_init(struct qnetd_instance *instance,
 
 	instance->max_clients = max_clients;
 
-	timer_list_init(&instance->main_timer_list);
+	pr_poll_loop_init(&instance->main_poll_loop);
 
 	if (qnetd_dpd_timer_init(instance) != 0) {
 		return (0);
@@ -88,10 +86,10 @@ qnetd_instance_destroy(struct qnetd_instance *instance)
 		client = client_next;
 	}
 
-	pr_poll_array_destroy(&instance->poll_array);
 	qnetd_cluster_list_free(&instance->clusters);
 	qnetd_client_list_free(&instance->clients);
-	timer_list_free(&instance->main_timer_list);
+
+	pr_poll_loop_destroy(&instance->main_poll_loop);
 
 	return (0);
 }

+ 4 - 5
qdevices/qnetd-instance.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016 Red Hat, Inc.
+ * Copyright (c) 2015-2020 Red Hat, Inc.
  *
  * All rights reserved.
  *
@@ -45,9 +45,10 @@
 #include "qnetd-cluster-list.h"
 #include "pr-poll-array.h"
 #include "qnet-config.h"
-#include "timer-list.h"
 #include "unix-socket-ipc.h"
 #include "qnetd-advanced-settings.h"
+#include "pr-poll-loop.h"
+#include "timer-list.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -62,16 +63,14 @@ struct qnetd_instance {
 	size_t max_clients;
 	struct qnetd_client_list clients;
 	struct qnetd_cluster_list clusters;
-	struct pr_poll_array poll_array;
 	enum tlv_tls_supported tls_supported;
 	int tls_client_cert_required;
 	const char *host_addr;
 	uint16_t host_port;
-	struct timer_list main_timer_list;
 	struct timer_list_entry *dpd_timer;		/* Dead peer detection timer */
 	struct unix_socket_ipc local_ipc;
-	PRFileDesc *ipc_socket_poll_fd;
 	const struct qnetd_advanced_settings *advanced_settings;
+	struct pr_poll_loop main_poll_loop;
 };
 
 extern int		qnetd_instance_init(struct qnetd_instance *instance,

+ 153 - 20
qdevices/qnetd-ipc.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2019 Red Hat, Inc.
+ * Copyright (c) 2015-2020 Red Hat, Inc.
  *
  * All rights reserved.
  *
@@ -45,6 +45,144 @@
  */
 #include <private/pprio.h>
 
+/*
+ * Callbacks
+ */
+
+/*
+ * IPC server socket
+ */
+static int
+ipc_socket_poll_loop_set_events_cb(int fd, short *events, void *user_data1, void *user_data2)
+{
+	struct qnetd_instance *instance = (struct qnetd_instance *)user_data1;
+
+	if (qnetd_ipc_is_closed(instance)) {
+		log(LOG_DEBUG, "Listening socket is closed");
+
+		return (-2);
+	}
+
+	return (0);
+}
+
+static int
+ipc_socket_poll_loop_read_cb(int fd, void *user_data1, void *user_data2)
+{
+	struct qnetd_instance *instance = (struct qnetd_instance *)user_data1;
+	struct unix_socket_client *ipc_client;
+
+	qnetd_ipc_accept(instance, &ipc_client);
+
+	return (0);
+}
+
+static int
+ipc_socket_poll_loop_write_cb(int fd, void *user_data1, void *user_data2)
+{
+
+	log(LOG_CRIT, "POLL_WRITE on listening IPC socket");
+
+	return (-1);
+}
+
+static int
+ipc_socket_poll_loop_err_cb(int fd, short revents, void *user_data1, void *user_data2)
+{
+
+	if (revents != POLLNVAL) {
+		/*
+		 * Poll ERR on listening socket is fatal error.
+		 * POLL_NVAL is used as a signal to quit poll loop.
+		 */
+		log(LOG_CRIT, "POLL_ERR (%u) on listening socket", revents);
+	} else {
+		log(LOG_DEBUG, "Listening socket is closed");
+	}
+
+	return (-1);
+}
+
+/*
+ * IPC client sockets
+ */
+static int
+ipc_client_socket_poll_loop_set_events_cb(int fd, short *events, void *user_data1, void *user_data2)
+{
+	struct qnetd_instance *instance = (struct qnetd_instance *)user_data1;
+	struct unix_socket_client *ipc_client = (struct unix_socket_client *)user_data2;
+
+	if (ipc_client->schedule_disconnect) {
+		qnetd_ipc_client_disconnect(instance, ipc_client);
+
+		if (pr_poll_loop_del_fd(&instance->main_poll_loop, fd) == -1) {
+			log(LOG_CRIT, "pr_poll_loop_del_fd for ipc client socket failed");
+
+			return (-2);
+		}
+
+		return (-1);
+	}
+
+	if (!ipc_client->reading_line && !ipc_client->writing_buffer) {
+		return (-1);
+	}
+
+	if (ipc_client->reading_line) {
+		*events |= POLLIN;
+	}
+
+	if (ipc_client->writing_buffer) {
+		*events |= POLLOUT;
+	}
+
+	return (0);
+}
+
+static int
+ipc_client_socket_poll_loop_read_cb(int fd, void *user_data1, void *user_data2)
+{
+	struct qnetd_instance *instance = (struct qnetd_instance *)user_data1;
+	struct unix_socket_client *ipc_client = (struct unix_socket_client *)user_data2;
+
+	if (!ipc_client->schedule_disconnect) {
+		qnetd_ipc_io_read(instance, ipc_client);
+	}
+
+	return (0);
+}
+
+static int
+ipc_client_socket_poll_loop_write_cb(int fd, void *user_data1, void *user_data2)
+{
+	struct qnetd_instance *instance = (struct qnetd_instance *)user_data1;
+	struct unix_socket_client *ipc_client = (struct unix_socket_client *)user_data2;
+
+	if (!ipc_client->schedule_disconnect) {
+		qnetd_ipc_io_write(instance, ipc_client);
+	}
+
+	return (0);
+}
+
+static int
+ipc_client_socket_poll_loop_err_cb(int fd, short revents, void *user_data1, void *user_data2)
+{
+	struct unix_socket_client *ipc_client = (struct unix_socket_client *)user_data2;
+
+	if (!ipc_client->schedule_disconnect) {
+		log(LOG_DEBUG, "POLL_ERR (%u) on ipc client socket."
+		    " Disconnecting.", revents);
+
+		ipc_client->schedule_disconnect = 1;
+	}
+
+	return (0);
+}
+
+/*
+ * Exported functions
+ */
 int
 qnetd_ipc_init(struct qnetd_instance *instance)
 {
@@ -60,8 +198,12 @@ qnetd_ipc_init(struct qnetd_instance *instance)
 		return (-1);
 	}
 
-	if ((instance->ipc_socket_poll_fd = PR_CreateSocketPollFd(instance->local_ipc.socket)) == NULL) {
-		log_nss(LOG_CRIT, "Can't create NSPR IPC socket poll fd");
+	if (pr_poll_loop_add_fd(&instance->main_poll_loop, instance->local_ipc.socket, POLLIN,
+	    ipc_socket_poll_loop_set_events_cb,
+	    ipc_socket_poll_loop_read_cb,
+	    ipc_socket_poll_loop_write_cb,
+	    ipc_socket_poll_loop_err_cb, instance, NULL) == -1) {
+		log_err(LOG_CRIT, "Can't add IPC socket to main poll loop");
 
 		return (-1);
 	}
@@ -102,10 +244,6 @@ qnetd_ipc_destroy(struct qnetd_instance *instance)
 		free(client->user_data);
 	}
 
-	if (PR_DestroySocketPollFd(instance->ipc_socket_poll_fd) != PR_SUCCESS) {
-		log_nss(LOG_WARNING, "Unable to destroy IPC poll socket fd");
-	}
-
 	res = unix_socket_ipc_destroy(&instance->local_ipc);
 	if (res != 0) {
 		log_err(LOG_WARNING, "Can't destroy local IPC");
@@ -119,7 +257,6 @@ qnetd_ipc_accept(struct qnetd_instance *instance, struct unix_socket_client **re
 {
 	int res;
 	int accept_res;
-	PRFileDesc *prfd;
 
 	accept_res = unix_socket_ipc_accept(&instance->local_ipc, res_client);
 
@@ -155,17 +292,19 @@ qnetd_ipc_accept(struct qnetd_instance *instance, struct unix_socket_client **re
 	}
 	memset((*res_client)->user_data, 0, sizeof(struct qnetd_ipc_user_data));
 
-	prfd = PR_CreateSocketPollFd((*res_client)->socket);
-	if (prfd == NULL) {
-		log_nss(LOG_CRIT, "Can't create NSPR poll fd for IPC client. Disconnecting client");
-		qnetd_ipc_client_disconnect(instance, *res_client);
+	if (pr_poll_loop_add_fd(&instance->main_poll_loop, (*res_client)->socket, 0,
+	    ipc_client_socket_poll_loop_set_events_cb,
+	    ipc_client_socket_poll_loop_read_cb,
+	    ipc_client_socket_poll_loop_write_cb,
+	    ipc_client_socket_poll_loop_err_cb, instance, *res_client) == -1) {
+		log_err(LOG_CRIT, "Can't add IPC client socket to main poll loop");
 		res = -1;
 
+		qnetd_ipc_client_disconnect(instance, *res_client);
+
 		goto return_res;
 	}
 
-	((struct qnetd_ipc_user_data *)(*res_client)->user_data)->nspr_poll_fd = prfd;
-
 return_res:
 	return (res);
 }
@@ -174,12 +313,6 @@ void
 qnetd_ipc_client_disconnect(struct qnetd_instance *instance, struct unix_socket_client *client)
 {
 
-	if ((struct qnetd_ipc_user_data *)(client)->user_data != NULL &&
-	    PR_DestroySocketPollFd(
-	    ((struct qnetd_ipc_user_data *)(client)->user_data)->nspr_poll_fd) != PR_SUCCESS) {
-		log_nss(LOG_WARNING, "Unable to destroy client IPC poll socket fd");
-	}
-
 	free(client->user_data);
 	unix_socket_ipc_client_disconnect(&instance->local_ipc, client);
 }

+ 1 - 2
qdevices/qnetd-ipc.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2016 Red Hat, Inc.
+ * Copyright (c) 2015-2020 Red Hat, Inc.
  *
  * All rights reserved.
  *
@@ -43,7 +43,6 @@ extern "C" {
 
 struct qnetd_ipc_user_data {
 	int shutdown_requested;
-	PRFileDesc *nspr_poll_fd;
 };
 
 extern int		qnetd_ipc_init(struct qnetd_instance *instance);

+ 0 - 61
qdevices/qnetd-poll-array-user-data.h

@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2015-2016 Red Hat, Inc.
- *
- * All rights reserved.
- *
- * Author: Jan Friesse (jfriesse@redhat.com)
- *
- * This software licensed under BSD license, the text of which follows:
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- *   this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright notice,
- *   this list of conditions and the following disclaimer in the documentation
- *   and/or other materials provided with the distribution.
- * - Neither the name of the Red Hat, Inc. nor the names of its
- *   contributors may be used to endorse or promote products derived from this
- *   software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _QNETD_POLL_ARRAY_USER_DATA_H_
-#define _QNETD_POLL_ARRAY_USER_DATA_H_
-
-#include "qnetd-client.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-enum qnetd_poll_array_user_data_type {
-	QNETD_POLL_ARRAY_USER_DATA_TYPE_SOCKET,
-	QNETD_POLL_ARRAY_USER_DATA_TYPE_CLIENT,
-	QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET,
-	QNETD_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT,
-};
-
-struct qnetd_poll_array_user_data {
-	enum qnetd_poll_array_user_data_type type;
-	struct qnetd_client *client;
-	struct unix_socket_client *ipc_client;
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _QNETD_POLL_ARRAY_USER_DATA_H_ */