blob: c9ddd565821dc2c15b4f61cd59cb8f200663322e [file] [log] [blame]
Harald Welte707c85a2019-03-09 12:56:35 +01001#include <stdint.h>
2#include <string.h>
3#include <errno.h>
4
5#include <talloc.h>
6
7#include <osmocom/core/logging.h>
8#include <osmocom/core/utils.h>
9#include <osmocom/core/msgb.h>
10#include <osmocom/core/fsm.h>
11
12#include <osmocom/abis/ipa.h>
13#include <osmocom/gsm/protocol/ipaccess.h>
14
15#include "client.h"
16#include "rspro_util.h"
17
18#define S(x) (1 << (x))
19
20static void bankd_updown_cb(struct ipa_client_conn *conn, int up)
21{
22 struct bankd_client *bc = conn->data;
23
24 printf("RSPRO link to %s:%d %s\n", conn->addr, conn->port, up ? "UP" : "DOWN");
25
26 osmo_fsm_inst_dispatch(bc->bankd_fi, up ? BDC_E_TCP_UP: BDC_E_TCP_DOWN, 0);
27}
28
29/***********************************************************************
30 * bankd connection FSM: Remsim Client connection to Bankd
31 ***********************************************************************/
32
33enum bankd_conn_fsm_state {
34 /* waiting for initial connectiong to remsim-bankd */
35 BDC_ST_INIT,
36 /* bankd connection established, waiting for ClientConnectRes */
37 BDC_ST_ESTABLISHED,
38 /* bankd connection etsablished, ClientConnect succeeded */
39 BDC_ST_CONNECTED,
40 /* connection lost, we're waiting for a re-establish */
41 BDC_ST_REESTABLISH,
42};
43
44static const struct value_string remsim_client_bankd_fsm_event_names[] = {
45 OSMO_VALUE_STRING(BDC_E_ESTABLISH),
46 OSMO_VALUE_STRING(BDC_E_TCP_UP),
47 OSMO_VALUE_STRING(BDC_E_TCP_DOWN),
48 OSMO_VALUE_STRING(BDC_E_CLIENT_CONN_RES),
49 { 0, NULL }
50};
51
52#define T1_WAIT_CLIENT_CONN_RES 10
53#define T2_RECONNECT 10
54
55
56static void bdc_st_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
57{
58 switch (event) {
59 case BDC_E_ESTABLISH:
60 osmo_fsm_inst_state_chg(fi, BDC_ST_REESTABLISH, T2_RECONNECT, 2);
61 break;
62 default:
63 OSMO_ASSERT(0);
64 }
65}
66
67static void bdc_st_established_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
68{
69 struct bankd_client *bc = (struct bankd_client *) fi->priv;
70 RsproPDU_t *pdu;
71
72 /* FIXME: Send ClientConnReq */
73 pdu = rspro_gen_ConnectClientReq(&bc->srv_conn.own_comp_id, bc->srv_conn.clslot);
74 ipa_client_conn_send_rspro(bc->bankd_conn, pdu);
75}
76
77static void bdc_st_established(struct osmo_fsm_inst *fi, uint32_t event, void *data)
78{
79 switch (event) {
80 case BDC_E_TCP_DOWN:
81 osmo_fsm_inst_state_chg(fi, BDC_ST_REESTABLISH, T2_RECONNECT, 2);
82 break;
83 case BDC_E_CLIENT_CONN_RES:
84 /* somehow notify the main code? */
85 osmo_fsm_inst_state_chg(fi, BDC_ST_CONNECTED, 0, 0);
86 break;
87 default:
88 OSMO_ASSERT(0);
89 }
90}
91
92static void bdc_st_connected(struct osmo_fsm_inst *fi, uint32_t event, void *data)
93{
94 switch (event) {
95 case BDC_E_TCP_DOWN:
96 osmo_fsm_inst_state_chg(fi, BDC_ST_REESTABLISH, T2_RECONNECT, 2);
97 break;
98 default:
99 OSMO_ASSERT(0);
100 }
101}
102
103static void bdc_st_reestablish_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
104{
105 struct bankd_client *bc = (struct bankd_client *) fi->priv;
106 int rc;
107
108 /* re-create bankd_conn */
109 if (bc->bankd_conn) {
110 LOGPFSML(fi, LOGL_INFO, "Destroying existing connection to bankd\n");
111 ipa_client_conn_destroy(bc->bankd_conn);
112 bc->bankd_conn = NULL;
113 }
114 LOGPFSML(fi, LOGL_INFO, "Creating TCP connection to bankd at %s:%u\n",
115 bc->bankd_host, bc->bankd_port);
116 bc->bankd_conn = ipa_client_conn_create(bc, NULL, 0, bc->bankd_host, bc->bankd_port,
117 bankd_updown_cb, bankd_read_cb, NULL, bc);
118 if (!bc->bankd_conn) {
119 fprintf(stderr, "Unable to create socket: %s\n", strerror(errno));
120 exit(1);
121 }
122
123 /* Attempt to connect TCP socket */
124 rc = ipa_client_conn_open(bc->bankd_conn);
125 if (rc < 0) {
126 fprintf(stderr, "Unable to connect RSPRO to %s:%d - %s\n",
127 bc->bankd_conn->addr, bc->bankd_conn->port, strerror(errno));
128 /* FIXME: retry? Timer? Abort? */
129 OSMO_ASSERT(0);
130 }
131}
132
133static void bdc_st_reestablish(struct osmo_fsm_inst *fi, uint32_t event, void *data)
134{
135 switch (event) {
136 case BDC_E_TCP_UP:
137 osmo_fsm_inst_state_chg(fi, BDC_ST_ESTABLISHED, T1_WAIT_CLIENT_CONN_RES, 1);
138 break;
139 case BDC_E_TCP_DOWN:
140 /* wait for normal T2 timeout */
141 break;
142 default:
143 OSMO_ASSERT(0);
144 }
145}
146
147static void bdc_allstate_action(struct osmo_fsm_inst *fi, uint32_t event, void *data)
148{
149 switch (event) {
150 case BDC_ST_REESTABLISH:
151 osmo_fsm_inst_state_chg(fi, BDC_ST_REESTABLISH, T2_RECONNECT, 2);
152 break;
153 default:
154 OSMO_ASSERT(0);
155 }
156}
157
158static int remsim_client_bankd_fsm_timer_cb(struct osmo_fsm_inst *fi)
159{
160 switch (fi->T) {
161 case 2:
162 /* TCP reconnect failed: retry */
163 osmo_fsm_inst_state_chg(fi, BDC_ST_REESTABLISH, T2_RECONNECT, 2);
164 break;
165 case 1:
166 /* no ClientConnectRes received: disconnect + reconnect */
167 osmo_fsm_inst_state_chg(fi, BDC_ST_REESTABLISH, T2_RECONNECT, 2);
168 break;
169 default:
170 OSMO_ASSERT(0);
171 }
172 return 0;
173}
174
175static const struct osmo_fsm_state bankd_conn_fsm_states[] = {
176 [BDC_ST_INIT] = {
177 .name = "INIT",
178 .in_event_mask = 0, /* S(BDC_E_ESTABLISH) via allstate */
179 .out_state_mask = S(BDC_ST_REESTABLISH),
180 .action = bdc_st_init,
181 },
182 [BDC_ST_ESTABLISHED] = {
183 .name = "ESTABLISHED",
184 .in_event_mask = S(BDC_E_TCP_DOWN) | S(BDC_E_CLIENT_CONN_RES),
185 .out_state_mask = S(BDC_ST_CONNECTED) | S(BDC_ST_REESTABLISH),
186 .action = bdc_st_established,
187 .onenter = bdc_st_established_onenter,
188 },
189 [BDC_ST_CONNECTED] = {
190 .name = "CONNECTED",
191 .in_event_mask = S(BDC_E_TCP_DOWN),
192 .out_state_mask = S(BDC_ST_REESTABLISH),
193 .action = bdc_st_connected,
194 },
195 [BDC_ST_REESTABLISH] = {
196 .name = "REESTABLISH",
197 .in_event_mask = S(BDC_E_TCP_UP) | S(BDC_E_TCP_DOWN),
198 .out_state_mask = S(BDC_ST_ESTABLISHED) | S(BDC_ST_REESTABLISH),
199 .action = bdc_st_reestablish,
200 .onenter = bdc_st_reestablish_onenter,
201 },
202};
203
204struct osmo_fsm remsim_client_bankd_fsm = {
205 .name = "BANKD_CONN",
206 .states = bankd_conn_fsm_states,
207 .num_states = ARRAY_SIZE(bankd_conn_fsm_states),
208 .allstate_event_mask = S(BDC_E_ESTABLISH),
209 .allstate_action = bdc_allstate_action,
210 .timer_cb = remsim_client_bankd_fsm_timer_cb,
211 .log_subsys = DMAIN,
212 .event_names = remsim_client_bankd_fsm_event_names,
213};
214
215int bankd_conn_fsm_alloc(struct bankd_client *bc)
216{
217 struct osmo_fsm_inst *fi;
218
219 fi = osmo_fsm_inst_alloc(&remsim_client_bankd_fsm, bc, bc, LOGL_DEBUG, "bankd");
220 if (!fi)
221 return -1;
222
223 bc->bankd_fi = fi;
224 return 0;
225}
226
227static __attribute__((constructor)) void on_dso_load(void)
228{
229 osmo_fsm_register(&remsim_client_bankd_fsm);
230}