blob: fc776eda98d0980fa6ba8e899b9f932b81e7f920 [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;
81 default:
82 OSMO_ASSERT(0);
83 }
84}
85
86static void bdc_st_established_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
87{
88 struct bankd_client *bc = (struct bankd_client *) fi->priv;
89 RsproPDU_t *pdu;
90
91 /* FIXME: Send ClientConnReq */
92 const ClientSlot_t clslot = { .clientId = 23, .slotNr = 1 };
93 pdu = rspro_gen_ConnectClientReq(&bc->own_comp_id, &clslot);
Harald Weltef29e0d02018-08-24 21:42:22 +020094 ipa_client_conn_send_rspro(bc->bankd_conn, pdu);
Harald Welte24173fb2018-08-24 20:37:28 +020095}
96
97static void bdc_st_established(struct osmo_fsm_inst *fi, uint32_t event, void *data)
98{
99 switch (event) {
100 case BDC_E_TCP_DOWN:
101 osmo_fsm_inst_state_chg(fi, BDC_ST_REESTABLISH, T2_RECONNECT, 2);
102 break;
103 case BDC_E_CLIENT_CONN_RES:
104 /* somehow notify the main code? */
105 osmo_fsm_inst_state_chg(fi, BDC_ST_CONNECTED, 0, 0);
106 break;
107 default:
108 OSMO_ASSERT(0);
109 }
110}
111
112static void bdc_st_connected(struct osmo_fsm_inst *fi, uint32_t event, void *data)
113{
114 switch (event) {
115 case BDC_E_TCP_DOWN:
116 osmo_fsm_inst_state_chg(fi, BDC_ST_REESTABLISH, T2_RECONNECT, 2);
117 break;
118 default:
119 OSMO_ASSERT(0);
120 }
121}
122
123static void bdc_st_reestablish_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
124{
125 struct bankd_client *bc = (struct bankd_client *) fi->priv;
126 int rc;
127
128 /* Attempt to connect TCP socket */
129 rc = ipa_client_conn_open(bc->bankd_conn);
130 if (rc < 0) {
131 fprintf(stderr, "Unable to connect RSPRO to %s:%d - %s\n",
132 bc->bankd_conn->addr, bc->bankd_conn->port, strerror(errno));
133 /* FIXME: retry? Timer? Abort? */
134 OSMO_ASSERT(0);
135 }
136}
137
138static void bdc_st_reestablish(struct osmo_fsm_inst *fi, uint32_t event, void *data)
139{
140 switch (event) {
141 case BDC_E_TCP_UP:
142 osmo_fsm_inst_state_chg(fi, BDC_ST_ESTABLISHED, T1_WAIT_CLIENT_CONN_RES, 1);
143 break;
144 default:
145 OSMO_ASSERT(0);
146 }
147}
148
149static int remsim_client_bankd_fsm_timer_cb(struct osmo_fsm_inst *fi)
150{
151 return 0;
152}
153
154static const struct osmo_fsm_state bankd_conn_fsm_states[] = {
155 [BDC_ST_INIT] = {
156 .name = "INIT",
157 .in_event_mask = S(BDC_E_TCP_UP),
158 .out_state_mask = S(BDC_ST_ESTABLISHED),
159 .action = bdc_st_init,
160 },
161 [BDC_ST_ESTABLISHED] = {
162 .name = "ESTABLISHED",
163 .in_event_mask = S(BDC_E_TCP_DOWN) | S(BDC_E_CLIENT_CONN_RES),
164 .out_state_mask = S(BDC_ST_CONNECTED) | S(BDC_ST_REESTABLISH),
165 .action = bdc_st_established,
166 .onenter = bdc_st_established_onenter,
167 },
168 [BDC_ST_CONNECTED] = {
169 .name = "CONNECTED",
170 .in_event_mask = S(BDC_E_TCP_DOWN),
171 .out_state_mask = S(BDC_ST_REESTABLISH),
172 .action = bdc_st_connected,
173 },
174 [BDC_ST_REESTABLISH] = {
175 .name = "REESTABLISH",
176 .in_event_mask = S(BDC_E_TCP_UP),
177 .out_state_mask = S(BDC_ST_ESTABLISHED),
178 .action = bdc_st_reestablish,
179 .onenter = bdc_st_reestablish_onenter,
180 },
181};
182
183struct osmo_fsm remsim_client_bankd_fsm = {
184 .name = "BANKD_CONN",
185 .states = bankd_conn_fsm_states,
186 .num_states = ARRAY_SIZE(bankd_conn_fsm_states),
187 .timer_cb = remsim_client_bankd_fsm_timer_cb,
188 .log_subsys = DMAIN,
189 .event_names = remsim_client_bankd_fsm_event_names,
190};
191
192int bankd_conn_fsm_alloc(struct bankd_client *bc)
193{
194 struct osmo_fsm_inst *fi;
195
196 fi = osmo_fsm_inst_alloc(&remsim_client_bankd_fsm, bc, bc, LOGL_DEBUG, "bankd");
197 if (!fi)
198 return -1;
199
200 bc->bankd_fi = fi;
201 /* onenter of the initial state is not automatically executed by osmo_fsm :( */
202 bdc_st_init_onenter(fi, 0);
203 return 0;
204}
205
206/***********************************************************************
207 * server connection FSM
208 ***********************************************************************/
209
210enum server_conn_fsm_state {
211 /* waiting for initial connectiong to remsim-server */
212 SRVC_ST_INIT,
213 /* server connection established, waiting for ClientConnectRes */
214 SRVC_ST_ESTABLISHED,
215 /* server connection etsablished, ClientConnect succeeded */
216 SRVC_ST_CONNECTED,
217 /* connection lost, we're waiting for a re-establish */
218 SRVC_ST_REESTABLISH,
219};
220
221static const struct value_string server_conn_fsm_event_names[] = {
222 OSMO_VALUE_STRING(SRVC_E_TCP_UP),
223 OSMO_VALUE_STRING(SRVC_E_TCP_DOWN),
224 OSMO_VALUE_STRING(SRVC_E_CLIENT_CONN_RES),
225 { 0, NULL }
226};
227
Harald Welte84ba2342018-08-24 22:20:20 +0200228/* representing a client-side connection to a RSPRO server */
229struct rspro_server_conn {
230 /* state */
231 struct ipa_client_conn *conn;
232 struct osmo_fsm_inst *fi;
233
234 /* our own component ID */
235 struct app_comp_id own_comp_id;
236
237 /* configuration */
238 char *server_host;
239 uint16_t server_port;
240};
241
242static void srvc_updown_cb(struct ipa_client_conn *conn, int up)
243{
244 struct rspro_server_conn *srvc = conn->data;
245
246 printf("RSPRO link to %s:%d %s\n", conn->addr, conn->port, up ? "UP" : "DOWN");
247
248 osmo_fsm_inst_dispatch(srvc->fi, up ? SRVC_E_TCP_UP: SRVC_E_TCP_DOWN, 0);
249}
250
251static int srvc_read_cb(struct ipa_client_conn *conn, struct msgb *msg)
252{
253 struct ipaccess_head *hh = (struct ipaccess_head *) msg->data;
254 struct ipaccess_head_ext *he = (struct ipaccess_head_ext *) msgb_l2(msg);
255 struct rspro_server_conn *srvc = conn->data;
256 int rc;
257
258 if (msgb_length(msg) < sizeof(*hh))
259 goto invalid;
260 msg->l2h = &hh->data[0];
261 if (hh->proto != IPAC_PROTO_OSMO)
262 goto invalid;
263 if (!he || msgb_l2len(msg) < sizeof(*he))
264 goto invalid;
265 msg->l2h = &he->data[0];
266
267 if (he->proto != IPAC_PROTO_EXT_RSPRO)
268 goto invalid;
269
270 printf("Received RSPRO %s\n", msgb_hexdump(msg));
271#if 0
272 rc = bankd_handle_msg(srvc, msg);
273 msgb_free(msg);
274
275 return rc;
276#endif
277
278invalid:
279 msgb_free(msg);
280 return -1;
281}
282
283
284static void srvc_st_init_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
285{
286 struct rspro_server_conn *srvc = (struct rspro_server_conn *) fi->priv;
287 int rc;
288
289 srvc->conn = ipa_client_conn_create(srvc, NULL, 0, srvc->server_host, srvc->server_port,
290 srvc_updown_cb, srvc_read_cb, NULL, srvc);
291 if (!srvc->conn) {
292 fprintf(stderr, "Unable to create socket: %s\n", strerror(errno));
293 /* FIXME */
294 }
295 /* Attempt to connect TCP socket */
296 rc = ipa_client_conn_open(srvc->conn);
297 if (rc < 0) {
298 fprintf(stderr, "Unable to connect: %s\n", strerror(errno));
299 /* FIXME */
300 }
301}
Harald Welte24173fb2018-08-24 20:37:28 +0200302
303static void srvc_st_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
304{
Harald Welte84ba2342018-08-24 22:20:20 +0200305 switch (event) {
306 case SRVC_E_TCP_UP:
307 osmo_fsm_inst_state_chg(fi, SRVC_ST_ESTABLISHED, T1_WAIT_CLIENT_CONN_RES, 1);
308 break;
309 default:
310 OSMO_ASSERT(0);
311 }
312}
313
314static void srvc_st_established_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
315{
316 struct rspro_server_conn *srvc = (struct rspro_server_conn *) fi->priv;
317 RsproPDU_t *pdu;
318
319 /* FIXME: Bankd in case of Bankd connection! */
320 pdu = rspro_gen_ConnectClientReq(&srvc->own_comp_id, NULL);
321 ipa_client_conn_send_rspro(srvc->conn, pdu);
Harald Welte24173fb2018-08-24 20:37:28 +0200322}
323
324static void srvc_st_established(struct osmo_fsm_inst *fi, uint32_t event, void *data)
325{
Harald Welte84ba2342018-08-24 22:20:20 +0200326 switch (event) {
327 case SRVC_E_TCP_DOWN:
328 osmo_fsm_inst_state_chg(fi, SRVC_ST_REESTABLISH, T2_RECONNECT, 2);
329 break;
330 case SRVC_E_CLIENT_CONN_RES:
331 /* somehow notify the main code? */
332 osmo_fsm_inst_state_chg(fi, SRVC_ST_CONNECTED, 0, 0);
333 break;
334 default:
335 OSMO_ASSERT(0);
336 }
Harald Welte24173fb2018-08-24 20:37:28 +0200337}
338
339static void srvc_st_connected(struct osmo_fsm_inst *fi, uint32_t event, void *data)
340{
Harald Welte84ba2342018-08-24 22:20:20 +0200341 switch (event) {
342 case SRVC_E_TCP_DOWN:
343 osmo_fsm_inst_state_chg(fi, SRVC_ST_REESTABLISH, T2_RECONNECT, 2);
344 break;
345 default:
346 OSMO_ASSERT(0);
347 }
348}
349
350static void srvc_st_reestablish_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
351{
352 struct rspro_server_conn *srvc = (struct rspro_server_conn *) fi->priv;
353 int rc;
354
355 /* Attempt to connect TCP socket */
356 rc = ipa_client_conn_open(srvc->conn);
357 if (rc < 0) {
358 fprintf(stderr, "Unable to connect RSPRO to %s:%d - %s\n",
359 srvc->server_host, srvc->server_port, strerror(errno));
360 /* FIXME: retry? Timer? Abort? */
361 OSMO_ASSERT(0);
362 }
Harald Welte24173fb2018-08-24 20:37:28 +0200363}
364
365static void srvc_st_reestablish(struct osmo_fsm_inst *fi, uint32_t event, void *data)
366{
Harald Welte84ba2342018-08-24 22:20:20 +0200367 switch (event) {
368 case BDC_E_TCP_UP:
369 osmo_fsm_inst_state_chg(fi, SRVC_ST_ESTABLISHED, T1_WAIT_CLIENT_CONN_RES, 1);
370 break;
371 default:
372 OSMO_ASSERT(0);
373 }
Harald Welte24173fb2018-08-24 20:37:28 +0200374}
375
376static int server_conn_fsm_timer_cb(struct osmo_fsm_inst *fi)
377{
378 return 0;
379}
380
381static const struct osmo_fsm_state server_conn_fsm_states[] = {
382 [SRVC_ST_INIT] = {
383 .name = "INIT",
384 .in_event_mask = S(SRVC_E_TCP_UP),
385 .out_state_mask = S(SRVC_ST_ESTABLISHED),
386 .action = srvc_st_init,
Harald Welte84ba2342018-08-24 22:20:20 +0200387 .onenter = srvc_st_init_onenter,
Harald Welte24173fb2018-08-24 20:37:28 +0200388 },
389 [SRVC_ST_ESTABLISHED] = {
390 .name = "ESTABLISHED",
391 .in_event_mask = S(SRVC_E_TCP_DOWN) | S(SRVC_E_CLIENT_CONN_RES),
392 .out_state_mask = S(SRVC_ST_CONNECTED) | S(SRVC_ST_REESTABLISH),
393 .action = srvc_st_established,
Harald Welte84ba2342018-08-24 22:20:20 +0200394 .onenter = srvc_st_established_onenter,
Harald Welte24173fb2018-08-24 20:37:28 +0200395 },
396 [SRVC_ST_CONNECTED] = {
397 .name = "CONNECTED",
398 .in_event_mask = S(SRVC_E_TCP_DOWN),
399 .out_state_mask = S(SRVC_ST_REESTABLISH),
400 .action = srvc_st_connected,
401 },
402 [SRVC_ST_REESTABLISH] = {
403 .name = "REESTABLISH",
404 .in_event_mask = S(SRVC_E_TCP_UP),
405 .out_state_mask = S(SRVC_ST_ESTABLISHED),
406 .action = srvc_st_reestablish,
Harald Welte84ba2342018-08-24 22:20:20 +0200407 .onenter = srvc_st_reestablish_onenter,
Harald Welte24173fb2018-08-24 20:37:28 +0200408 },
409};
410
411struct osmo_fsm remsim_client_server_fsm = {
412 .name = "SERVER_CONN",
413 .states = server_conn_fsm_states,
414 .num_states = ARRAY_SIZE(server_conn_fsm_states),
415 .timer_cb = server_conn_fsm_timer_cb,
416 .log_subsys = DMAIN,
417 .event_names = server_conn_fsm_event_names,
418};
419
Harald Welte84ba2342018-08-24 22:20:20 +0200420int server_conn_fsm_alloc(struct rspro_server_conn *srvc)
Harald Welte24173fb2018-08-24 20:37:28 +0200421{
422 struct osmo_fsm_inst *fi;
423
Harald Welte84ba2342018-08-24 22:20:20 +0200424 fi = osmo_fsm_inst_alloc(&remsim_client_server_fsm, srvc, srvc, LOGL_DEBUG, "server");
Harald Welte24173fb2018-08-24 20:37:28 +0200425 if (!fi)
426 return -1;
427
Harald Welte84ba2342018-08-24 22:20:20 +0200428 srvc->fi = fi;
Harald Welte24173fb2018-08-24 20:37:28 +0200429 /* onenter of the initial state is not automatically executed by osmo_fsm :( */
Harald Welte84ba2342018-08-24 22:20:20 +0200430 srvc_st_init_onenter(fi, 0);
Harald Welte24173fb2018-08-24 20:37:28 +0200431 return 0;
432}