remsim-server: Add support for keepalive

This ensures that any RSPRO client (remsim-client or remsim-bankd) is
disconnected if he's no longer responding to IPA PING requests.

Change-Id: I324f0f2a0613d6310e1d191103b136c539b6ec05
Depends: libosmocore Change-Id I2763da49a74de85046ac07d53592c89973314ca6
diff --git a/src/server/rspro_server.c b/src/server/rspro_server.c
index 9165547..1b228cb 100644
--- a/src/server/rspro_server.c
+++ b/src/server/rspro_server.c
@@ -91,6 +91,7 @@
 	CLNTC_E_CLIENT_CONN,	/* Connect{Client,Bank}Req received */
 	CLNTC_E_BANK_CONN,
 	CLNTC_E_TCP_DOWN,
+	CLNTC_E_KA_TIMEOUT,
 	CLNTC_E_CREATE_MAP_RES,	/* CreateMappingRes received */
 	CLNTC_E_REMOVE_MAP_RES,	/* RemoveMappingRes received */
 	CLNTC_E_CONFIG_CL_RES,	/* ConfigClientRes received */
@@ -102,6 +103,7 @@
 	OSMO_VALUE_STRING(CLNTC_E_CLIENT_CONN),
 	OSMO_VALUE_STRING(CLNTC_E_BANK_CONN),
 	OSMO_VALUE_STRING(CLNTC_E_TCP_DOWN),
+	OSMO_VALUE_STRING(CLNTC_E_KA_TIMEOUT),
 	OSMO_VALUE_STRING(CLNTC_E_CREATE_MAP_RES),
 	OSMO_VALUE_STRING(CLNTC_E_REMOVE_MAP_RES),
 	OSMO_VALUE_STRING(CLNTC_E_CONFIG_CL_RES),
@@ -321,6 +323,9 @@
 	case CLNTC_E_TCP_DOWN:
 		osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
 		break;
+	case CLNTC_E_KA_TIMEOUT:
+		osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
+		break;
 	default:
 		OSMO_ASSERT(0);
 	}
@@ -465,6 +470,16 @@
 	switch (hh->proto) {
 	case IPAC_PROTO_IPACCESS:
 		rc = ipa_server_conn_ccm(peer, msg);
+		if (rc < 0)
+			break;
+		switch (hh->data[0]) {
+		case IPAC_MSGT_PONG:
+			ipa_keepalive_fsm_pong_received(conn->keepalive_fi);
+			rc = 0;
+			break;
+		default:
+			break;
+		}
 		break;
 	case IPAC_PROTO_OSMO:
 		if (!he || msgb_l2len(msg)< sizeof(*he))
@@ -504,6 +519,11 @@
 	return 0;
 }
 
+static const struct ipa_keepalive_params ka_params = {
+	.interval = 30,
+	.wait_for_resp = 10,
+};
+
 /* a new TCP connection was accepted on the RSPRO server socket */
 static int accept_cb(struct ipa_server_link *link, int fd)
 {
@@ -525,6 +545,14 @@
 	if (!conn->fi)
 		goto out_err_conn;
 
+	/* use ipa_keepalive_fsm to periodically send an IPA_PING and expect a PONG in response */
+	conn->keepalive_fi = ipa_server_conn_alloc_keepalive_fsm(conn->peer, &ka_params, NULL);
+	if (!conn->keepalive_fi)
+		goto out_err_fi;
+	/* ensure parent is notified once keepalive FSM instance is dying */
+	osmo_fsm_inst_change_parent(conn->keepalive_fi, conn->fi, CLNTC_E_KA_TIMEOUT);
+	ipa_keepalive_fsm_start(conn->keepalive_fi);
+
 	INIT_LLIST_HEAD(&conn->bank.maps_new);
 	INIT_LLIST_HEAD(&conn->bank.maps_unack);
 	INIT_LLIST_HEAD(&conn->bank.maps_active);
@@ -538,6 +566,8 @@
 	osmo_fsm_inst_dispatch(conn->fi, CLNTC_E_TCP_UP, NULL);
 	return 0;
 
+out_err_fi:
+	osmo_fsm_inst_term(conn->fi, OSMO_FSM_TERM_ERROR, NULL);
 out_err_conn:
 	ipa_server_conn_destroy(conn->peer);
 	/* the above will free 'conn' down the chain */
diff --git a/src/server/rspro_server.h b/src/server/rspro_server.h
index 44b0fb9..1703cb5 100644
--- a/src/server/rspro_server.h
+++ b/src/server/rspro_server.h
@@ -35,6 +35,8 @@
 	struct osmo_fsm_inst *fi;
 	/* remote component identity (after it has been received) */
 	struct app_comp_id comp_id;
+	/* keep-alive handling FSM */
+	struct osmo_fsm_inst *keepalive_fi;
 
 	struct {
 		struct llist_head maps_new;