blob: 4fb57f31b1d93f26afd85fde8bc1314e5138b297 [file] [log] [blame]
Harald Welte24173fb2018-08-24 20:37:28 +02001#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
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_TCP_UP),
46 OSMO_VALUE_STRING(BDC_E_TCP_DOWN),
47 OSMO_VALUE_STRING(BDC_E_CLIENT_CONN_RES),
48 { 0, NULL }
49};
50
51#define T1_WAIT_CLIENT_CONN_RES 10
52#define T2_RECONNECT 10
53
54
55static void bdc_st_init_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
56{
57 struct bankd_client *bc = (struct bankd_client *) fi->priv;
58 int rc;
59
60 printf("onenter\n");
61 bc->bankd_conn = ipa_client_conn_create(bc, NULL, 0, bc->bankd_host, bc->bankd_port,
62 bankd_updown_cb, bankd_read_cb, NULL, bc);
63 if (!bc->bankd_conn) {
64 fprintf(stderr, "Unable to create socket: %s\n", strerror(errno));
65 exit(1);
66 }
67 /* Attempt to connect TCP socket */
68 rc = ipa_client_conn_open(bc->bankd_conn);
69 if (rc < 0) {
70 fprintf(stderr, "Unable to connect: %s\n", strerror(errno));
71 exit(1);
72 }
73}
74
75static void bdc_st_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
76{
77 switch (event) {
78 case BDC_E_TCP_UP:
79 osmo_fsm_inst_state_chg(fi, BDC_ST_ESTABLISHED, T1_WAIT_CLIENT_CONN_RES, 1);
80 break;
Harald Welte52cc7db2018-09-24 11:51:51 +020081 case BDC_E_TCP_DOWN:
82 osmo_fsm_inst_state_chg(fi, BDC_ST_REESTABLISH, T2_RECONNECT, 2);
83 break;
Harald Welte24173fb2018-08-24 20:37:28 +020084 default:
85 OSMO_ASSERT(0);
86 }
87}
88
89static void bdc_st_established_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
90{
91 struct bankd_client *bc = (struct bankd_client *) fi->priv;
92 RsproPDU_t *pdu;
93
94 /* FIXME: Send ClientConnReq */
Kévin Redon38cd4f72018-10-10 00:36:46 +020095 pdu = rspro_gen_ConnectClientReq(&bc->own_comp_id, bc->clslot);
Harald Weltef29e0d02018-08-24 21:42:22 +020096 ipa_client_conn_send_rspro(bc->bankd_conn, pdu);
Harald Welte24173fb2018-08-24 20:37:28 +020097}
98
99static void bdc_st_established(struct osmo_fsm_inst *fi, uint32_t event, void *data)
100{
101 switch (event) {
102 case BDC_E_TCP_DOWN:
103 osmo_fsm_inst_state_chg(fi, BDC_ST_REESTABLISH, T2_RECONNECT, 2);
104 break;
105 case BDC_E_CLIENT_CONN_RES:
106 /* somehow notify the main code? */
107 osmo_fsm_inst_state_chg(fi, BDC_ST_CONNECTED, 0, 0);
108 break;
109 default:
110 OSMO_ASSERT(0);
111 }
112}
113
114static void bdc_st_connected(struct osmo_fsm_inst *fi, uint32_t event, void *data)
115{
116 switch (event) {
117 case BDC_E_TCP_DOWN:
118 osmo_fsm_inst_state_chg(fi, BDC_ST_REESTABLISH, T2_RECONNECT, 2);
119 break;
120 default:
121 OSMO_ASSERT(0);
122 }
123}
124
125static void bdc_st_reestablish_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
126{
127 struct bankd_client *bc = (struct bankd_client *) fi->priv;
128 int rc;
129
130 /* Attempt to connect TCP socket */
131 rc = ipa_client_conn_open(bc->bankd_conn);
132 if (rc < 0) {
133 fprintf(stderr, "Unable to connect RSPRO to %s:%d - %s\n",
134 bc->bankd_conn->addr, bc->bankd_conn->port, strerror(errno));
135 /* FIXME: retry? Timer? Abort? */
136 OSMO_ASSERT(0);
137 }
138}
139
140static void bdc_st_reestablish(struct osmo_fsm_inst *fi, uint32_t event, void *data)
141{
142 switch (event) {
143 case BDC_E_TCP_UP:
144 osmo_fsm_inst_state_chg(fi, BDC_ST_ESTABLISHED, T1_WAIT_CLIENT_CONN_RES, 1);
145 break;
Harald Welte52cc7db2018-09-24 11:51:51 +0200146 case BDC_E_TCP_DOWN:
147 /* wait for normal T2 timeout */
148 break;
Harald Welte24173fb2018-08-24 20:37:28 +0200149 default:
150 OSMO_ASSERT(0);
151 }
152}
153
154static int remsim_client_bankd_fsm_timer_cb(struct osmo_fsm_inst *fi)
155{
Harald Welte52cc7db2018-09-24 11:51:51 +0200156 switch (fi->T) {
157 case 2:
158 osmo_fsm_inst_state_chg(fi, BDC_ST_REESTABLISH, T2_RECONNECT, 2);
159 break;
160 case 1:
161 /* FIXME: close connection and re-start */
162 break;
163 default:
164 OSMO_ASSERT(0);
165 }
Harald Welte24173fb2018-08-24 20:37:28 +0200166 return 0;
167}
168
169static const struct osmo_fsm_state bankd_conn_fsm_states[] = {
170 [BDC_ST_INIT] = {
171 .name = "INIT",
Harald Welte52cc7db2018-09-24 11:51:51 +0200172 .in_event_mask = S(BDC_E_TCP_UP) | S(BDC_E_TCP_DOWN),
173 .out_state_mask = S(BDC_ST_ESTABLISHED) | S(BDC_ST_REESTABLISH),
Harald Welte24173fb2018-08-24 20:37:28 +0200174 .action = bdc_st_init,
175 },
176 [BDC_ST_ESTABLISHED] = {
177 .name = "ESTABLISHED",
178 .in_event_mask = S(BDC_E_TCP_DOWN) | S(BDC_E_CLIENT_CONN_RES),
179 .out_state_mask = S(BDC_ST_CONNECTED) | S(BDC_ST_REESTABLISH),
180 .action = bdc_st_established,
181 .onenter = bdc_st_established_onenter,
182 },
183 [BDC_ST_CONNECTED] = {
184 .name = "CONNECTED",
185 .in_event_mask = S(BDC_E_TCP_DOWN),
186 .out_state_mask = S(BDC_ST_REESTABLISH),
187 .action = bdc_st_connected,
188 },
189 [BDC_ST_REESTABLISH] = {
190 .name = "REESTABLISH",
Harald Welte52cc7db2018-09-24 11:51:51 +0200191 .in_event_mask = S(BDC_E_TCP_UP) | S(BDC_E_TCP_DOWN),
192 .out_state_mask = S(BDC_ST_ESTABLISHED) | S(BDC_ST_REESTABLISH),
Harald Welte24173fb2018-08-24 20:37:28 +0200193 .action = bdc_st_reestablish,
194 .onenter = bdc_st_reestablish_onenter,
195 },
196};
197
198struct osmo_fsm remsim_client_bankd_fsm = {
199 .name = "BANKD_CONN",
200 .states = bankd_conn_fsm_states,
201 .num_states = ARRAY_SIZE(bankd_conn_fsm_states),
202 .timer_cb = remsim_client_bankd_fsm_timer_cb,
203 .log_subsys = DMAIN,
204 .event_names = remsim_client_bankd_fsm_event_names,
205};
206
207int bankd_conn_fsm_alloc(struct bankd_client *bc)
208{
209 struct osmo_fsm_inst *fi;
210
211 fi = osmo_fsm_inst_alloc(&remsim_client_bankd_fsm, bc, bc, LOGL_DEBUG, "bankd");
212 if (!fi)
213 return -1;
214
215 bc->bankd_fi = fi;
216 /* onenter of the initial state is not automatically executed by osmo_fsm :( */
217 bdc_st_init_onenter(fi, 0);
218 return 0;
219}
220
221/***********************************************************************
222 * server connection FSM
223 ***********************************************************************/
224
225enum server_conn_fsm_state {
226 /* waiting for initial connectiong to remsim-server */
227 SRVC_ST_INIT,
228 /* server connection established, waiting for ClientConnectRes */
229 SRVC_ST_ESTABLISHED,
230 /* server connection etsablished, ClientConnect succeeded */
231 SRVC_ST_CONNECTED,
232 /* connection lost, we're waiting for a re-establish */
233 SRVC_ST_REESTABLISH,
234};
235
236static const struct value_string server_conn_fsm_event_names[] = {
237 OSMO_VALUE_STRING(SRVC_E_TCP_UP),
238 OSMO_VALUE_STRING(SRVC_E_TCP_DOWN),
239 OSMO_VALUE_STRING(SRVC_E_CLIENT_CONN_RES),
240 { 0, NULL }
241};
242
Harald Welte84ba2342018-08-24 22:20:20 +0200243/* representing a client-side connection to a RSPRO server */
244struct rspro_server_conn {
245 /* state */
246 struct ipa_client_conn *conn;
247 struct osmo_fsm_inst *fi;
248
249 /* our own component ID */
250 struct app_comp_id own_comp_id;
251
252 /* configuration */
253 char *server_host;
254 uint16_t server_port;
255};
256
257static void srvc_updown_cb(struct ipa_client_conn *conn, int up)
258{
259 struct rspro_server_conn *srvc = conn->data;
260
261 printf("RSPRO link to %s:%d %s\n", conn->addr, conn->port, up ? "UP" : "DOWN");
262
263 osmo_fsm_inst_dispatch(srvc->fi, up ? SRVC_E_TCP_UP: SRVC_E_TCP_DOWN, 0);
264}
265
266static int srvc_read_cb(struct ipa_client_conn *conn, struct msgb *msg)
267{
268 struct ipaccess_head *hh = (struct ipaccess_head *) msg->data;
269 struct ipaccess_head_ext *he = (struct ipaccess_head_ext *) msgb_l2(msg);
270 struct rspro_server_conn *srvc = conn->data;
271 int rc;
272
273 if (msgb_length(msg) < sizeof(*hh))
274 goto invalid;
275 msg->l2h = &hh->data[0];
276 if (hh->proto != IPAC_PROTO_OSMO)
277 goto invalid;
278 if (!he || msgb_l2len(msg) < sizeof(*he))
279 goto invalid;
280 msg->l2h = &he->data[0];
281
282 if (he->proto != IPAC_PROTO_EXT_RSPRO)
283 goto invalid;
284
285 printf("Received RSPRO %s\n", msgb_hexdump(msg));
286#if 0
287 rc = bankd_handle_msg(srvc, msg);
288 msgb_free(msg);
289
290 return rc;
291#endif
292
293invalid:
294 msgb_free(msg);
295 return -1;
296}
297
298
299static void srvc_st_init_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
300{
301 struct rspro_server_conn *srvc = (struct rspro_server_conn *) fi->priv;
302 int rc;
303
304 srvc->conn = ipa_client_conn_create(srvc, NULL, 0, srvc->server_host, srvc->server_port,
305 srvc_updown_cb, srvc_read_cb, NULL, srvc);
306 if (!srvc->conn) {
307 fprintf(stderr, "Unable to create socket: %s\n", strerror(errno));
308 /* FIXME */
309 }
310 /* Attempt to connect TCP socket */
311 rc = ipa_client_conn_open(srvc->conn);
312 if (rc < 0) {
313 fprintf(stderr, "Unable to connect: %s\n", strerror(errno));
314 /* FIXME */
315 }
316}
Harald Welte24173fb2018-08-24 20:37:28 +0200317
318static void srvc_st_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
319{
Harald Welte84ba2342018-08-24 22:20:20 +0200320 switch (event) {
321 case SRVC_E_TCP_UP:
322 osmo_fsm_inst_state_chg(fi, SRVC_ST_ESTABLISHED, T1_WAIT_CLIENT_CONN_RES, 1);
323 break;
Harald Welte52cc7db2018-09-24 11:51:51 +0200324 case SRVC_E_TCP_DOWN:
325 osmo_fsm_inst_state_chg(fi, SRVC_ST_REESTABLISH, T2_RECONNECT, 2);
326 break;
Harald Welte84ba2342018-08-24 22:20:20 +0200327 default:
328 OSMO_ASSERT(0);
329 }
330}
331
332static void srvc_st_established_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
333{
334 struct rspro_server_conn *srvc = (struct rspro_server_conn *) fi->priv;
335 RsproPDU_t *pdu;
336
337 /* FIXME: Bankd in case of Bankd connection! */
338 pdu = rspro_gen_ConnectClientReq(&srvc->own_comp_id, NULL);
339 ipa_client_conn_send_rspro(srvc->conn, pdu);
Harald Welte24173fb2018-08-24 20:37:28 +0200340}
341
342static void srvc_st_established(struct osmo_fsm_inst *fi, uint32_t event, void *data)
343{
Harald Welte84ba2342018-08-24 22:20:20 +0200344 switch (event) {
345 case SRVC_E_TCP_DOWN:
346 osmo_fsm_inst_state_chg(fi, SRVC_ST_REESTABLISH, T2_RECONNECT, 2);
347 break;
348 case SRVC_E_CLIENT_CONN_RES:
349 /* somehow notify the main code? */
350 osmo_fsm_inst_state_chg(fi, SRVC_ST_CONNECTED, 0, 0);
351 break;
352 default:
353 OSMO_ASSERT(0);
354 }
Harald Welte24173fb2018-08-24 20:37:28 +0200355}
356
357static void srvc_st_connected(struct osmo_fsm_inst *fi, uint32_t event, void *data)
358{
Harald Welte84ba2342018-08-24 22:20:20 +0200359 switch (event) {
360 case SRVC_E_TCP_DOWN:
361 osmo_fsm_inst_state_chg(fi, SRVC_ST_REESTABLISH, T2_RECONNECT, 2);
362 break;
363 default:
364 OSMO_ASSERT(0);
365 }
366}
367
368static void srvc_st_reestablish_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
369{
370 struct rspro_server_conn *srvc = (struct rspro_server_conn *) fi->priv;
371 int rc;
372
373 /* Attempt to connect TCP socket */
374 rc = ipa_client_conn_open(srvc->conn);
375 if (rc < 0) {
376 fprintf(stderr, "Unable to connect RSPRO to %s:%d - %s\n",
377 srvc->server_host, srvc->server_port, strerror(errno));
378 /* FIXME: retry? Timer? Abort? */
379 OSMO_ASSERT(0);
380 }
Harald Welte24173fb2018-08-24 20:37:28 +0200381}
382
383static void srvc_st_reestablish(struct osmo_fsm_inst *fi, uint32_t event, void *data)
384{
Harald Welte84ba2342018-08-24 22:20:20 +0200385 switch (event) {
Harald Welte52cc7db2018-09-24 11:51:51 +0200386 case SRVC_E_TCP_UP:
Harald Welte84ba2342018-08-24 22:20:20 +0200387 osmo_fsm_inst_state_chg(fi, SRVC_ST_ESTABLISHED, T1_WAIT_CLIENT_CONN_RES, 1);
388 break;
Harald Welte52cc7db2018-09-24 11:51:51 +0200389 case SRVC_E_TCP_DOWN:
390 /* wait for normal T2 call-back */
391 break;
Harald Welte84ba2342018-08-24 22:20:20 +0200392 default:
393 OSMO_ASSERT(0);
394 }
Harald Welte24173fb2018-08-24 20:37:28 +0200395}
396
397static int server_conn_fsm_timer_cb(struct osmo_fsm_inst *fi)
398{
Harald Welte52cc7db2018-09-24 11:51:51 +0200399 switch (fi->T) {
400 case 2:
401 osmo_fsm_inst_state_chg(fi, SRVC_ST_REESTABLISH, T2_RECONNECT, 2);
402 break;
403 case 1:
404 /* FIXME: close connection and re-start connection attempt */
405 break;
406 default:
407 OSMO_ASSERT(0);
408 }
409
Harald Welte24173fb2018-08-24 20:37:28 +0200410 return 0;
411}
412
413static const struct osmo_fsm_state server_conn_fsm_states[] = {
414 [SRVC_ST_INIT] = {
415 .name = "INIT",
Harald Welte52cc7db2018-09-24 11:51:51 +0200416 .in_event_mask = S(SRVC_E_TCP_UP) | S(SRVC_E_TCP_DOWN),
417 .out_state_mask = S(SRVC_ST_ESTABLISHED) | S(SRVC_ST_REESTABLISH),
Harald Welte24173fb2018-08-24 20:37:28 +0200418 .action = srvc_st_init,
Harald Welte84ba2342018-08-24 22:20:20 +0200419 .onenter = srvc_st_init_onenter,
Harald Welte24173fb2018-08-24 20:37:28 +0200420 },
421 [SRVC_ST_ESTABLISHED] = {
422 .name = "ESTABLISHED",
423 .in_event_mask = S(SRVC_E_TCP_DOWN) | S(SRVC_E_CLIENT_CONN_RES),
424 .out_state_mask = S(SRVC_ST_CONNECTED) | S(SRVC_ST_REESTABLISH),
425 .action = srvc_st_established,
Harald Welte84ba2342018-08-24 22:20:20 +0200426 .onenter = srvc_st_established_onenter,
Harald Welte24173fb2018-08-24 20:37:28 +0200427 },
428 [SRVC_ST_CONNECTED] = {
429 .name = "CONNECTED",
430 .in_event_mask = S(SRVC_E_TCP_DOWN),
431 .out_state_mask = S(SRVC_ST_REESTABLISH),
432 .action = srvc_st_connected,
433 },
434 [SRVC_ST_REESTABLISH] = {
435 .name = "REESTABLISH",
Harald Welte52cc7db2018-09-24 11:51:51 +0200436 .in_event_mask = S(SRVC_E_TCP_UP) | S(SRVC_E_TCP_DOWN),
437 .out_state_mask = S(SRVC_ST_ESTABLISHED) | S(SRVC_ST_REESTABLISH),
Harald Welte24173fb2018-08-24 20:37:28 +0200438 .action = srvc_st_reestablish,
Harald Welte84ba2342018-08-24 22:20:20 +0200439 .onenter = srvc_st_reestablish_onenter,
Harald Welte24173fb2018-08-24 20:37:28 +0200440 },
441};
442
443struct osmo_fsm remsim_client_server_fsm = {
444 .name = "SERVER_CONN",
445 .states = server_conn_fsm_states,
446 .num_states = ARRAY_SIZE(server_conn_fsm_states),
447 .timer_cb = server_conn_fsm_timer_cb,
448 .log_subsys = DMAIN,
449 .event_names = server_conn_fsm_event_names,
450};
451
Harald Welte84ba2342018-08-24 22:20:20 +0200452int server_conn_fsm_alloc(struct rspro_server_conn *srvc)
Harald Welte24173fb2018-08-24 20:37:28 +0200453{
454 struct osmo_fsm_inst *fi;
455
Harald Welte84ba2342018-08-24 22:20:20 +0200456 fi = osmo_fsm_inst_alloc(&remsim_client_server_fsm, srvc, srvc, LOGL_DEBUG, "server");
Harald Welte24173fb2018-08-24 20:37:28 +0200457 if (!fi)
458 return -1;
459
Harald Welte84ba2342018-08-24 22:20:20 +0200460 srvc->fi = fi;
Harald Welte24173fb2018-08-24 20:37:28 +0200461 /* onenter of the initial state is not automatically executed by osmo_fsm :( */
Harald Welte84ba2342018-08-24 22:20:20 +0200462 srvc_st_init_onenter(fi, 0);
Harald Welte24173fb2018-08-24 20:37:28 +0200463 return 0;
464}