Pārlūkot izejas kodu

Qdevice: Support for IPC status cmd in net model

Signed-off-by: Jan Friesse <jfriesse@redhat.com>
Jan Friesse 9 gadi atpakaļ
vecāks
revīzija
0552b339d1

+ 1 - 1
qdevices/Makefile.am

@@ -56,7 +56,7 @@ corosync_qdevice_SOURCES	= corosync-qdevice.c qdevice-cmap.c qdevice-instance.c
 				  msg.c msgio.c nss-sock.c tlv.c \
 				  msg.c msgio.c nss-sock.c tlv.c \
 				  unix-socket.c unix-socket-client.c unix-socket-client-list.c \
 				  unix-socket.c unix-socket-client.c unix-socket-client-list.c \
 				  unix-socket-ipc.c qdevice-ipc.c pr-poll-array.c dynar-simple-lex.c \
 				  unix-socket-ipc.c qdevice-ipc.c pr-poll-array.c dynar-simple-lex.c \
-				  dynar-str.c qdevice-ipc-cmd.c \
+				  dynar-str.c qdevice-ipc-cmd.c qdevice-net-ipc-cmd.c \
 				  qdevice-net-poll.c qdevice-net-send.c qdevice-net-votequorum.c \
 				  qdevice-net-poll.c qdevice-net-send.c qdevice-net-votequorum.c \
 				  qdevice-net-socket.c qdevice-net-nss.c qdevice-net-msg-received.c \
 				  qdevice-net-socket.c qdevice-net-nss.c qdevice-net-msg-received.c \
 				  qdevice-net-cast-vote-timer.c qdevice-net-echo-request-timer.c \
 				  qdevice-net-cast-vote-timer.c qdevice-net-echo-request-timer.c \

+ 4 - 2
qdevices/qdevice-ipc-cmd.c

@@ -53,7 +53,7 @@ qdevice_ipc_cmd_status_add_model(struct qdevice_instance *instance, struct dynar
 {
 {
 
 
 	return (dynar_str_catf(outbuf, "Model:\t\t\t%s\n",
 	return (dynar_str_catf(outbuf, "Model:\t\t\t%s\n",
-		qdevice_mode_type_to_str(instance->model_type)) != -1);
+		qdevice_model_type_to_str(instance->model_type)) != -1);
 }
 }
 
 
 static int
 static int
@@ -255,7 +255,9 @@ qdevice_ipc_cmd_status(struct qdevice_instance *instance, struct dynar *outbuf,
 	    qdevice_ipc_cmd_status_add_membership_node_list(instance, outbuf, verbose) &&
 	    qdevice_ipc_cmd_status_add_membership_node_list(instance, outbuf, verbose) &&
 	    qdevice_ipc_cmd_status_add_quorum_node_list(instance, outbuf, verbose) &&
 	    qdevice_ipc_cmd_status_add_quorum_node_list(instance, outbuf, verbose) &&
 	    qdevice_ipc_cmd_status_add_expected_votes(instance, outbuf, verbose) &&
 	    qdevice_ipc_cmd_status_add_expected_votes(instance, outbuf, verbose) &&
-	    qdevice_ipc_cmd_status_add_last_poll(instance, outbuf, verbose)) {
+	    qdevice_ipc_cmd_status_add_last_poll(instance, outbuf, verbose) &&
+	    dynar_str_catf(outbuf, "\n") != -1 &&
+	    qdevice_model_ipc_cmd_status(instance, outbuf, verbose) != -1) {
 		return (0);
 		return (0);
 	}
 	}
 
 

+ 17 - 0
qdevices/qdevice-model-net.c

@@ -39,6 +39,7 @@
 #include "qdevice-log.h"
 #include "qdevice-log.h"
 #include "qdevice-net-cast-vote-timer.h"
 #include "qdevice-net-cast-vote-timer.h"
 #include "qdevice-net-instance.h"
 #include "qdevice-net-instance.h"
+#include "qdevice-net-ipc-cmd.h"
 #include "qdevice-net-algorithm.h"
 #include "qdevice-net-algorithm.h"
 #include "qdevice-net-poll.h"
 #include "qdevice-net-poll.h"
 #include "qdevice-net-send.h"
 #include "qdevice-net-send.h"
@@ -473,6 +474,21 @@ qdevice_model_net_votequorum_expected_votes_notify(struct qdevice_instance *inst
 	return (0);
 	return (0);
 }
 }
 
 
+int
+qdevice_model_net_ipc_cmd_status(struct qdevice_instance *instance,
+    struct dynar *outbuf, int verbose)
+{
+	struct qdevice_net_instance *net_instance;
+
+	net_instance = instance->model_data;
+
+	if (!qdevice_net_ipc_cmd_status(net_instance, outbuf, verbose)) {
+		return (-1);
+	}
+
+	return (0);
+}
+
 static struct qdevice_model qdevice_model_net = {
 static struct qdevice_model qdevice_model_net = {
 	.name					= "net",
 	.name					= "net",
 	.init					= qdevice_model_net_init,
 	.init					= qdevice_model_net_init,
@@ -483,6 +499,7 @@ static struct qdevice_model qdevice_model_net = {
 	.votequorum_quorum_notify		= qdevice_model_net_votequorum_quorum_notify,
 	.votequorum_quorum_notify		= qdevice_model_net_votequorum_quorum_notify,
 	.votequorum_node_list_notify		= qdevice_model_net_votequorum_node_list_notify,
 	.votequorum_node_list_notify		= qdevice_model_net_votequorum_node_list_notify,
 	.votequorum_expected_votes_notify	= qdevice_model_net_votequorum_expected_votes_notify,
 	.votequorum_expected_votes_notify	= qdevice_model_net_votequorum_expected_votes_notify,
+	.ipc_cmd_status				= qdevice_model_net_ipc_cmd_status,
 };
 };
 
 
 int
 int

+ 3 - 0
qdevices/qdevice-model-net.h

@@ -62,6 +62,9 @@ extern int	qdevice_model_net_votequorum_node_list_notify(struct qdevice_instance
 extern int 	qdevice_model_net_votequorum_expected_votes_notify(struct qdevice_instance *instance,
 extern int 	qdevice_model_net_votequorum_expected_votes_notify(struct qdevice_instance *instance,
     uint32_t expected_votes);
     uint32_t expected_votes);
 
 
+extern int	qdevice_model_net_ipc_cmd_status(struct qdevice_instance *instance,
+    struct dynar *outbuf, int verbose);
+
 extern int	qdevice_model_net_register(void);
 extern int	qdevice_model_net_register(void);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus

+ 15 - 1
qdevices/qdevice-model.c

@@ -150,6 +150,20 @@ qdevice_model_votequorum_expected_votes_notify(struct qdevice_instance *instance
 	    votequorum_expected_votes_notify(instance, expected_votes));
 	    votequorum_expected_votes_notify(instance, expected_votes));
 }
 }
 
 
+int
+qdevice_model_ipc_cmd_status(struct qdevice_instance *instance, struct dynar *outbuf, int verbose)
+{
+
+	if (instance->model_type >= QDEVICE_MODEL_TYPE_ARRAY_SIZE ||
+	    qdevice_model_array[instance->model_type] == NULL) {
+		qdevice_log(LOG_CRIT, "qdevice_model_ipc_cmd_status unhandled model");
+		exit(1);
+	}
+
+	return (qdevice_model_array[instance->model_type]->
+	    ipc_cmd_status(instance, outbuf, verbose));
+}
+
 int
 int
 qdevice_model_register(enum qdevice_model_type model_type,
 qdevice_model_register(enum qdevice_model_type model_type,
     struct qdevice_model *model)
     struct qdevice_model *model)
@@ -196,7 +210,7 @@ qdevice_model_str_to_type(const char *str, enum qdevice_model_type *model_type)
 }
 }
 
 
 const char *
 const char *
-qdevice_mode_type_to_str(enum qdevice_model_type model_type)
+qdevice_model_type_to_str(enum qdevice_model_type model_type)
 {
 {
 
 
 	switch (model_type) {
 	switch (model_type) {

+ 5 - 1
qdevices/qdevice-model.h

@@ -62,6 +62,9 @@ extern int	qdevice_model_votequorum_node_list_notify(struct qdevice_instance *in
 extern int 	qdevice_model_votequorum_expected_votes_notify(struct qdevice_instance *instance,
 extern int 	qdevice_model_votequorum_expected_votes_notify(struct qdevice_instance *instance,
     uint32_t expected_votes);
     uint32_t expected_votes);
 
 
+extern int	qdevice_model_ipc_cmd_status(struct qdevice_instance *instance,
+    struct dynar *outbuf, int verbose);
+
 struct qdevice_model {
 struct qdevice_model {
 	const char *name;
 	const char *name;
 	int (*init)(struct qdevice_instance *instance);
 	int (*init)(struct qdevice_instance *instance);
@@ -77,6 +80,7 @@ struct qdevice_model {
 	    uint32_t node_list[]);
 	    uint32_t node_list[]);
 	int (*votequorum_expected_votes_notify)(struct qdevice_instance *instance,
 	int (*votequorum_expected_votes_notify)(struct qdevice_instance *instance,
 	    uint32_t expected_votes);
 	    uint32_t expected_votes);
+	int (*ipc_cmd_status)(struct qdevice_instance *instance, struct dynar *outbuf, int verbose);
 };
 };
 
 
 extern int		 qdevice_model_register(
 extern int		 qdevice_model_register(
@@ -87,7 +91,7 @@ extern void qdevice_model_register_all(void);
 extern int		 qdevice_model_str_to_type(const char *str,
 extern int		 qdevice_model_str_to_type(const char *str,
     enum qdevice_model_type *model_type);
     enum qdevice_model_type *model_type);
 
 
-extern const char 	*qdevice_mode_type_to_str(enum qdevice_model_type model_type);
+extern const char 	*qdevice_model_type_to_str(enum qdevice_model_type model_type);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 17 - 0
qdevices/qdevice-net-algorithm.c

@@ -311,3 +311,20 @@ qdevice_net_algorithm_register_all(void)
 
 
 	return (0);
 	return (0);
 }
 }
+
+const char *
+qdevice_net_algorithm_type_to_str(enum tlv_decision_algorithm_type algo_type)
+{
+
+	switch (algo_type) {
+	case TLV_DECISION_ALGORITHM_TYPE_TEST: return ("Test"); break;
+	case TLV_DECISION_ALGORITHM_TYPE_FFSPLIT: return ("Fifty-Fifty split"); break;
+	case TLV_DECISION_ALGORITHM_TYPE_2NODELMS: return ("2 Node LMS"); break;
+	case TLV_DECISION_ALGORITHM_TYPE_LMS: return ("LMS"); break;
+	/*
+	 * Default is not defined intentionally. Compiler shows warning when new model is added
+	 */
+	}
+
+	return ("Unknown algorithm");
+}

+ 5 - 2
qdevices/qdevice-net-algorithm.h

@@ -121,10 +121,13 @@ struct qdevice_net_algorithm {
 	void (*destroy)(struct qdevice_net_instance *instance);
 	void (*destroy)(struct qdevice_net_instance *instance);
 };
 };
 
 
-extern int		qdevice_net_algorithm_register(
+extern int		 qdevice_net_algorithm_register(
 	enum tlv_decision_algorithm_type algorithm_number, struct qdevice_net_algorithm *algorithm);
 	enum tlv_decision_algorithm_type algorithm_number, struct qdevice_net_algorithm *algorithm);
 
 
-extern int		qdevice_net_algorithm_register_all(void);
+extern int		 qdevice_net_algorithm_register_all(void);
+
+extern const char 	*qdevice_net_algorithm_type_to_str(
+    enum tlv_decision_algorithm_type algo_type);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 6 - 0
qdevices/qdevice-net-instance.c

@@ -75,6 +75,9 @@ qdevice_net_instance_init(struct qdevice_net_instance *instance, size_t initial_
 	instance->echo_request_expected_msg_seq_num = 1;
 	instance->echo_request_expected_msg_seq_num = 1;
 	instance->echo_reply_received_msg_seq_num = 1;
 	instance->echo_reply_received_msg_seq_num = 1;
 	instance->force_ip_version = force_ip_version;
 	instance->force_ip_version = force_ip_version;
+	instance->last_echo_reply_received_time = ((time_t) -1);
+	instance->connected_since_time = ((time_t) -1);
+
 	memcpy(&instance->tie_breaker, tie_breaker, sizeof(*tie_breaker));
 	memcpy(&instance->tie_breaker, tie_breaker, sizeof(*tie_breaker));
 
 
 	dynar_init(&instance->receive_buffer, initial_receive_size);
 	dynar_init(&instance->receive_buffer, initial_receive_size);
@@ -119,9 +122,12 @@ qdevice_net_instance_clean(struct qdevice_net_instance *instance)
 	instance->state = QDEVICE_NET_INSTANCE_STATE_WAITING_PREINIT_REPLY;
 	instance->state = QDEVICE_NET_INSTANCE_STATE_WAITING_PREINIT_REPLY;
 	instance->echo_request_expected_msg_seq_num = instance->echo_reply_received_msg_seq_num;
 	instance->echo_request_expected_msg_seq_num = instance->echo_reply_received_msg_seq_num;
 	instance->using_tls = 0;
 	instance->using_tls = 0;
+	instance->tls_client_cert_sent = 0;
 
 
 	instance->schedule_disconnect = 0;
 	instance->schedule_disconnect = 0;
 	instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNDEFINED;
 	instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNDEFINED;
+	instance->last_echo_reply_received_time = ((time_t) -1);
+	instance->connected_since_time = ((time_t) -1);
 }
 }
 
 
 int
 int

+ 3 - 0
qdevices/qdevice-net-instance.h

@@ -81,6 +81,7 @@ struct qdevice_net_instance {
 	uint32_t echo_reply_received_msg_seq_num;
 	uint32_t echo_reply_received_msg_seq_num;
 	enum tlv_tls_supported tls_supported;
 	enum tlv_tls_supported tls_supported;
 	int using_tls;
 	int using_tls;
+	int tls_client_cert_sent;
 	uint32_t heartbeat_interval;            /* Adjusted heartbeat interval during normal operation */
 	uint32_t heartbeat_interval;            /* Adjusted heartbeat interval during normal operation */
 	uint32_t sync_heartbeat_interval;       /* Adjusted heartbeat interval during corosync sync */
 	uint32_t sync_heartbeat_interval;       /* Adjusted heartbeat interval during corosync sync */
 	uint32_t cast_vote_timer_interval;	/* Timer for cast vote */
 	uint32_t cast_vote_timer_interval;	/* Timer for cast vote */
@@ -106,6 +107,8 @@ struct qdevice_net_instance {
 	struct timer_list_entry *connect_timer;
 	struct timer_list_entry *connect_timer;
 	int force_ip_version;
 	int force_ip_version;
 	struct pr_poll_array poll_array;
 	struct pr_poll_array poll_array;
+	time_t last_echo_reply_received_time;
+	time_t connected_since_time;
 };
 };
 
 
 extern int		qdevice_net_instance_init(struct qdevice_net_instance *instance,
 extern int		qdevice_net_instance_init(struct qdevice_net_instance *instance,

+ 240 - 0
qdevices/qdevice-net-ipc-cmd.c

@@ -0,0 +1,240 @@
+/*
+ * 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.
+ */
+
+#include "qdevice-net-ipc-cmd.h"
+#include "qdevice-log.h"
+#include "dynar-str.h"
+#include "qdevice-net-algorithm.h"
+#include "utils.h"
+
+static int
+qdevice_net_ipc_cmd_status_add_header(struct dynar *outbuf, int verbose)
+{
+
+	return ((dynar_str_catf(outbuf, "Qdevice-net information\n") != -1) &&
+	    (dynar_str_catf(outbuf, "----------------------\n") != -1));
+}
+
+static int
+qdevice_net_ipc_cmd_status_add_tie_breaker(struct qdevice_net_instance *instance,
+    struct dynar *outbuf, int verbose)
+{
+
+	if (dynar_str_catf(outbuf, "Tie-breaker:\t\t") == -1) {
+		return (0);
+	}
+
+	switch (instance->tie_breaker.mode) {
+	case TLV_TIE_BREAKER_MODE_LOWEST:
+		if (dynar_str_catf(outbuf, "Node with lowest node ID") == -1) {
+			return (0);
+		}
+		break;
+	case TLV_TIE_BREAKER_MODE_HIGHEST:
+		if (dynar_str_catf(outbuf, "Node with highest node ID") == -1) {
+			return (0);
+		}
+		break;
+	case TLV_TIE_BREAKER_MODE_NODE_ID:
+		if (dynar_str_catf(outbuf, "Node with node ID "UTILS_PRI_NODE_ID,
+		    instance->tie_breaker.node_id) == -1) {
+			return (0);
+		}
+		break;
+	}
+
+	return (dynar_str_catf(outbuf, "\n") != -1);
+}
+
+static int
+qdevice_net_ipc_cmd_status_add_basic_info(struct qdevice_net_instance *instance,
+    struct dynar *outbuf, int verbose)
+{
+
+	if (dynar_str_catf(outbuf, "Cluster name:\t\t%s\n", instance->cluster_name) == -1) {
+		return (0);
+	}
+
+	if (dynar_str_catf(outbuf, "QNetd host:\t\t%s:%"PRIu16"\n",
+	    instance->host_addr, instance->host_port) == -1) {
+		return (0);
+	}
+
+	if (verbose && instance->force_ip_version != 0) {
+		if (dynar_str_catf(outbuf, "Force IP version:\t%u\n",
+		    instance->force_ip_version) == -1) {
+			return (0);
+		}
+	}
+
+	if (verbose) {
+		if ((dynar_str_catf(outbuf, "Connect timeout:\t%"PRIu32"ms\n",
+		    instance->connect_timeout) == -1) ||
+		    (dynar_str_catf(outbuf, "HB interval:\t\t%"PRIu32"ms\n",
+		    instance->heartbeat_interval) == -1) ||
+		    (dynar_str_catf(outbuf, "VQ vote timer interval:\t%"PRIu32"ms\n",
+		    instance->cast_vote_timer_interval) == -1)) {
+			return (0);
+		}
+
+		if (dynar_str_catf(outbuf, "TLS:\t\t\t%s\n",
+		    tlv_tls_supported_to_str(instance->tls_supported)) == -1) {
+			return (0);
+		}
+	}
+
+	if (dynar_str_catf(outbuf, "Algorithm:\t\t%s\n",
+	    qdevice_net_algorithm_type_to_str(instance->decision_algorithm)) == -1) {
+		return (0);
+	}
+
+	return (1);
+}
+
+static int
+qdevice_net_ipc_cmd_status_add_poll_timer_status(struct qdevice_net_instance *instance,
+    struct dynar *outbuf, int verbose)
+{
+
+	if (!verbose) {
+		return (1);
+	}
+
+	if (dynar_str_catf(outbuf, "Poll timer running:\t%s",
+	    (instance->cast_vote_timer != NULL ? "Yes" : "No")) == -1) {
+		return (0);
+	}
+
+	if (instance->cast_vote_timer != NULL && instance->cast_vote_timer_vote == TLV_VOTE_ACK) {
+		if (dynar_str_catf(outbuf, " (cast vote)") == -1) {
+			return (0);
+		}
+	}
+
+	return (dynar_str_catf(outbuf, "\n") != -1);
+}
+
+static int
+qdevice_net_ipc_cmd_status_add_state(struct qdevice_net_instance *instance,
+    struct dynar *outbuf, int verbose)
+{
+	const char *state;
+
+	if (instance->schedule_disconnect) {
+		state = "Disconnected";
+	} else {
+		if (instance->state == QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) {
+			state = "Connected";
+		} else {
+			if (instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_CONNECT ||
+			    !instance->non_blocking_client.destroyed) {
+				state = "Connecting";
+			} else {
+				state = "Connect failed";
+			}
+		}
+	}
+
+	return (dynar_str_catf(outbuf, "State:\t\t\t%s\n", state) != -1);
+}
+
+static int
+qdevice_net_ipc_cmd_status_add_tls_state(struct qdevice_net_instance *instance,
+    struct dynar *outbuf, int verbose)
+{
+
+	if (!verbose || instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) {
+		return (1);
+	}
+
+	if (dynar_str_catf(outbuf, "TLS active:\t\t%s", (instance->using_tls ? "Yes" : "No")) == -1) {
+		return (0);
+	}
+
+	if (instance->using_tls && instance->tls_client_cert_sent) {
+		if (dynar_str_catf(outbuf, " (client certificate sent)") == -1) {
+			return (0);
+		}
+	}
+
+	return (dynar_str_catf(outbuf, "\n") != -1);
+}
+
+static int
+qdevice_net_ipc_cmd_status_add_times(struct qdevice_net_instance *instance,
+    struct dynar *outbuf, int verbose)
+{
+	struct tm tm_res;
+
+	if (!verbose || instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) {
+		return (1);
+	}
+
+	if (instance->connected_since_time != ((time_t) -1)) {
+		localtime_r(&instance->connected_since_time, &tm_res);
+		if (dynar_str_catf(outbuf, "Connected since:\t%04d-%02d-%02dT%02d:%02d:%02d\n",
+		    tm_res.tm_year + 1900, tm_res.tm_mon + 1, tm_res.tm_mday,
+		    tm_res.tm_hour, tm_res.tm_min, tm_res.tm_sec) == -1) {
+			return (0);
+		}
+	}
+
+	if (instance->last_echo_reply_received_time != ((time_t) -1)) {
+		localtime_r(&instance->last_echo_reply_received_time, &tm_res);
+		if (dynar_str_catf(outbuf, "Echo reply received:\t%04d-%02d-%02dT%02d:%02d:%02d\n",
+		    tm_res.tm_year + 1900, tm_res.tm_mon + 1, tm_res.tm_mday,
+		    tm_res.tm_hour, tm_res.tm_min, tm_res.tm_sec) == -1) {
+			return (0);
+		}
+	}
+
+	return (1);
+}
+
+int
+qdevice_net_ipc_cmd_status(struct qdevice_net_instance *instance, struct dynar *outbuf, int verbose)
+{
+
+	if (qdevice_net_ipc_cmd_status_add_header(outbuf, verbose) &&
+	    qdevice_net_ipc_cmd_status_add_basic_info(instance, outbuf, verbose) &&
+	    qdevice_net_ipc_cmd_status_add_tie_breaker(instance, outbuf, verbose) &&
+	    qdevice_net_ipc_cmd_status_add_poll_timer_status(instance, outbuf, verbose) &&
+	    qdevice_net_ipc_cmd_status_add_state(instance, outbuf, verbose) &&
+	    qdevice_net_ipc_cmd_status_add_tls_state(instance, outbuf, verbose) &&
+	    qdevice_net_ipc_cmd_status_add_times(instance, outbuf, verbose)) {
+		return (1);
+	}
+
+	return (0);
+}

+ 52 - 0
qdevices/qdevice-net-ipc-cmd.h

@@ -0,0 +1,52 @@
+/*
+ * 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 _QDEVICE_NET_IPC_CMD_H_
+#define _QDEVICE_NET_IPC_CMD_H_
+
+#include "dynar.h"
+#include "qdevice-net-instance.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int	qdevice_net_ipc_cmd_status(struct qdevice_net_instance *instance,
+    struct dynar *outbuf, int verbose);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _QDEVICE_NET_IPC_CMD_H_ */

+ 2 - 0
qdevices/qdevice-net-msg-received.c

@@ -431,6 +431,7 @@ qdevice_net_msg_received_init_reply(struct qdevice_net_instance *instance,
 	}
 	}
 
 
 	instance->state = QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS;
 	instance->state = QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS;
+	instance->connected_since_time = time(NULL);
 
 
 	return (0);
 	return (0);
 }
 }
@@ -529,6 +530,7 @@ qdevice_net_msg_received_echo_reply(struct qdevice_net_instance *instance,
 	}
 	}
 
 
 	instance->echo_reply_received_msg_seq_num = msg->seq_number;
 	instance->echo_reply_received_msg_seq_num = msg->seq_number;
+	instance->last_echo_reply_received_time = time(NULL);
 
 
 	return (0);
 	return (0);
 }
 }

+ 9 - 1
qdevices/qdevice-net-nss.c

@@ -37,6 +37,8 @@
 
 
 #include "qdevice-log.h"
 #include "qdevice-log.h"
 #include "qdevice-net-nss.h"
 #include "qdevice-net-nss.h"
+#include "qdevice-net-instance.h"
+#include "qnet-config.h"
 
 
 SECStatus
 SECStatus
 qdevice_net_nss_bad_cert_hook(void *arg, PRFileDesc *fd) {
 qdevice_net_nss_bad_cert_hook(void *arg, PRFileDesc *fd) {
@@ -59,8 +61,14 @@ SECStatus
 qdevice_net_nss_get_client_auth_data(void *arg, PRFileDesc *sock, struct CERTDistNamesStr *caNames,
 qdevice_net_nss_get_client_auth_data(void *arg, PRFileDesc *sock, struct CERTDistNamesStr *caNames,
     struct CERTCertificateStr **pRetCert, struct SECKEYPrivateKeyStr **pRetKey)
     struct CERTCertificateStr **pRetCert, struct SECKEYPrivateKeyStr **pRetKey)
 {
 {
+	struct qdevice_net_instance *instance;
 
 
 	qdevice_log(LOG_DEBUG, "Sending client auth data.");
 	qdevice_log(LOG_DEBUG, "Sending client auth data.");
 
 
-	return (NSS_GetClientAuthData(arg, sock, caNames, pRetCert, pRetKey));
+	instance = (struct qdevice_net_instance *)arg;
+
+	instance->tls_client_cert_sent = 1;
+
+	return (NSS_GetClientAuthData((void *)QDEVICE_NET_NSS_CLIENT_CERT_NICKNAME, sock, caNames,
+	    pRetCert, pRetKey));
 }
 }

+ 2 - 1
qdevices/qdevice-net-socket.c

@@ -142,7 +142,7 @@ qdevice_net_socket_write_finished(struct qdevice_net_instance *instance)
 		if ((new_pr_fd = nss_sock_start_ssl_as_client(instance->socket, QNETD_NSS_SERVER_CN,
 		if ((new_pr_fd = nss_sock_start_ssl_as_client(instance->socket, QNETD_NSS_SERVER_CN,
 		    qdevice_net_nss_bad_cert_hook,
 		    qdevice_net_nss_bad_cert_hook,
 		    qdevice_net_nss_get_client_auth_data,
 		    qdevice_net_nss_get_client_auth_data,
-		    (void *)QDEVICE_NET_NSS_CLIENT_CERT_NICKNAME, 0, NULL)) == NULL) {
+		    instance, 0, NULL)) == NULL) {
 			qdevice_log_nss(LOG_ERR, "Can't start TLS");
 			qdevice_log_nss(LOG_ERR, "Can't start TLS");
 			instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_START_TLS;
 			instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_START_TLS;
 			return (-1);
 			return (-1);
@@ -159,6 +159,7 @@ qdevice_net_socket_write_finished(struct qdevice_net_instance *instance)
 		}
 		}
 
 
 		instance->socket = new_pr_fd;
 		instance->socket = new_pr_fd;
+		instance->using_tls = 1;
 	}
 	}
 
 
 	return (0);
 	return (0);

+ 13 - 0
qdevices/tlv.c

@@ -1008,3 +1008,16 @@ tlv_node_state_to_str(enum tlv_node_state state)
 
 
 	return ("Unhandled node state");
 	return ("Unhandled node state");
 }
 }
+
+extern const char *
+tlv_tls_supported_to_str(enum tlv_tls_supported tls_supported)
+{
+
+	switch (tls_supported) {
+	case TLV_TLS_UNSUPPORTED: return ("Unsupported"); break;
+	case TLV_TLS_SUPPORTED: return ("Supported"); break;
+	case TLV_TLS_REQUIRED: return ("Required"); break;
+	}
+
+	return ("Unhandled tls supported state");
+}

+ 2 - 0
qdevices/tlv.h

@@ -325,6 +325,8 @@ extern const char *		 tlv_vote_to_str(enum tlv_vote vote);
 
 
 extern const char *		 tlv_node_state_to_str(enum tlv_node_state state);
 extern const char *		 tlv_node_state_to_str(enum tlv_node_state state);
 
 
+extern const char *		 tlv_tls_supported_to_str(enum tlv_tls_supported tls_supported);
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }
 #endif
 #endif