diff options
| -rw-r--r-- | common/glib-ectomy.c | 175 | ||||
| -rw-r--r-- | common/glib-ectomy.h | 27 | ||||
| -rw-r--r-- | hcid/dbus.c | 128 | ||||
| -rw-r--r-- | hcid/dbus.h | 6 | ||||
| -rw-r--r-- | hcid/main.c | 3 | ||||
| -rw-r--r-- | test/Makefile.am | 5 | 
6 files changed, 222 insertions, 122 deletions
| diff --git a/common/glib-ectomy.c b/common/glib-ectomy.c index 463d0aee..f1d79e7f 100644 --- a/common/glib-ectomy.c +++ b/common/glib-ectomy.c @@ -10,8 +10,11 @@  #include <malloc.h>  #include <string.h>  #include <limits.h> +#include <sys/time.h> +#include <time.h>  #include "glib-ectomy.h" +#include "list.h"  GIOError g_io_channel_read(GIOChannel *channel, gchar *buf, gsize count, gsize *bytes_read)  { @@ -89,6 +92,7 @@ struct watch {  };  static struct watch watch_head = { .id = 0, .next = 0 }; +static GMainContext *default_context = NULL;  void g_io_remove_watch(guint id)  { @@ -129,6 +133,23 @@ guint g_io_add_watch(GIOChannel *channel, GIOCondition condition,  						func, user_data, NULL);  } +static GMainContext *g_main_context_default() +{ + +	if (default_context) +		return default_context; + +	default_context = malloc(sizeof(GMainContext)); +	if (!default_context) +		return NULL; + +	memset(default_context, 0, sizeof(GMainContext)); + +	default_context->timeout = -1; + +	return default_context; +} +  GMainLoop *g_main_loop_new(GMainContext *context, gboolean is_running)  {  	GMainLoop *ml; @@ -137,11 +158,80 @@ GMainLoop *g_main_loop_new(GMainContext *context, gboolean is_running)  	if (!ml)  		return NULL; -	ml->bail = 0; +	memset(ml, 0, sizeof(GMainLoop)); + +	if (!context) +		ml->context = g_main_context_default(); +	else +		ml->context = context; +	ml->bail = 0;  	return ml;  } +static void timeout_handlers_prepare(GMainContext *context) +{ +	struct slist *l = context->ltimeout; +	struct timeout *t; +	struct timeval tv; +	glong msec, timeout = LONG_MAX; + +	gettimeofday(&tv, NULL); + +	while (l) { +		t = l->data; +		l = l->next; + +		/* calculate the remainning time */ +		msec = (t->expiration.tv_sec - tv.tv_sec) * 1000 + +				(t->expiration.tv_usec - tv.tv_usec) / 1000; +		if (msec < 0) +			msec = 0; + +		timeout = MIN_TIMEOUT(timeout, msec); +	} + +	/* set to min value found or NO timeout */ +	context->timeout = (timeout != LONG_MAX ? timeout: -1); +} + +static void timeout_handlers_check(GMainContext *context) +{ +	struct slist *l = context->ltimeout; +	struct timeout *t; +	struct timeval tv; + +	gettimeofday(&tv, NULL); + +	while (l) { +		t = l->data; +		l = l->next; + +		if ((tv.tv_sec < t->expiration.tv_sec) || +		   	(tv.tv_sec == t->expiration.tv_sec && +		   	 tv.tv_usec < t->expiration.tv_usec)) +			continue; + +		if (t->func(t->data)) { +			/* if false/expired: remove it from the list */ +			context->ltimeout = slist_remove(context->ltimeout, t); +			free(t); +		} else { +			glong secs, msecs; +			/* update the next expiration time */ +			secs = t->interval / 1000; +			msecs = t->interval - secs * 1000; + +			t->expiration.tv_sec = tv.tv_sec + secs; +			t->expiration.tv_usec = tv.tv_usec + msecs * 1000; +			if (t->expiration.tv_usec >= 1000000) { +				t->expiration.tv_usec -= 1000000; +				t->expiration.tv_sec++; +			} +		} +	} +} +  void g_main_loop_run(GMainLoop *loop)  {  	int open_max = sysconf(_SC_OPEN_MAX); @@ -163,7 +253,10 @@ void g_main_loop_run(GMainLoop *loop)  			nfds++;  		} -		rc = poll(ufds, nfds, -1); +		/* calculate the next timeout */ +		timeout_handlers_prepare(loop->context); + +		rc = poll(ufds, nfds, loop->context->timeout);  		if (rc < 0)  			continue; @@ -190,6 +283,9 @@ void g_main_loop_run(GMainLoop *loop)  			w = w->next;  			i++;  		} + +		/* check expired timers */ +		timeout_handlers_check(loop->context);  	}  	free(ufds); @@ -208,3 +304,78 @@ void g_main_loop_quit(GMainLoop *loop)  		free(w);  	}  } + +void g_main_loop_unref(GMainLoop *loop) +{ +	if (!loop->context) +		return; + +	slist_free(loop->context->ltimeout); +	free(loop->context); +} + +guint g_timeout_add(guint interval, timeout_func_t *func, void *data) +{ +	struct timeval tv; +	guint secs; +	guint msecs; +	struct timeout *t; + +	if (!default_context || !func) +		return 0; + +	t = malloc(sizeof(*t)); + +	if (!t) +		return 0; + +	t->interval = interval; +	t->func = func; +	t->data = data; + +	gettimeofday(&tv, NULL); + +	secs = interval /1000; +	msecs = interval - secs * 1000; + +	t->expiration.tv_sec = tv.tv_sec + secs; +	t->expiration.tv_usec = tv.tv_usec + msecs * 1000; + +	if (t->expiration.tv_usec >= 1000000) { +		t->expiration.tv_usec -= 1000000; +		t->expiration.tv_sec++; +	} + +	/* attach the timeout the default context */ +	t->id = ++default_context->next_id; +	default_context->ltimeout = slist_append(default_context->ltimeout, t); + +	return t->id; +} + +gint g_timeout_remove(const guint id) +{ +	struct slist *l; +	struct timeout *t; + +	if (!default_context) +		return -1; + +	l = default_context->ltimeout; + +	while (l) { +		t = l->data; +		l = l->next; + +		if (t->id != id) +			continue; + +		default_context->ltimeout = slist_remove(default_context->ltimeout, t); +		free(t); + +		return 0; +	} + +	return -1; +} + diff --git a/common/glib-ectomy.h b/common/glib-ectomy.h index e921b40d..56dac08b 100644 --- a/common/glib-ectomy.h +++ b/common/glib-ectomy.h @@ -28,16 +28,36 @@ typedef ssize_t	gssize;  #define SSIZE_MAX	INT_MAX  #endif +#define MIN_TIMEOUT(a, b)  (((a) < (b)) ? (a) : (b)) +  typedef struct _GIOChannel {  	int fd;  } GIOChannel; +typedef int (timeout_func_t)(void *data); + +typedef struct { +	glong tv_sec; +	glong tv_usec; +} time_val_t; + +struct timeout { +	guint id; +	guint interval; +	time_val_t expiration; +	void *data; +	timeout_func_t *func; +}; +  typedef struct _GMainContext { -	int dummy; +	guint next_id; +	glong timeout; +	struct slist *ltimeout;  } GMainContext;  typedef struct _GMainLoop {  	int bail; +	GMainContext *context;  } GMainLoop;  typedef enum { @@ -89,9 +109,14 @@ void g_io_remove_watch(guint id);  GMainLoop *g_main_loop_new(GMainContext *context, gboolean is_running);  void g_main_loop_run(GMainLoop *loop);  void g_main_loop_quit(GMainLoop *loop); +void g_main_loop_unref(GMainLoop *loop); +guint g_timeout_add(guint interval, timeout_func_t *func, void *data); +gint g_timeout_remove(const guint id); +  #define g_main_new(is_running)	g_main_loop_new(NULL, is_running);  #define g_main_run(loop)	g_main_loop_run(loop)  #define g_main_quit(loop)	g_main_loop_quit(loop) +#define g_main_unref(loop)	g_main_loop_unref(loop)  #endif /* __GLIB_ECTOMY_H */ diff --git a/hcid/dbus.c b/hcid/dbus.c index 6ed5b6a4..c1abd71b 100644 --- a/hcid/dbus.c +++ b/hcid/dbus.c @@ -28,9 +28,7 @@  #include <stdio.h>  #include <errno.h>  #include <unistd.h> -#include <signal.h>  #include <string.h> -#include <sys/time.h>  #include <sys/ioctl.h>  #include <sys/socket.h> @@ -50,9 +48,9 @@  static DBusConnection *connection;  static int default_dev = -1; -static volatile sig_atomic_t __timeout_active = 0;  #define MAX_CONN_NUMBER			10 +#define RECONNECT_RETRY_TIMEOUT		5000  static const char *services_cls[] = {  	"positioning", @@ -289,8 +287,6 @@ static DBusMessage *dbus_msg_new_authentication_return(DBusMessage *msg, uint8_t  /*   * Timeout functions Protypes   */ -static int discoverable_timeout_handler(void *data); -  DBusConnection *get_dbus_connection(void)  {  	return connection; @@ -496,13 +492,6 @@ gboolean hcid_dbus_register_device(uint16_t id)  	else  		pdata->mode = rp.enable;	/* Keep the current scan status */ -	/*  -	 * Enable timeout to address dbus daemon restart, where -	 * register the device paths is required due connection lost. -	 */ -	if (pdata->mode & SCAN_INQUIRY) -		pdata->timeout_handler = &discoverable_timeout_handler; -  	message = dbus_message_new_signal(MANAGER_PATH, MANAGER_INTERFACE,  							"AdapterAdded");  	if (message == NULL) { @@ -1055,7 +1044,7 @@ void hcid_dbus_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class, i  	name = textfile_get(filename, peer_addr);  	if (name) { -		signal_name = dev_signal_factory(pdata->dev_id, "RemoteNameUpdate", +		signal_name = dev_signal_factory(pdata->dev_id, "RemoteNameUpdated",  							DBUS_TYPE_STRING, &peer_addr,  							DBUS_TYPE_STRING, &name,  							DBUS_TYPE_INVALID); @@ -1475,7 +1464,7 @@ static int discoverable_timeout_handler(void *data)  	dd = hci_open_dev(dbus_data->dev_id);  	if (dd < 0) {  		error("HCI device open failed: hci%d", dbus_data->dev_id); -		return -1; +		return 0;  	}  	memset(&rq, 0, sizeof(rq)); @@ -1489,15 +1478,14 @@ static int discoverable_timeout_handler(void *data)  	if (hci_send_req(dd, &rq, 100) < 0) {  		error("Sending write scan enable command to hci%d failed: %s (%d)",  				dbus_data->dev_id, strerror(errno), errno); -		retval = -1;  		goto failed;  	}  	if (status) {  		error("Setting scan enable failed with status 0x%02x", status); -		retval = -1;  		goto failed;  	} +	retval = -1;  failed:  	if (dd >= 0)  		close(dd); @@ -1505,22 +1493,24 @@ failed:  	return retval;  } -static void system_bus_reconnect(void) +static int system_bus_reconnect(void *data)  {  	struct hci_dev_list_req *dl = NULL;  	struct hci_dev_req *dr; -	int sk; -	int i; +	int sk, i, ret_val = 0; + +       if (dbus_connection_get_is_connected(connection)) +	       return -1;  	if (hcid_dbus_init() == FALSE) -		return; +		return 0;  	/* Create and bind HCI socket */  	sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);  	if (sk < 0) {  		error("Can't open HCI socket: %s (%d)",  							strerror(errno), errno); -		return; +		return 0;  	}  	dl = malloc(HCI_MAX_DEV * sizeof(*dr) + sizeof(*dl)); @@ -1544,98 +1534,15 @@ static void system_bus_reconnect(void)  	for (i = 0; i < dl->dev_num; i++, dr++)  		hcid_dbus_register_device(dr->dev_id); +	ret_val = -1;  failed:  	if (sk >= 0)  		close(sk);  	if (dl)  		free(dl); -} - -static void sigalarm_handler(int signum) -{ -	struct hci_dbus_data *pdata = NULL; -	char device_path[MAX_PATH_LENGTH]; -	char **device = NULL; -	int active_handlers = 0; -	int i = 0; - -	if (!dbus_connection_get_is_connected(connection)) { -		/* it is not connected */ -		system_bus_reconnect(); -		return; -	} - -	if (!dbus_connection_list_registered(connection, ADAPTER_PATH, &device)) -		goto done; - -	/* check the timer for each registered path */ -	for (; device[i]; i++) { - -		snprintf(device_path, sizeof(device_path), "%s/%s", ADAPTER_PATH, device[i]); - -		if (!dbus_connection_get_object_path_data(connection, device_path, (void *) &pdata)){ -			error("Getting %s path data failed!", device_path); -			continue; -		} - -		if (pdata->timeout_handler == NULL) -			continue; - -		if (!(pdata->mode & SCAN_INQUIRY)) { -			pdata->timeout_hits = 0; -			continue; -		} - -		active_handlers++; - -		if (!pdata->discoverable_timeout) -			continue; /* skip if discoverable always: timeout zero */ - -		if ((++(pdata->timeout_hits) % pdata->discoverable_timeout) != 0) -			continue; - -		if (!pdata->timeout_handler(pdata)) { -			/* Remove from the timeout queue */ -			pdata->timeout_handler = NULL; -			pdata->timeout_hits = 0; -			active_handlers--; -		} -	} - -	dbus_free_string_array(device); - -done: -	if (!active_handlers) { -		sigaction(SIGALRM, NULL, NULL); -		setitimer(ITIMER_REAL, NULL, NULL); -		__timeout_active = 0; -	} -} - -static void bluez_timeout_start(void) -{ -	struct sigaction sa; -	struct itimerval timer; - -	if (__timeout_active) -		return; - -	__timeout_active = 1; - -	memset (&sa, 0, sizeof (sa)); -	sa.sa_handler = &sigalarm_handler; -	sigaction(SIGALRM, &sa, NULL); -	/* expire after 1 sec... */ -	timer.it_value.tv_sec = 1; -	timer.it_value.tv_usec = 0; - -	/* ... and every 1 sec after that. */ -	timer.it_interval.tv_sec = 1; -	timer.it_interval.tv_usec = 0; - -	setitimer(ITIMER_REAL, &timer, NULL); +	return ret_val;  }  /***************************************************************** @@ -1662,8 +1569,7 @@ static DBusHandlerResult hci_dbus_signal_filter(DBusConnection *conn, DBusMessag  			(strcmp(method, "Disconnected") == 0)) {  		error("Got disconnected from the system message bus");  		dbus_connection_unref(conn); -		bluez_timeout_start(); -		ret = DBUS_HANDLER_RESULT_HANDLED; +		g_timeout_add(RECONNECT_RETRY_TIMEOUT, system_bus_reconnect, NULL);  	}  	return ret; @@ -1802,13 +1708,11 @@ void hcid_dbus_setscan_enable_complete(bdaddr_t *local)  		break;  	case (SCAN_PAGE | SCAN_INQUIRY):  		scan_mode = MODE_DISCOVERABLE; -		pdata->timeout_handler = &discoverable_timeout_handler; -		bluez_timeout_start(); +		g_timeout_add(pdata->discoverable_timeout, discoverable_timeout_handler, pdata);  		break;  	case SCAN_INQUIRY:  		/* Address the scenario where another app changed the scan mode */ -		pdata->timeout_handler = &discoverable_timeout_handler; -		bluez_timeout_start(); +		g_timeout_add(pdata->discoverable_timeout, discoverable_timeout_handler, pdata);  		/* ignore, this event should not be sent*/  	default:  		/* ignore, reserved */ diff --git a/hcid/dbus.h b/hcid/dbus.h index 61817090..f6f0b6d8 100644 --- a/hcid/dbus.h +++ b/hcid/dbus.h @@ -70,8 +70,6 @@ struct service_data {  	service_handler_func_t	handler_func;  }; -typedef int (timeout_handler_func_t) (void *data); -  typedef enum {  	STATE_IDLE,  	STATE_DISCOVER, @@ -108,8 +106,6 @@ struct hci_dbus_data {  	uint16_t dev_id;  	uint16_t path_id;  	uint32_t discoverable_timeout; -	uint32_t timeout_hits; -	timeout_handler_func_t *timeout_handler;  	uint8_t mode;		           /* scan mode */  	discover_state_t discover_state;   /* discover states */  	int discover_type;                 /* with/without name resolving */ @@ -211,7 +207,7 @@ int disc_device_req_name(struct hci_dbus_data *dbus_data);  #define MODE_DISCOVERABLE	"discoverable"  #define MODE_UNKNOWN		"unknown" -#define DFT_DISCOVERABLE_TIMEOUT	180	/* 3 seconds */ +#define DFT_DISCOVERABLE_TIMEOUT	180*1000 /* 3 seconds */  #define DISCOVERABLE_TIMEOUT_OFF	0  #endif /* __H_BLUEZ_DBUS_H__ */ diff --git a/hcid/main.c b/hcid/main.c index a449f37b..6a6b382c 100644 --- a/hcid/main.c +++ b/hcid/main.c @@ -34,7 +34,6 @@  #include <stdlib.h>  #include <string.h>  #include <signal.h> -#include <sys/time.h>  #include <sys/stat.h>  #include <sys/ioctl.h>  #include <sys/socket.h> @@ -660,6 +659,8 @@ int main(int argc, char *argv[], char *env[])  	/* Start event processor */  	g_main_run(event_loop); +	g_main_unref(event_loop); +  	if (sdp)  		stop_sdp_server(); diff --git a/test/Makefile.am b/test/Makefile.am index 751fa50c..32b32b33 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -6,7 +6,10 @@ bin_PROGRAMS = l2test rctest  noinst_PROGRAMS = scotest attest hstest bdaddr -hciemu_LDADD = @BLUEZ_LIBS@ $(top_builddir)/common/libglib-ectomy.a +hciemu_LDADD = @BLUEZ_LIBS@ \ +	       $(top_builddir)/common/libglib-ectomy.a \ +	       $(top_builddir)/common/liblist.a +  l2test_LDADD = @BLUEZ_LIBS@ | 
