Home | History | Annotate | Download | only in test
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2009-2010  Marcel Holtmann <marcel (at) holtmann.org>
      6  *  Copyright (C) 2009-2010  Nokia Corporation
      7  *
      8  *
      9  *  This program is free software; you can redistribute it and/or modify
     10  *  it under the terms of the GNU General Public License as published by
     11  *  the Free Software Foundation; either version 2 of the License, or
     12  *  (at your option) any later version.
     13  *
     14  *  This program is distributed in the hope that it will be useful,
     15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  *  GNU General Public License for more details.
     18  *
     19  *  You should have received a copy of the GNU General Public License
     20  *  along with this program; if not, write to the Free Software
     21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     22  *
     23  */
     24 #include <stdio.h>
     25 #include <stdlib.h>
     26 #include <stdint.h>
     27 #include <errno.h>
     28 #include <string.h>
     29 #include <signal.h>
     30 
     31 #include <glib.h>
     32 
     33 #include "btio.h"
     34 
     35 #define DEFAULT_ACCEPT_TIMEOUT 2
     36 
     37 struct io_data {
     38 	guint ref;
     39 	GIOChannel *io;
     40 	BtIOType type;
     41 	gint reject;
     42 	gint disconn;
     43 	gint accept;
     44 };
     45 
     46 static void io_data_unref(struct io_data *data)
     47 {
     48 	data->ref--;
     49 
     50 	if (data->ref)
     51 		return;
     52 
     53 	if (data->io)
     54 		g_io_channel_unref(data->io);
     55 
     56 	g_free(data);
     57 }
     58 
     59 static struct io_data *io_data_ref(struct io_data *data)
     60 {
     61 	data->ref++;
     62 	return data;
     63 }
     64 
     65 static struct io_data *io_data_new(GIOChannel *io, BtIOType type, gint reject,
     66 						gint disconn, gint accept)
     67 {
     68 	struct io_data *data;
     69 
     70 	data = g_new0(struct io_data, 1);
     71 	data->io = io;
     72 	data->type = type;
     73 	data->reject = reject;
     74 	data->disconn = disconn;
     75 	data->accept = accept;
     76 
     77 	return io_data_ref(data);
     78 }
     79 
     80 static gboolean io_watch(GIOChannel *io, GIOCondition cond, gpointer user_data)
     81 {
     82 	printf("Disconnected\n");
     83 	return FALSE;
     84 }
     85 
     86 static gboolean disconn_timeout(gpointer user_data)
     87 {
     88 	struct io_data *data = user_data;
     89 
     90 	printf("Disconnecting\n");
     91 
     92 	g_io_channel_shutdown(data->io, TRUE, NULL);
     93 
     94 	return FALSE;
     95 }
     96 
     97 static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
     98 {
     99 	struct io_data *data = user_data;
    100 	GIOCondition cond;
    101 	char addr[18];
    102 	uint16_t handle;
    103 	uint8_t cls[3];
    104 
    105 	if (err) {
    106 		printf("Connecting failed: %s\n", err->message);
    107 		return;
    108 	}
    109 
    110 	if (!bt_io_get(io, data->type, &err,
    111 			BT_IO_OPT_DEST, addr,
    112 			BT_IO_OPT_HANDLE, &handle,
    113 			BT_IO_OPT_CLASS, cls,
    114 			BT_IO_OPT_INVALID)) {
    115 		printf("Unable to get destination address: %s\n",
    116 								err->message);
    117 		g_clear_error(&err);
    118 		strcpy(addr, "(unknown)");
    119 	}
    120 
    121 	printf("Successfully connected to %s. handle=%u, class=%02x%02x%02x\n",
    122 			addr, handle, cls[0], cls[1], cls[2]);
    123 
    124 	if (data->type == BT_IO_L2CAP || data->type == BT_IO_SCO) {
    125 		uint16_t omtu, imtu;
    126 
    127 		if (!bt_io_get(io, data->type, &err,
    128 					BT_IO_OPT_OMTU, &omtu,
    129 					BT_IO_OPT_IMTU, &imtu,
    130 					BT_IO_OPT_INVALID)) {
    131 			printf("Unable to get L2CAP MTU sizes: %s\n",
    132 								err->message);
    133 			g_clear_error(&err);
    134 		} else
    135 			printf("imtu=%u, omtu=%u\n", imtu, omtu);
    136 	}
    137 
    138 	if (data->disconn == 0) {
    139 		g_io_channel_shutdown(io, TRUE, NULL);
    140 		printf("Disconnected\n");
    141 		return;
    142 	}
    143 
    144 	if (data->io == NULL)
    145 		data->io = g_io_channel_ref(io);
    146 
    147 	if (data->disconn > 0) {
    148 		io_data_ref(data);
    149 		g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, data->disconn,
    150 					disconn_timeout, data,
    151 					(GDestroyNotify) io_data_unref);
    152 	}
    153 
    154 
    155 	io_data_ref(data);
    156 	cond = G_IO_NVAL | G_IO_HUP | G_IO_ERR;
    157 	g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, io_watch, data,
    158 					(GDestroyNotify) io_data_unref);
    159 }
    160 
    161 static gboolean confirm_timeout(gpointer user_data)
    162 {
    163 	struct io_data *data = user_data;
    164 
    165 	if (data->reject >= 0) {
    166 		printf("Rejecting connection\n");
    167 		g_io_channel_shutdown(data->io, TRUE, NULL);
    168 		return FALSE;
    169 	}
    170 
    171 	printf("Accepting connection\n");
    172 
    173 	io_data_ref(data);
    174 
    175 	if (!bt_io_accept(data->io, connect_cb, data,
    176 				(GDestroyNotify) io_data_unref, NULL)) {
    177 		printf("bt_io_accept() failed\n");
    178 		io_data_unref(data);
    179 	}
    180 
    181 	return FALSE;
    182 }
    183 
    184 static void confirm_cb(GIOChannel *io, gpointer user_data)
    185 {
    186 	char addr[18];
    187 	struct io_data *data = user_data;
    188 	GError *err = NULL;
    189 
    190 	if (!bt_io_get(io, data->type, &err, BT_IO_OPT_DEST, addr,
    191 							BT_IO_OPT_INVALID)) {
    192 		printf("bt_io_get(OPT_DEST): %s\n", err->message);
    193 		g_clear_error(&err);
    194 	} else
    195 		printf("Got confirmation request for %s\n", addr);
    196 
    197 	if (data->accept < 0 && data->reject < 0)
    198 		return;
    199 
    200 	if (data->reject == 0) {
    201 		printf("Rejecting connection\n");
    202 		g_io_channel_shutdown(io, TRUE, NULL);
    203 		return;
    204 	}
    205 
    206 	data->io = g_io_channel_ref(io);
    207 	io_data_ref(data);
    208 
    209 	if (data->accept == 0) {
    210 		if (!bt_io_accept(io, connect_cb, data,
    211 					(GDestroyNotify) io_data_unref,
    212 					&err)) {
    213 			printf("bt_io_accept() failed: %s\n", err->message);
    214 			g_clear_error(&err);
    215 			io_data_unref(data);
    216 			return;
    217 		}
    218 	} else {
    219 		gint seconds = (data->reject > 0) ?
    220 						data->reject : data->accept;
    221 		g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, seconds,
    222 					confirm_timeout, data,
    223 					(GDestroyNotify) io_data_unref);
    224 	}
    225 }
    226 
    227 static void l2cap_connect(const char *src, const char *dst, uint16_t psm,
    228 						gint disconn, gint sec)
    229 {
    230 	struct io_data *data;
    231 	GError *err = NULL;
    232 
    233 	printf("Connecting to %s L2CAP PSM %u\n", dst, psm);
    234 
    235 	data = io_data_new(NULL, BT_IO_L2CAP, -1, disconn, -1);
    236 
    237 	if (src)
    238 		data->io = bt_io_connect(BT_IO_L2CAP, connect_cb, data,
    239 						(GDestroyNotify) io_data_unref,
    240 						&err,
    241 						BT_IO_OPT_SOURCE, src,
    242 						BT_IO_OPT_DEST, dst,
    243 						BT_IO_OPT_PSM, psm,
    244 						BT_IO_OPT_SEC_LEVEL, sec,
    245 						BT_IO_OPT_INVALID);
    246 	else
    247 		data->io = bt_io_connect(BT_IO_L2CAP, connect_cb, data,
    248 						(GDestroyNotify) io_data_unref,
    249 						&err,
    250 						BT_IO_OPT_DEST, dst,
    251 						BT_IO_OPT_PSM, psm,
    252 						BT_IO_OPT_SEC_LEVEL, sec,
    253 						BT_IO_OPT_INVALID);
    254 
    255 	if (!data->io) {
    256 		printf("Connecting to %s failed: %s\n", dst, err->message);
    257 		g_error_free(err);
    258 		exit(EXIT_FAILURE);
    259 	}
    260 }
    261 
    262 static void l2cap_listen(const char *src, uint16_t psm, gint defer,
    263 				gint reject, gint disconn, gint accept,
    264 				gint sec, gboolean master)
    265 {
    266 	struct io_data *data;
    267 	BtIOConnect conn;
    268 	BtIOConfirm cfm;
    269 	GIOChannel *l2_srv;
    270 	GError *err = NULL;
    271 
    272 	if (defer) {
    273 		conn = NULL;
    274 		cfm = confirm_cb;
    275 	} else {
    276 		conn = connect_cb;
    277 		cfm = NULL;
    278 	}
    279 
    280 	printf("Listening on L2CAP PSM %u\n", psm);
    281 
    282 	data = io_data_new(NULL, BT_IO_L2CAP, reject, disconn, accept);
    283 
    284 	if (src)
    285 		l2_srv = bt_io_listen(BT_IO_L2CAP, conn, cfm,
    286 					data, (GDestroyNotify) io_data_unref,
    287 					&err,
    288 					BT_IO_OPT_SOURCE, src,
    289 					BT_IO_OPT_PSM, psm,
    290 					BT_IO_OPT_SEC_LEVEL, sec,
    291 					BT_IO_OPT_MASTER, master,
    292 					BT_IO_OPT_INVALID);
    293 	else
    294 		l2_srv = bt_io_listen(BT_IO_L2CAP, conn, cfm,
    295 					data, (GDestroyNotify) io_data_unref,
    296 					&err,
    297 					BT_IO_OPT_PSM, psm,
    298 					BT_IO_OPT_SEC_LEVEL, sec,
    299 					BT_IO_OPT_MASTER, master,
    300 					BT_IO_OPT_INVALID);
    301 
    302 	if (!l2_srv) {
    303 		printf("Listening failed: %s\n", err->message);
    304 		g_error_free(err);
    305 		exit(EXIT_FAILURE);
    306 	}
    307 
    308 	g_io_channel_unref(l2_srv);
    309 }
    310 
    311 static void rfcomm_connect(const char *src, const char *dst, uint8_t ch,
    312 						gint disconn, gint sec)
    313 {
    314 	struct io_data *data;
    315 	GError *err = NULL;
    316 
    317 	printf("Connecting to %s RFCOMM channel %u\n", dst, ch);
    318 
    319 	data = io_data_new(NULL, BT_IO_RFCOMM, -1, disconn, -1);
    320 
    321 	if (src)
    322 		data->io = bt_io_connect(BT_IO_RFCOMM, connect_cb, data,
    323 						(GDestroyNotify) io_data_unref,
    324 						&err,
    325 						BT_IO_OPT_SOURCE, src,
    326 						BT_IO_OPT_DEST, dst,
    327 						BT_IO_OPT_CHANNEL, ch,
    328 						BT_IO_OPT_SEC_LEVEL, sec,
    329 						BT_IO_OPT_INVALID);
    330 	else
    331 		data->io = bt_io_connect(BT_IO_RFCOMM, connect_cb, data,
    332 						(GDestroyNotify) io_data_unref,
    333 						&err,
    334 						BT_IO_OPT_DEST, dst,
    335 						BT_IO_OPT_CHANNEL, ch,
    336 						BT_IO_OPT_SEC_LEVEL, sec,
    337 						BT_IO_OPT_INVALID);
    338 
    339 	if (!data->io) {
    340 		printf("Connecting to %s failed: %s\n", dst, err->message);
    341 		g_error_free(err);
    342 		exit(EXIT_FAILURE);
    343 	}
    344 }
    345 
    346 static void rfcomm_listen(const char *src, uint8_t ch, gboolean defer,
    347 				gint reject, gint disconn, gint accept,
    348 				gint sec, gboolean master)
    349 {
    350 	struct io_data *data;
    351 	BtIOConnect conn;
    352 	BtIOConfirm cfm;
    353 	GIOChannel *rc_srv;
    354 	GError *err = NULL;
    355 
    356 	if (defer) {
    357 		conn = NULL;
    358 		cfm = confirm_cb;
    359 	} else {
    360 		conn = connect_cb;
    361 		cfm = NULL;
    362 	}
    363 
    364 	data = io_data_new(NULL, BT_IO_RFCOMM, reject, disconn, accept);
    365 
    366 	if (src)
    367 		rc_srv = bt_io_listen(BT_IO_RFCOMM, conn, cfm,
    368 					data, (GDestroyNotify) io_data_unref,
    369 					&err,
    370 					BT_IO_OPT_SOURCE, src,
    371 					BT_IO_OPT_CHANNEL, ch,
    372 					BT_IO_OPT_SEC_LEVEL, sec,
    373 					BT_IO_OPT_MASTER, master,
    374 					BT_IO_OPT_INVALID);
    375 	else
    376 		rc_srv = bt_io_listen(BT_IO_RFCOMM, conn, cfm,
    377 					data, (GDestroyNotify) io_data_unref,
    378 					&err,
    379 					BT_IO_OPT_CHANNEL, ch,
    380 					BT_IO_OPT_SEC_LEVEL, sec,
    381 					BT_IO_OPT_MASTER, master,
    382 					BT_IO_OPT_INVALID);
    383 
    384 	if (!rc_srv) {
    385 		printf("Listening failed: %s\n", err->message);
    386 		g_error_free(err);
    387 		exit(EXIT_FAILURE);
    388 	}
    389 
    390 	bt_io_get(rc_srv, BT_IO_RFCOMM, &err,
    391 			BT_IO_OPT_CHANNEL, &ch,
    392 			BT_IO_OPT_INVALID);
    393 
    394 	printf("Listening on RFCOMM channel %u\n", ch);
    395 
    396 	g_io_channel_unref(rc_srv);
    397 }
    398 
    399 static void sco_connect(const char *src, const char *dst, gint disconn)
    400 {
    401 	struct io_data *data;
    402 	GError *err = NULL;
    403 
    404 	printf("Connecting SCO to %s\n", dst);
    405 
    406 	data = io_data_new(NULL, BT_IO_SCO, -1, disconn, -1);
    407 
    408 	if (src)
    409 		data->io = bt_io_connect(BT_IO_SCO, connect_cb, data,
    410 						(GDestroyNotify) io_data_unref,
    411 						&err,
    412 						BT_IO_OPT_SOURCE, src,
    413 						BT_IO_OPT_DEST, dst,
    414 						BT_IO_OPT_INVALID);
    415 	else
    416 		data->io = bt_io_connect(BT_IO_SCO, connect_cb, data,
    417 						(GDestroyNotify) io_data_unref,
    418 						&err,
    419 						BT_IO_OPT_DEST, dst,
    420 						BT_IO_OPT_INVALID);
    421 
    422 	if (!data->io) {
    423 		printf("Connecting to %s failed: %s\n", dst, err->message);
    424 		g_error_free(err);
    425 		exit(EXIT_FAILURE);
    426 	}
    427 }
    428 
    429 static void sco_listen(const char *src, gint disconn)
    430 {
    431 	struct io_data *data;
    432 	GIOChannel *sco_srv;
    433 	GError *err = NULL;
    434 
    435 	printf("Listening for SCO connections\n");
    436 
    437 	data = io_data_new(NULL, BT_IO_SCO, -1, disconn, -1);
    438 
    439 	if (src)
    440 		sco_srv = bt_io_listen(BT_IO_SCO, connect_cb, NULL,
    441 					data, (GDestroyNotify) io_data_unref,
    442 					&err,
    443 					BT_IO_OPT_SOURCE, src,
    444 					BT_IO_OPT_INVALID);
    445 	else
    446 		sco_srv = bt_io_listen(BT_IO_SCO, connect_cb, NULL,
    447 					data, (GDestroyNotify) io_data_unref,
    448 					&err, BT_IO_OPT_INVALID);
    449 
    450 	if (!sco_srv) {
    451 		printf("Listening failed: %s\n", err->message);
    452 		g_error_free(err);
    453 		exit(EXIT_FAILURE);
    454 	}
    455 
    456 	g_io_channel_unref(sco_srv);
    457 }
    458 
    459 static gint opt_channel = -1;
    460 static gint opt_psm = 0;
    461 static gboolean opt_sco = FALSE;
    462 static gboolean opt_defer = FALSE;
    463 static char *opt_dev = NULL;
    464 static gint opt_reject = -1;
    465 static gint opt_disconn = -1;
    466 static gint opt_accept = DEFAULT_ACCEPT_TIMEOUT;
    467 static gint opt_sec = 0;
    468 static gboolean opt_master = FALSE;
    469 
    470 static GMainLoop *main_loop;
    471 
    472 static GOptionEntry options[] = {
    473 	{ "channel", 'c', 0, G_OPTION_ARG_INT, &opt_channel,
    474 				"RFCOMM channel" },
    475 	{ "psm", 'p', 0, G_OPTION_ARG_INT, &opt_psm,
    476 				"L2CAP PSM" },
    477 	{ "sco", 's', 0, G_OPTION_ARG_NONE, &opt_sco,
    478 				"Use SCO" },
    479 	{ "defer", 'd', 0, G_OPTION_ARG_NONE, &opt_defer,
    480 				"Use DEFER_SETUP for incoming connections" },
    481 	{ "sec-level", 'S', 0, G_OPTION_ARG_INT, &opt_sec,
    482 				"Security level" },
    483 	{ "dev", 'i', 0, G_OPTION_ARG_STRING, &opt_dev,
    484 				"Which HCI device to use" },
    485 	{ "reject", 'r', 0, G_OPTION_ARG_INT, &opt_reject,
    486 				"Reject connection after N seconds" },
    487 	{ "disconnect", 'D', 0, G_OPTION_ARG_INT, &opt_disconn,
    488 				"Disconnect connection after N seconds" },
    489 	{ "accept", 'a', 0, G_OPTION_ARG_INT, &opt_accept,
    490 				"Accept connection after N seconds" },
    491 	{ "master", 'm', 0, G_OPTION_ARG_NONE, &opt_master,
    492 				"Master role switch (incoming connections)" },
    493 	{ NULL },
    494 };
    495 
    496 static void sig_term(int sig)
    497 {
    498 	g_main_loop_quit(main_loop);
    499 }
    500 
    501 int main(int argc, char *argv[])
    502 {
    503 	GOptionContext *context;
    504 
    505 	context = g_option_context_new(NULL);
    506 	g_option_context_add_main_entries(context, options, NULL);
    507 
    508 	if (!g_option_context_parse(context, &argc, &argv, NULL))
    509 		exit(EXIT_FAILURE);
    510 
    511 	g_option_context_free(context);
    512 
    513 	printf("accept=%d, reject=%d, discon=%d, defer=%d, sec=%d\n",
    514 		opt_accept, opt_reject, opt_disconn, opt_defer, opt_sec);
    515 
    516 	if (opt_psm) {
    517 		if (argc > 1)
    518 			l2cap_connect(opt_dev, argv[1], opt_psm,
    519 							opt_disconn, opt_sec);
    520 		else
    521 			l2cap_listen(opt_dev, opt_psm, opt_defer, opt_reject,
    522 					opt_disconn, opt_accept, opt_sec,
    523 					opt_master);
    524 	}
    525 
    526 	if (opt_channel != -1) {
    527 		if (argc > 1)
    528 			rfcomm_connect(opt_dev, argv[1], opt_channel,
    529 							opt_disconn, opt_sec);
    530 		else
    531 			rfcomm_listen(opt_dev, opt_channel, opt_defer,
    532 					opt_reject, opt_disconn, opt_accept,
    533 					opt_sec, opt_master);
    534 	}
    535 
    536 	if (opt_sco) {
    537 		if (argc > 1)
    538 			sco_connect(opt_dev, argv[1], opt_disconn);
    539 		else
    540 			sco_listen(opt_dev, opt_disconn);
    541 	}
    542 
    543 	signal(SIGTERM, sig_term);
    544 	signal(SIGINT, sig_term);
    545 
    546 	main_loop = g_main_loop_new(NULL, FALSE);
    547 
    548 	g_main_loop_run(main_loop);
    549 
    550 	g_main_loop_unref(main_loop);
    551 
    552 	printf("Exiting\n");
    553 
    554 	exit(EXIT_SUCCESS);
    555 }
    556