summaryrefslogtreecommitdiff
path: root/src/devices/bluetooth/tests/nm-bt-test.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bluetooth/tests/nm-bt-test.c')
-rw-r--r--src/devices/bluetooth/tests/nm-bt-test.c220
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;
+}