diff options
Diffstat (limited to 'src/devices/bluetooth/tests/nm-bt-test.c')
-rw-r--r-- | src/devices/bluetooth/tests/nm-bt-test.c | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/src/devices/bluetooth/tests/nm-bt-test.c b/src/devices/bluetooth/tests/nm-bt-test.c new file mode 100644 index 0000000000..02cfd2288f --- /dev/null +++ b/src/devices/bluetooth/tests/nm-bt-test.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: LGPL-2.1+ + +#include "nm-default.h" + +#include <glib-unix.h> + +#include "devices/bluetooth/nm-bluez5-dun.h" + +#include "nm-test-utils-core.h" + +/*****************************************************************************/ + +#define _NMLOG_DOMAIN LOGD_BT +#define _NMLOG(level, ...) \ + nm_log ((level), _NMLOG_DOMAIN, \ + NULL, NULL, \ + "bt%s%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + NM_PRINT_FMT_QUOTED (gl.argv_cmd, "[", gl.argv_cmd, "]", "") \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)) + +/*****************************************************************************/ + +struct { + int argc; + const char *const*argv; + const char *argv_cmd; + GMainLoop *loop; +} gl; + +typedef struct _MainCmdInfo { + const char *name; + int (*main_func) (const struct _MainCmdInfo *main_cmd_info); +} MainCmdInfo; + +/*****************************************************************************/ + +#if WITH_BLUEZ5_DUN + +typedef struct { + NMBluez5DunContext *dun_context; + GCancellable *cancellable; + guint timeout_id; + guint sig_term_id; + guint sig_int_id; +} DunConnectData; + +static void +_dun_connect_cb (NMBluez5DunContext *context, + const char *rfcomm_dev, + GError *error, + gpointer user_data) +{ + DunConnectData *dun_connect_data = user_data; + + g_assert (dun_connect_data); + g_assert (!dun_connect_data->dun_context); + g_assert ((!!error) != (!!rfcomm_dev)); + + if (rfcomm_dev && !context) { + _LOGI ("dun-connect notifies path \"%s\". Wait longer...", rfcomm_dev); + return; + } + + if (rfcomm_dev) { + g_assert (context); + _LOGI ("dun-connect completed with path \"%s\"", rfcomm_dev); + } else { + g_assert (!context); + _LOGI ("dun-connect failed with error: %s", error->message); + } + + dun_connect_data->dun_context = context; + + g_main_loop_quit (gl.loop); +} + +static void +_dun_notify_tty_hangup_cb (NMBluez5DunContext *context, + gpointer user_data) +{ + _LOGI ("dun-connect: notified TTY hangup"); +} + +static gboolean +_timeout_cb (gpointer user_data) +{ + DunConnectData *dun_connect_data = user_data; + + _LOGI ("timeout"); + dun_connect_data->timeout_id = 0; + if (dun_connect_data->cancellable) + g_cancellable_cancel (dun_connect_data->cancellable); + return G_SOURCE_REMOVE; +} + +static gboolean +_sig_xxx_cb (DunConnectData *dun_connect_data, int sigid) +{ + _LOGI ("signal %s received", sigid == SIGTERM ? "SIGTERM" : "SIGINT"); + g_main_loop_quit (gl.loop); + return G_SOURCE_CONTINUE; +} + +static gboolean +_sig_term_cb (gpointer user_data) +{ + return _sig_xxx_cb (user_data, SIGTERM); +} + +static gboolean +_sig_int_cb (gpointer user_data) +{ + return _sig_xxx_cb (user_data, SIGINT); +} +#endif + +static int +do_dun_connect (const MainCmdInfo *main_cmd_info) +{ +#if WITH_BLUEZ5_DUN + gs_unref_object GCancellable *cancellable = NULL; + gs_free_error GError *error = NULL; + const char *adapter; + const char *remote; + DunConnectData dun_connect_data = { }; + + if (gl.argc < 4) { + _LOGE ("missing arguments \"adapter\" and \"remote\""); + return -1; + } + + adapter = gl.argv[2]; + remote = gl.argv[3]; + + cancellable = g_cancellable_new (); + dun_connect_data.cancellable = cancellable; + + if (!nm_bluez5_dun_connect (adapter, + remote, + cancellable, + _dun_connect_cb, + &dun_connect_data, + _dun_notify_tty_hangup_cb, + &dun_connect_data, + &error)) { + _LOGE ("connect failed to start: %s", error->message); + return -1; + } + + dun_connect_data.timeout_id = g_timeout_add (60000, _timeout_cb, &dun_connect_data); + + g_main_loop_run (gl.loop); + + nm_clear_g_source (&dun_connect_data.timeout_id); + + if (dun_connect_data.dun_context) { + + dun_connect_data.sig_term_id = g_unix_signal_add (SIGTERM, _sig_term_cb, &dun_connect_data); + dun_connect_data.sig_int_id = g_unix_signal_add (SIGINT, _sig_int_cb, &dun_connect_data); + + g_main_loop_run (gl.loop); + + nm_clear_g_source (&dun_connect_data.sig_term_id); + nm_clear_g_source (&dun_connect_data.sig_int_id); + + nm_bluez5_dun_disconnect (g_steal_pointer (&dun_connect_data.dun_context)); + } + + return 0; +#else + _LOGE ("compiled without bluetooth DUN support"); + return 1; +#endif +} + +/*****************************************************************************/ + +NMTST_DEFINE (); + +int +main (int argc, char **argv) +{ + static const MainCmdInfo main_cmd_infos[] = { + { .name = "dun-connect", .main_func = do_dun_connect, }, + }; + int exit_code = 0; + guint i; + + if (!g_getenv ("G_MESSAGES_DEBUG")) + g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); + + nmtst_init_with_logging (&argc, &argv, "DEBUG", "ALL"); + + nm_logging_init (NULL, TRUE); + + gl.argv = (const char *const*) argv; + gl.argc = argc; + gl.loop = g_main_loop_new (NULL, FALSE); + + _LOGI ("bluetooth test util start"); + + gl.argv_cmd = argc >= 2 ? argv[1] : NULL; + + for (i = 0; i < G_N_ELEMENTS (main_cmd_infos); i++) { + if (nm_streq0 (main_cmd_infos[i].name, gl.argv_cmd)) { + _LOGD ("start \"%s\"", gl.argv_cmd); + exit_code = main_cmd_infos[i].main_func (&main_cmd_infos[i]); + _LOGD ("completed with %d", exit_code); + break; + } + } + if (gl.argv_cmd && i >= G_N_ELEMENTS (main_cmd_infos)) { + nm_log_err (LOGD_BT, "invalid command \"%s\"", gl.argv_cmd); + exit_code = -1; + } + + nm_clear_pointer (&gl.loop, g_main_loop_unref); + + return exit_code; +} |