comparison euse-demo/osmo-euse-demo.c @ 0:d87e6dbd32c2

osmo-euse-demo compiles and links
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 01 Aug 2023 17:14:37 -0800
parents
children 2067c55e2c79
comparison
equal deleted inserted replaced
-1:000000000000 0:d87e6dbd32c2
1 /* osmo-demo-euse: An External USSD Entity (EUSE) for demo purpose */
2
3 /* (C) 2018 by Harald Welte <laforge@gnumonks.org>
4 *
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 /*
22 * This program illustrates how to implement an external USSD application using
23 * the existing osmocom libraries, particularly libosmocore, libosmogsm and libosmo-gsup-client.
24 *
25 * It will receive any MS-originated USSD message that is routed to it via the HLR, and
26 * simply respond it quoted in the following string: 'You sent "foobar"' (assuming the original
27 * message was 'foobar').
28 */
29
30 #include <string.h>
31 #include <stdio.h>
32 #include <errno.h>
33 #include <signal.h>
34
35 #include <osmocom/core/msgb.h>
36 #include <osmocom/core/select.h>
37 #include <osmocom/core/application.h>
38 #include <osmocom/core/utils.h>
39 #include <osmocom/core/logging.h>
40
41 #include <osmocom/gsm/gsup.h>
42 #include <osmocom/gsm/gsm0480.h>
43 #include <osmocom/gsm/protocol/gsm_04_80.h>
44
45 #include <osmocom/gsupclient/gsup_client.h>
46
47 /* logging categories */
48 enum {
49 DMAIN,
50 };
51
52 static struct osmo_gsup_client *g_gc;
53
54 /*! send a SS/USSD response to a given imsi/session.
55 * \param[in] gsupc GSUP client connection through which to send
56 * \param[in] imsi IMSI of the subscriber
57 * \param[in] session_id Unique identifier of SS session for which this response is
58 * \param[in] gsup_msg_type GSUP message type (OSMO_GSUP_MSGT_PROC_SS_{REQUEST,RESULT,ERROR})
59 * \param[in] final Is this the final result (true=END) or an intermediate result (false=CONTINUE)
60 * \param[in] msg Optional binary/BER encoded SS date (for FACILITY IE). Can be NULL. Freed in
61 * this function call.
62 */
63 static int euse_tx_ss(struct osmo_gsup_client *gsupc, const char *imsi, uint32_t session_id,
64 enum osmo_gsup_message_type gsup_msg_type, bool final, struct msgb *ss_msg)
65 {
66 struct osmo_gsup_message resp = {0};
67 struct msgb *resp_msg;
68
69 switch (gsup_msg_type) {
70 case OSMO_GSUP_MSGT_PROC_SS_REQUEST:
71 case OSMO_GSUP_MSGT_PROC_SS_RESULT:
72 case OSMO_GSUP_MSGT_PROC_SS_ERROR:
73 break;
74 default:
75 msgb_free(ss_msg);
76 return -EINVAL;
77 }
78
79 resp.message_type = gsup_msg_type;
80 OSMO_STRLCPY_ARRAY(resp.imsi, imsi);
81 if (final)
82 resp.session_state = OSMO_GSUP_SESSION_STATE_END;
83 else
84 resp.session_state = OSMO_GSUP_SESSION_STATE_CONTINUE;
85 resp.session_id = session_id;
86 if (ss_msg) {
87 resp.ss_info = msgb_data(ss_msg);
88 resp.ss_info_len = msgb_length(ss_msg);
89 }
90
91 resp_msg = gsm0480_msgb_alloc_name(__func__);
92 OSMO_ASSERT(resp_msg);
93 osmo_gsup_encode(resp_msg, &resp);
94 msgb_free(ss_msg);
95 return osmo_gsup_client_send(gsupc, resp_msg);
96 }
97
98 /*! send a SS/USSD reject to a given IMSI/session.
99 * \param[in] gsupc GSUP client connection through which to send
100 * \param[in] imsi IMSI of the subscriber
101 * \param[in] session_id Unique identifier of SS session for which this response is
102 * \param[in] invoke_id InvokeID of the request
103 * \param[in] problem_tag Problem code tag (table 3.13)
104 * \param[in] problem_code Problem code (table 3.14-3.17)
105 */
106 static int euse_tx_ussd_reject(struct osmo_gsup_client *gsupc, const char *imsi, uint32_t session_id,
107 int invoke_id, uint8_t problem_tag, uint8_t problem_code)
108 {
109 struct msgb *msg = gsm0480_gen_reject(invoke_id, problem_tag, problem_code);
110 LOGP(DMAIN, LOGL_NOTICE, "Tx %s/0x%08x: Reject(%d, 0x%02x, 0x%02x)\n", imsi, session_id,
111 invoke_id, problem_tag, problem_code);
112 OSMO_ASSERT(msg);
113 return euse_tx_ss(gsupc, imsi, session_id, OSMO_GSUP_MSGT_PROC_SS_RESULT, true, msg);
114 }
115
116 /*! send a SS/USSD response in 7-bit GSM default alphabet o a given imsi/session.
117 * \param[in] gsupc GSUP client connection through which to send
118 * \param[in] imsi IMSI of the subscriber
119 * \param[in] session_id Unique identifier of SS session for which this response is
120 * \param[in] final Is this the final result (true=END) or an intermediate result
121 * (false=CONTINUE)
122 * \param[in] invoke_id InvokeID of the request
123 */
124 static int euse_tx_ussd_resp_7bit(struct osmo_gsup_client *gsupc, const char *imsi, uint32_t session_id,
125 bool final, uint8_t invoke_id, const char *text)
126 {
127 struct msgb *ss_msg;
128
129 /* encode response; remove L3 header */
130 ss_msg = gsm0480_gen_ussd_resp_7bit(invoke_id, text);
131 LOGP(DMAIN, LOGL_DEBUG, "Tx %s/0x%08x: USSD Result(%d, %s, '%s')\n", imsi, session_id,
132 invoke_id, final ? "END" : "CONTINUE", text);
133 OSMO_ASSERT(ss_msg);
134 return euse_tx_ss(gsupc, imsi, session_id, OSMO_GSUP_MSGT_PROC_SS_RESULT, final, ss_msg);
135 }
136
137 static int euse_rx_proc_ss_req(struct osmo_gsup_client *gsupc, const struct osmo_gsup_message *gsup)
138 {
139 char buf[GSM0480_USSD_7BIT_STRING_LEN+1];
140 struct ss_request req = {0};
141
142 if (gsup->ss_info && gsup->ss_info_len) {
143 if (gsm0480_parse_facility_ie(gsup->ss_info, gsup->ss_info_len, &req)) {
144 return euse_tx_ussd_reject(gsupc, gsup->imsi, gsup->session_id, -1,
145 GSM_0480_PROBLEM_CODE_TAG_GENERAL,
146 GSM_0480_GEN_PROB_CODE_BAD_STRUCTURE);
147 }
148 }
149
150 LOGP(DMAIN, LOGL_INFO, "Rx %s/0x%08x: USSD SessionState=%s, OpCode=%s, '%s'\n", gsup->imsi,
151 gsup->session_id, osmo_gsup_session_state_name(gsup->session_state),
152 gsm0480_op_code_name(req.opcode), req.ussd_text);
153
154 /* we only handle single-request-response USSD in this demo */
155 if (gsup->session_state != OSMO_GSUP_SESSION_STATE_BEGIN) {
156 return euse_tx_ussd_reject(gsupc, gsup->imsi, gsup->session_id, req.invoke_id,
157 GSM_0480_PROBLEM_CODE_TAG_GENERAL,
158 GSM_0480_GEN_PROB_CODE_UNRECOGNISED);
159 }
160
161 snprintf(buf, sizeof(buf), "You sent \"%s\"", req.ussd_text);
162 return euse_tx_ussd_resp_7bit(gsupc, gsup->imsi, gsup->session_id, true, req.invoke_id, buf);
163 }
164
165 static int gsupc_read_cb(struct osmo_gsup_client *gsupc, struct msgb *msg)
166 {
167 struct osmo_gsup_message gsup_msg = {0};
168 int rc;
169
170 rc = osmo_gsup_decode(msgb_l2(msg), msgb_l2len(msg), &gsup_msg);
171 if (rc < 0) {
172 LOGP(DMAIN, LOGL_ERROR, "Error decoding GSUP: %s\n", msgb_hexdump(msg));
173 return rc;
174 }
175 DEBUGP(DMAIN, "Rx GSUP %s: %s\n", osmo_gsup_message_type_name(gsup_msg.message_type),
176 msgb_hexdump(msg));
177
178 switch (gsup_msg.message_type) {
179 case OSMO_GSUP_MSGT_PROC_SS_REQUEST:
180 case OSMO_GSUP_MSGT_PROC_SS_RESULT:
181 euse_rx_proc_ss_req(gsupc, &gsup_msg);
182 break;
183 case OSMO_GSUP_MSGT_PROC_SS_ERROR:
184 break;
185 default:
186 LOGP(DMAIN, LOGL_DEBUG, "Unhandled GSUP message type %s\n",
187 osmo_gsup_message_type_name(gsup_msg.message_type));
188 break;
189 }
190
191 msgb_free(msg);
192 return 0;
193 }
194
195
196 static struct log_info_cat default_categories[] = {
197 [DMAIN] = {
198 .name = "DMAIN",
199 .description = "Main Program",
200 .enabled = 1, .loglevel = LOGL_DEBUG,
201 },
202 };
203
204 static const struct log_info gsup_log_info = {
205 .cat = default_categories,
206 .num_cat = ARRAY_SIZE(default_categories),
207 };
208
209 static void print_usage(void)
210 {
211 printf("Usage: osmo-euse-demo [hlr-ip [hlr-gsup-port]]\n");
212 }
213
214 int main(int argc, char **argv)
215 {
216 char *server_host = "127.0.0.1";
217 uint16_t server_port = OSMO_GSUP_PORT;
218 void *ctx = talloc_named_const(NULL, 0, "demo-euse");
219
220 osmo_init_logging2(ctx, &gsup_log_info);
221
222 printf("argc=%d\n", argc);
223
224 if (argc > 1) {
225 if (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")) {
226 print_usage();
227 exit(0);
228 } else
229 server_host = argv[1];
230 }
231 if (argc > 2)
232 server_port = atoi(argv[2]);
233
234 g_gc = osmo_gsup_client_create(ctx, "EUSE-foobar", server_host, server_port, gsupc_read_cb, NULL);
235
236 while (1) {
237 osmo_select_main(0);
238 }
239
240 exit(0);
241 }
242