diff options
| author | Johan Hedberg <johan.hedberg@nokia.com> | 2009-02-16 19:48:54 +0200 | 
|---|---|---|
| committer | Johan Hedberg <johan.hedberg@nokia.com> | 2009-02-16 19:48:54 +0200 | 
| commit | d1f188d4b3822b9ac2bc333f1cb47b54536f6843 (patch) | |
| tree | 5b8ba9e20f3f4d4b971d2bc8a7b7776a5f2525cd | |
| parent | 820e5e15ced0fff0e3e70a5b3e8270809a3fc422 (diff) | |
Convert BtIO API to use GError
| -rw-r--r-- | common/btio.c | 320 | ||||
| -rw-r--r-- | common/btio.h | 26 | ||||
| -rw-r--r-- | test/btiotest.c | 29 | 
3 files changed, 208 insertions, 167 deletions
| diff --git a/common/btio.c b/common/btio.c index 64f8a16d..111b4a3a 100644 --- a/common/btio.c +++ b/common/btio.c @@ -41,6 +41,10 @@  #include "logging.h"  #include "btio.h" +#define ERROR_FAILED(gerr, str, err) \ +		g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_FAILED, \ +				str ": %s (%d)", strerror(err), err) +  #define DEFAULT_DEFER_TIMEOUT 30  struct set_opts { @@ -99,15 +103,19 @@ static gboolean accept_cb(GIOChannel *io, GIOCondition cond,  							gpointer user_data)  {  	struct accept *accept = user_data; +	GError *err = NULL;  	/* If the user aborted this accept attempt */  	if (cond & G_IO_NVAL)  		return FALSE;  	if (cond & (G_IO_HUP | G_IO_ERR)) -		accept->connect(io, EIO, accept->user_data); -	else -		accept->connect(io, 0, accept->user_data); +		g_set_error(&err, BT_IO_ERROR, BT_IO_ERROR_DISCONNECTED, +				"HUP or ERR on socket"); + +	accept->connect(io, err, accept->user_data); + +	g_clear_error(&err);  	return FALSE;  } @@ -116,24 +124,30 @@ static gboolean connect_cb(GIOChannel *io, GIOCondition cond,  							gpointer user_data)  {  	struct connect *conn = user_data; -	int err; +	GError *gerr = NULL;  	/* If the user aborted this connect attempt */  	if (cond & G_IO_NVAL)  		return FALSE; -	err = 0; -  	if (cond & G_IO_OUT) { +		int err = 0, sock = g_io_channel_unix_get_fd(io);  		socklen_t len = sizeof(err); -		int sock = g_io_channel_unix_get_fd(io); +  		if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len) < 0)  			err = errno; +		if (err) +			g_set_error(&gerr, BT_IO_ERROR, +					BT_IO_ERROR_CONNECT_FAILED, "%s (%d)", +					strerror(err), err);  	} else if (cond & (G_IO_HUP | G_IO_ERR)) -		err = EIO; +		g_set_error(&gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED, +				"HUP or ERR on socket"); + +	conn->connect(io, gerr, conn->user_data); -	conn->connect(io, err, conn->user_data); +	g_clear_error(&gerr);  	return FALSE;  } @@ -162,7 +176,7 @@ static gboolean server_cb(GIOChannel *io, GIOCondition cond,  	if (server->confirm)  		server->confirm(cli_io, server->user_data);  	else -		server->connect(cli_io, 0, server->user_data); +		server->connect(cli_io, NULL, server->user_data);  	g_io_channel_unref(cli_io); @@ -248,29 +262,31 @@ static int l2cap_connect(int sock, bdaddr_t *dst, uint16_t psm)  	return 0;  } -static int l2cap_set(int sock, int sec_level, uint16_t imtu, uint16_t omtu) +static gboolean l2cap_set(int sock, int sec_level, uint16_t imtu, +						uint16_t omtu, GError **err)  { -	int err; -  	if (imtu || omtu) {  		struct l2cap_options l2o;  		socklen_t len;  		memset(&l2o, 0, sizeof(l2o));  		len = sizeof(l2o); -		err = getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &len); -		if (err < 0) -			return err; +		if (getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o, +								&len) < 0) { +			ERROR_FAILED(err, "getsockopt(L2CAP_OPTIONS)", errno); +			return FALSE; +		}  		if (imtu)  			l2o.imtu = imtu;  		if (omtu)  			l2o.omtu = omtu; -		err = setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o, -								sizeof(l2o)); -		if (err < 0) -			return err; +		if (setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o, +							sizeof(l2o)) < 0) { +			ERROR_FAILED(err, "setsockopt(L2CAP_OPTIONS)", errno); +			return FALSE; +		}  	}  	if (sec_level) { @@ -279,13 +295,14 @@ static int l2cap_set(int sock, int sec_level, uint16_t imtu, uint16_t omtu)  		memset(&sec, 0, sizeof(sec));  		sec.level = sec_level; -		err = setsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec, -				sizeof(sec)); -		if (err < 0) -			return err; +		if (setsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec, +							sizeof(sec)) < 0) { +			ERROR_FAILED(err, "setsockopt(BT_SECURITY)", errno); +			return FALSE; +		}  	} -	return 0; +	return TRUE;  }  static int rfcomm_bind(int sock, bdaddr_t *src, uint8_t channel) @@ -304,10 +321,6 @@ static int rfcomm_connect(int sock, bdaddr_t *dst, uint8_t channel)  {  	int err;  	struct sockaddr_rc addr; -	char str[18]; - -	ba2str(dst, str); -	debug("Connecting to %s", str);  	memset(&addr, 0, sizeof(addr));  	addr.rc_family = AF_BLUETOOTH; @@ -321,23 +334,22 @@ static int rfcomm_connect(int sock, bdaddr_t *dst, uint8_t channel)  	return 0;  } -static int rfcomm_set(int sock, int sec_level) +static gboolean rfcomm_set(int sock, int sec_level, GError **err)  { -	int err; -  	if (sec_level) {  		struct bt_security sec;  		memset(&sec, 0, sizeof(sec));  		sec.level = sec_level; -		err = setsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec, -				sizeof(sec)); -		if (err < 0) -			return err; +		if (setsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec, +							sizeof(sec)) < 0) { +			ERROR_FAILED(err, "getsockopt(BT_SECURITY)", errno); +			return FALSE; +		}  	} -	return 0; +	return TRUE;  }  static int sco_bind(int sock, bdaddr_t *src) @@ -367,32 +379,33 @@ static int sco_connect(int sock, bdaddr_t *dst)  	return 0;  } -static int sco_set(int sock, uint16_t mtu) +static gboolean sco_set(int sock, uint16_t mtu, GError **err)  { -	int err;  	struct sco_options sco_opt; +	socklen_t len; -	if (mtu) { -		socklen_t len; +	if (!mtu) +		return TRUE; -		memset(&sco_opt, 0, len); -		len = sizeof(sco_opt); -		err = getsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, &len); -		if (err < 0) -			return err; - -		sco_opt.mtu = mtu; -		err = setsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, -							sizeof(sco_opt)); -		if (err < 0) -			return err; +	memset(&sco_opt, 0, len); +	len = sizeof(sco_opt); +	if (getsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, &len) < 0) { +		ERROR_FAILED(err, "getsockopt(SCO_OPTIONS)", errno); +		return FALSE;  	} -	return 0; +	sco_opt.mtu = mtu; +	if (setsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, +						sizeof(sco_opt)) < 0) { +		ERROR_FAILED(err, "setsockopt(SCO_OPTIONS)", errno); +		return FALSE; +	} + +	return TRUE;  }  static gboolean set_valist(GIOChannel *io, struct set_opts *opts, -					BtIOOption opt1, va_list args) +				GError **err, BtIOOption opt1, va_list args)  {  	BtIOOption opt = opt1;  	const char *str; @@ -443,7 +456,8 @@ static gboolean set_valist(GIOChannel *io, struct set_opts *opts,  				opts->mtu = opts->imtu;  			break;  		default: -			error("set_valist: unknown option %d", opt); +			g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS, +					"Unknown option %d", opt);  			return FALSE;  		} @@ -453,7 +467,7 @@ static gboolean set_valist(GIOChannel *io, struct set_opts *opts,  	return TRUE;  } -static gboolean get_sec_level(int sock, int *level) +static gboolean get_sec_level(int sock, int *level, GError **err)  {  	struct bt_security sec;  	socklen_t len; @@ -461,8 +475,7 @@ static gboolean get_sec_level(int sock, int *level)  	memset(&sec, 0, sizeof(sec));  	len = sizeof(sec);  	if (getsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec, &len) < 0) { -		error("getsockopt(BT_SECURITY): %s (%d)", strerror(errno), -									errno); +		ERROR_FAILED(err, "getsockopt(BT_SECURITY)", errno);  		return FALSE;  	} @@ -472,28 +485,29 @@ static gboolean get_sec_level(int sock, int *level)  }  static gboolean get_peers(int sock, struct sockaddr *src, struct sockaddr *dst, -								socklen_t len) +				socklen_t len, GError **err)  {  	socklen_t olen;  	memset(src, 0, len);  	olen = len;  	if (getsockname(sock, src, &olen) < 0) { -		error("getsockname: %s (%d)", strerror(errno), errno); +		ERROR_FAILED(err, "getsockname", errno);  		return FALSE;  	}  	memset(dst, 0, len);  	olen = len;  	if (getpeername(sock, dst, &olen) < 0) { -		error("getpeername: %s (%d)", strerror(errno), errno); +		ERROR_FAILED(err, "getpeername", errno);  		return FALSE;  	}  	return TRUE;  } -static gboolean l2cap_get(int sock, BtIOOption opt1, va_list args) +static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1, +								va_list args)  {  	BtIOOption opt = opt1;  	struct sockaddr_l2 src, dst; @@ -503,12 +517,12 @@ static gboolean l2cap_get(int sock, BtIOOption opt1, va_list args)  	len = sizeof(l2o);  	memset(&l2o, 0, len);  	if (getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &len) < 0) { -		error("getsockopt: %s (%d)", strerror(errno), errno); +		ERROR_FAILED(err, "getsockopt(L2CAP_OPTIONS)", errno);  		return FALSE;  	}  	if (!get_peers(sock, (struct sockaddr *) &src, -				(struct sockaddr *) &dst, sizeof(src))) +				(struct sockaddr *) &dst, sizeof(src), err))  		return FALSE;  	while (opt != BT_IO_OPT_INVALID) { @@ -528,11 +542,14 @@ static gboolean l2cap_get(int sock, BtIOOption opt1, va_list args)  		case BT_IO_OPT_DEFER_TIMEOUT:  			len = sizeof(int);  			if (getsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP, -						va_arg(args, int *), &len) < 0) +					va_arg(args, int *), &len) < 0) { +				ERROR_FAILED(err, "getsockopt(DEFER_SETUP)", +									errno);  				return FALSE; +			}  			break;  		case BT_IO_OPT_SEC_LEVEL: -			if (!get_sec_level(sock, va_arg(args, int *))) +			if (!get_sec_level(sock, va_arg(args, int *), err))  				return FALSE;  			break;  		case BT_IO_OPT_PSM: @@ -546,7 +563,8 @@ static gboolean l2cap_get(int sock, BtIOOption opt1, va_list args)  			*(va_arg(args, int *)) = l2o.imtu;  			break;  		default: -			error("l2cap_get: unknown option %d", opt); +			g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS, +					"Unknown option %d", opt);  			return FALSE;  		} @@ -556,14 +574,15 @@ static gboolean l2cap_get(int sock, BtIOOption opt1, va_list args)  	return TRUE;  } -static gboolean rfcomm_get(int sock, BtIOOption opt1, va_list args) +static gboolean rfcomm_get(int sock, GError **err, BtIOOption opt1, +								va_list args)  {  	BtIOOption opt = opt1;  	struct sockaddr_rc src, dst;  	socklen_t len;  	if (!get_peers(sock, (struct sockaddr *) &src, -				(struct sockaddr *) &dst, sizeof(src))) +				(struct sockaddr *) &dst, sizeof(src), err))  		return FALSE;  	while (opt != BT_IO_OPT_INVALID) { @@ -583,11 +602,14 @@ static gboolean rfcomm_get(int sock, BtIOOption opt1, va_list args)  		case BT_IO_OPT_DEFER_TIMEOUT:  			len = sizeof(int);  			if (getsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP, -						va_arg(args, int *), &len) < 0) +					va_arg(args, int *), &len) < 0) { +				ERROR_FAILED(err, "getsockopt(DEFER_SETUP)", +									errno);  				return FALSE; +			}  			break;  		case BT_IO_OPT_SEC_LEVEL: -			if (!get_sec_level(sock, va_arg(args, int *))) +			if (!get_sec_level(sock, va_arg(args, int *), err))  				return FALSE;  			break;  		case BT_IO_OPT_CHANNEL: @@ -595,7 +617,8 @@ static gboolean rfcomm_get(int sock, BtIOOption opt1, va_list args)  					src.rc_channel : dst.rc_channel;  			break;  		default: -			error("rfcomm_get: unknown option %d", opt); +			g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS, +					"Unknown option %d", opt);  			return FALSE;  		} @@ -605,7 +628,7 @@ static gboolean rfcomm_get(int sock, BtIOOption opt1, va_list args)  	return TRUE;  } -static gboolean sco_get(int sock, BtIOOption opt1, va_list args) +static gboolean sco_get(int sock, GError **err, BtIOOption opt1, va_list args)  {  	BtIOOption opt = opt1;  	struct sockaddr_sco src, dst; @@ -615,12 +638,12 @@ static gboolean sco_get(int sock, BtIOOption opt1, va_list args)  	len = sizeof(sco_opt);  	memset(&sco_opt, 0, len);  	if (getsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, &len) < 0) { -		error("getsockopt: %s (%d)", strerror(errno), errno); +		ERROR_FAILED(err, "getsockopt(SCO_OPTIONS)", errno);  		return FALSE;  	}  	if (!get_peers(sock, (struct sockaddr *) &src, -				(struct sockaddr *) &dst, sizeof(src))) +				(struct sockaddr *) &dst, sizeof(src), err))  		return FALSE;  	while (opt != BT_IO_OPT_INVALID) { @@ -637,23 +660,14 @@ static gboolean sco_get(int sock, BtIOOption opt1, va_list args)  		case BT_IO_OPT_DEST_BDADDR:  			bacpy(va_arg(args, bdaddr_t *), &dst.sco_bdaddr);  			break; -		case BT_IO_OPT_DEFER_TIMEOUT: -			len = sizeof(int); -			if (getsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP, -						va_arg(args, int *), &len) < 0) -				return FALSE; -			break; -		case BT_IO_OPT_SEC_LEVEL: -			if (!get_sec_level(sock, va_arg(args, int *))) -				return FALSE; -			break;  		case BT_IO_OPT_MTU:  		case BT_IO_OPT_IMTU:  		case BT_IO_OPT_OMTU:  			*(va_arg(args, int *)) = sco_opt.mtu;  			break;  		default: -			error("sco_get: unknown option %d", opt); +			g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS, +					"Unknown option %d", opt);  			return FALSE;  		} @@ -663,8 +677,8 @@ static gboolean sco_get(int sock, BtIOOption opt1, va_list args)  	return TRUE;  } -static gboolean get_valist(GIOChannel *io, BtIOType type, BtIOOption opt1, -								va_list args) +static gboolean get_valist(GIOChannel *io, BtIOType type, GError **err, +						BtIOOption opt1, va_list args)  {  	int sock; @@ -673,18 +687,20 @@ static gboolean get_valist(GIOChannel *io, BtIOType type, BtIOOption opt1,  	switch (type) {  	case BT_IO_L2RAW:  	case BT_IO_L2CAP: -		return l2cap_get(sock, opt1, args); +		return l2cap_get(sock, err, opt1, args);  	case BT_IO_RFCOMM: -		return rfcomm_get(sock, opt1, args); +		return rfcomm_get(sock, err, opt1, args);  	case BT_IO_SCO: -		return sco_get(sock, opt1, args); +		return sco_get(sock, err, opt1, args);  	} +	g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS, +			"Unknown BtIO type %d", type);  	return FALSE;  }  gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data, -						GDestroyNotify destroy) +					GDestroyNotify destroy, GError **err)  {  	int sock;  	char c; @@ -696,9 +712,12 @@ gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data,  	pfd.fd = sock;  	pfd.events = POLLOUT; -	if (poll(&pfd, 1, 0) < 0) -		error("poll: %s (%d)", strerror(errno), errno); -	else if (!(pfd.revents & POLLOUT)) +	if (poll(&pfd, 1, 0) < 0) { +		ERROR_FAILED(err, "poll", errno); +		return FALSE; +	} + +	if (!(pfd.revents & POLLOUT))  		read(sock, &c, 1);  	accept_add(io, connect, user_data, destroy); @@ -706,7 +725,8 @@ gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data,  	return TRUE;  } -gboolean bt_io_set(GIOChannel *io, BtIOType type, BtIOOption opt1, ...) +gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err, +							BtIOOption opt1, ...)  {  	va_list args;  	gboolean ret; @@ -716,7 +736,7 @@ gboolean bt_io_set(GIOChannel *io, BtIOType type, BtIOOption opt1, ...)  	memset(&opts, 0, sizeof(opts));  	va_start(args, opt1); -	ret = set_valist(io, &opts, opt1, args); +	ret = set_valist(io, &opts, err, opt1, args);  	va_end(args);  	if (!ret) @@ -727,107 +747,92 @@ gboolean bt_io_set(GIOChannel *io, BtIOType type, BtIOOption opt1, ...)  	switch (type) {  	case BT_IO_L2RAW:  	case BT_IO_L2CAP: -		if (l2cap_set(sock, opts.sec_level, opts.imtu, opts.omtu) < 0) -			return FALSE; -		break; +		return l2cap_set(sock, opts.sec_level, opts.imtu, opts.omtu, +									err);  	case BT_IO_RFCOMM: -		if (rfcomm_set(sock, opts.sec_level) < 0) -			return FALSE; -		break; +		return rfcomm_set(sock, opts.sec_level, err);  	case BT_IO_SCO: -		if (sco_set(sock, opts.mtu) < 0) -			return FALSE; -		break; +		return sco_set(sock, opts.mtu, err);  	} -	return ret; +	g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS, +			"Unknown BtIO type %d", type); +	return FALSE;  } -gboolean bt_io_get(GIOChannel *io, BtIOType type, BtIOOption opt1, ...) +gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err, +							BtIOOption opt1, ...)  {  	va_list args;  	gboolean ret;  	va_start(args, opt1); -	ret = get_valist(io, type, opt1, args); +	ret = get_valist(io, type, err, opt1, args);  	va_end(args);  	return ret;  } -static GIOChannel *create_io(BtIOType type, gboolean server, struct set_opts *opts) +static GIOChannel *create_io(BtIOType type, gboolean server, +					struct set_opts *opts, GError **err)  { -	int sock, err; +	int sock;  	GIOChannel *io;  	switch (type) {  	case BT_IO_L2RAW:  		sock = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);  		if (sock < 0) { -			error("socket: %s (%d)", strerror(errno), errno); +			ERROR_FAILED(err, "socket(RAW, L2CAP)", errno);  			return NULL;  		} -		err = l2cap_bind(sock, &opts->src, server ? opts->psm : 0); -		if (err < 0) { -			error("l2cap_bind: %s (%d)", strerror(-err), -err); +		if (l2cap_bind(sock, &opts->src, server ? opts->psm : 0) < 0) { +			ERROR_FAILED(err, "l2cap_bind", errno);  			return NULL;  		} -		err = l2cap_set(sock, opts->sec_level, 0, 0); -		if (err < 0) { -			error("l2cap_set: %s (%d)", strerror(-err), -err); +		if (!l2cap_set(sock, opts->sec_level, 0, 0, err))  			return NULL; -		}  		break;  	case BT_IO_L2CAP:  		sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);  		if (sock < 0) { -			error("socket: %s (%d)", strerror(errno), errno); +			ERROR_FAILED(err, "socket(SEQPACKET, L2CAP)", errno);  			return NULL;  		} -		err = l2cap_bind(sock, &opts->src, server ? opts->psm : 0); -		if (err < 0) { -			error("l2cap_bind: %s (%d)", strerror(-err), -err); +		if (l2cap_bind(sock, &opts->src, server ? opts->psm : 0) < 0) { +			ERROR_FAILED(err, "l2cap_bind", errno);  			return NULL;  		} -		err = l2cap_set(sock, opts->sec_level, opts->imtu, opts->omtu); -		if (err < 0) { -			error("l2cap_set: %s (%d)", strerror(-err), -err); +		if (!l2cap_set(sock, opts->sec_level, opts->imtu, opts->omtu, +									err))  			return NULL; -		}  		break;  	case BT_IO_RFCOMM:  		sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);  		if (sock < 0) { -			error("socket: %s (%d)", strerror(errno), errno); +			ERROR_FAILED(err, "socket(STREAM, RFCOMM)", errno);  			return NULL;  		} -		err = rfcomm_bind(sock, &opts->src, server ? opts->channel : 0); -		if (err < 0) { -			error("rfcomm_bind: %s (%d)", strerror(-err), -err); +		if (rfcomm_bind(sock, &opts->src, +					server ? opts->channel : 0) < 0) { +			ERROR_FAILED(err, "rfcomm_bind", errno);  			return NULL;  		} -		err = rfcomm_set(sock, opts->sec_level); -		if (err < 0) { -			error("rfcomm_set: %s (%d)", strerror(-err), -err); +		if (!rfcomm_set(sock, opts->sec_level, err))  			return NULL; -		}  		break;  	case BT_IO_SCO:  		sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);  		if (sock < 0) { -			error("socket: %s (%d)", strerror(errno), errno); +			ERROR_FAILED(err, "socket(SEQPACKET, SCO)", errno);  			return NULL;  		} -		err = sco_bind(sock, &opts->src); -		if (err < 0) { -			error("sco_bind: %s (%d)", strerror(-err), -err); +		if (sco_bind(sock, &opts->src) < 0) { +			ERROR_FAILED(err, "sco_bind", errno);  			return NULL;  		} -		err = sco_set(sock, opts->mtu); -		if (err < 0) { -			error("sco_set: %s (%d)", strerror(-err), -err); +		if (!sco_set(sock, opts->mtu, err))  			return NULL; -		}  		break;  	} @@ -840,7 +845,7 @@ static GIOChannel *create_io(BtIOType type, gboolean server, struct set_opts *op  GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,  				gpointer user_data, GDestroyNotify destroy, -				BtIOOption opt1, ...) +				GError **gerr, BtIOOption opt1, ...)  {  	GIOChannel *io;  	va_list args; @@ -851,13 +856,13 @@ GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,  	memset(&opts, 0, sizeof(opts));  	va_start(args, opt1); -	ret = set_valist(io, &opts, opt1, args); +	ret = set_valist(io, &opts, gerr, opt1, args);  	va_end(args);  	if (ret == FALSE)  		return NULL; -	io = create_io(type, FALSE, &opts); +	io = create_io(type, FALSE, &opts, gerr);  	if (io == NULL)  		return NULL; @@ -878,8 +883,9 @@ GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,  		break;  	} -	if (ret < 0) { -		error("connect: %s (%d)", strerror(-err), -err); +	if (err < 0) { +		g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED, +				"connect: %s (%d)", strerror(-err), -err);  		g_io_channel_unref(io);  		return NULL;  	} @@ -891,7 +897,8 @@ GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,  GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,  				BtIOConfirm confirm, gpointer user_data, -				GDestroyNotify destroy, BtIOOption opt1, ...) +				GDestroyNotify destroy, GError **err, +				BtIOOption opt1, ...)  {  	GIOChannel *io;  	va_list args; @@ -899,21 +906,24 @@ GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,  	int sock;  	gboolean ret; -	if (type == BT_IO_L2RAW) +	if (type == BT_IO_L2RAW) { +		g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS, +				"Server L2CAP RAW sockets not supported");  		return NULL; +	}  	memset(&opts, 0, sizeof(opts));  	opts.defer = DEFAULT_DEFER_TIMEOUT;  	va_start(args, opt1); -	ret = set_valist(io, &opts, opt1, args); +	ret = set_valist(io, &opts, err, opt1, args);  	va_end(args);  	if (ret == FALSE)  		return NULL; -	io = create_io(type, TRUE, &opts); +	io = create_io(type, TRUE, &opts, err);  	if (io == NULL)  		return NULL; @@ -933,3 +943,9 @@ GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,  	return io;  } + +GQuark bt_io_error_quark(void) +{ +	return g_quark_from_static_string("bt-io-error-quark"); +} + diff --git a/common/btio.h b/common/btio.h index 834e8527..614a1632 100644 --- a/common/btio.h +++ b/common/btio.h @@ -27,6 +27,17 @@  #include <glib.h>  typedef enum { +	BT_IO_ERROR_DISCONNECTED, +	BT_IO_ERROR_CONNECT_FAILED, +	BT_IO_ERROR_FAILED, +	BT_IO_ERROR_INVALID_ARGS, +} BtIOError; + +#define BT_IO_ERROR bt_io_error_quark() + +GQuark bt_io_error_quark(void); + +typedef enum {  	BT_IO_L2RAW,  	BT_IO_L2CAP,  	BT_IO_RFCOMM, @@ -50,21 +61,24 @@ typedef enum {  typedef void (*BtIOConfirm)(GIOChannel *io, gpointer user_data); -typedef void (*BtIOConnect)(GIOChannel *io, int err, gpointer user_data); +typedef void (*BtIOConnect)(GIOChannel *io, GError *err, gpointer user_data);  gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data, -						GDestroyNotify destroy); +					GDestroyNotify destroy, GError **err); -gboolean bt_io_set(GIOChannel *io, BtIOType type, BtIOOption opt1, ...); +gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err, +						BtIOOption opt1, ...); -gboolean bt_io_get(GIOChannel *io, BtIOType type, BtIOOption opt1, ...); +gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err, +						BtIOOption opt1, ...);  GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,  				gpointer user_data, GDestroyNotify destroy, -				BtIOOption opt1, ...); +				GError **err, BtIOOption opt1, ...);  GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,  				BtIOConfirm confirm, gpointer user_data, -				GDestroyNotify destroy, BtIOOption opt1, ...); +				GDestroyNotify destroy, GError **err, +				BtIOOption opt1, ...);  #endif diff --git a/test/btiotest.c b/test/btiotest.c index cb672abb..723f5002 100644 --- a/test/btiotest.c +++ b/test/btiotest.c @@ -94,20 +94,20 @@ static gboolean disconn_timeout(gpointer user_data)  	return FALSE;  } -static void connect_cb(GIOChannel *io, int err, gpointer user_data) +static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)  {  	struct io_data *data = user_data;  	GIOCondition cond;  	char addr[18]; -	if (!bt_io_get(io, data->type, BT_IO_OPT_DEST, addr, +	if (!bt_io_get(io, data->type, NULL, BT_IO_OPT_DEST, addr,  			BT_IO_OPT_INVALID)) {  		printf("Unable to get destination address\n");  		strcpy(addr, "(unknown)");  	}  	if (err) { -		printf("Connecting failed: %s\n", strerror(err)); +		printf("Connecting failed: %s\n", err->message);  		return;  	} @@ -116,7 +116,7 @@ static void connect_cb(GIOChannel *io, int err, gpointer user_data)  	if (data->type == BT_IO_L2CAP) {  		uint16_t omtu, imtu; -		if (!bt_io_get(io, data->type, +		if (!bt_io_get(io, data->type, NULL,  					BT_IO_OPT_OMTU, &omtu,  					BT_IO_OPT_IMTU, &imtu,  					BT_IO_OPT_INVALID)) @@ -163,7 +163,7 @@ static gboolean confirm_timeout(gpointer user_data)  	io_data_ref(data);  	if (!bt_io_accept(data->io, connect_cb, data, -				(GDestroyNotify) io_data_unref)) { +				(GDestroyNotify) io_data_unref, NULL)) {  		printf("bt_io_accept() failed\n");  		io_data_unref(data);  	} @@ -176,8 +176,8 @@ static void confirm_cb(GIOChannel *io, gpointer user_data)  	char addr[18];  	struct io_data *data = user_data; -	if (!bt_io_get(io, data->type, BT_IO_OPT_DEST, addr, -			BT_IO_OPT_INVALID)) +	if (!bt_io_get(io, data->type, NULL, BT_IO_OPT_DEST, addr, +							BT_IO_OPT_INVALID))  		printf("Unable to get destination address\n");  	else  		printf("Got confirmation request for %s\n", addr); @@ -196,7 +196,8 @@ static void confirm_cb(GIOChannel *io, gpointer user_data)  	if (data->accept == 0) {  		if (!bt_io_accept(io, connect_cb, data, -					(GDestroyNotify) io_data_unref)) { +					(GDestroyNotify) io_data_unref, +					NULL)) {  			printf("bt_io_accept() failed\n");  			io_data_unref(data);  			return; @@ -214,6 +215,7 @@ static void l2cap_connect(const char *src, const char *dst, uint16_t psm,  								gint disconn)  {  	struct io_data *data; +	GError *err = NULL;  	printf("Connecting to %s L2CAP PSM %u\n", dst, psm); @@ -222,6 +224,7 @@ static void l2cap_connect(const char *src, const char *dst, uint16_t psm,  	if (src)  		data->io = bt_io_connect(BT_IO_L2CAP, connect_cb, data,  						(GDestroyNotify) io_data_unref, +						&err,  						BT_IO_OPT_SOURCE, src,  						BT_IO_OPT_DEST, dst,  						BT_IO_OPT_PSM, psm, @@ -229,12 +232,14 @@ static void l2cap_connect(const char *src, const char *dst, uint16_t psm,  	else  		data->io = bt_io_connect(BT_IO_L2CAP, connect_cb, data,  						(GDestroyNotify) io_data_unref, +						&err,  						BT_IO_OPT_DEST, dst,  						BT_IO_OPT_PSM, psm,  						BT_IO_OPT_INVALID);  	if (!data->io) { -		printf("Connecting to %s failed\n", dst); +		printf("Connecting to %s failed: %s\n", dst, err->message); +		g_error_free(err);  		exit(EXIT_FAILURE);  	}  } @@ -262,12 +267,14 @@ static void l2cap_listen(const char *src, uint16_t psm, gint defer,  	if (src)  		l2_srv = bt_io_listen(BT_IO_L2CAP, conn, cfm,  					data, (GDestroyNotify) io_data_unref, +					NULL,  					BT_IO_OPT_SOURCE, src,  					BT_IO_OPT_PSM, psm,  					BT_IO_OPT_INVALID);  	else  		l2_srv = bt_io_listen(BT_IO_L2CAP, conn, cfm,  					data, (GDestroyNotify) io_data_unref, +					NULL,  					BT_IO_OPT_PSM, psm,  					BT_IO_OPT_INVALID); @@ -291,6 +298,7 @@ static void rfcomm_connect(const char *src, const char *dst, uint8_t ch,  	if (src)  		data->io = bt_io_connect(BT_IO_RFCOMM, connect_cb, data,  						(GDestroyNotify) io_data_unref, +						NULL,  						BT_IO_OPT_SOURCE, src,  						BT_IO_OPT_DEST, dst,  						BT_IO_OPT_CHANNEL, ch, @@ -298,6 +306,7 @@ static void rfcomm_connect(const char *src, const char *dst, uint8_t ch,  	else  		data->io = bt_io_connect(BT_IO_RFCOMM, connect_cb, data,  						(GDestroyNotify) io_data_unref, +						NULL,  						BT_IO_OPT_DEST, dst,  						BT_IO_OPT_CHANNEL, ch,  						BT_IO_OPT_INVALID); @@ -331,12 +340,14 @@ static void rfcomm_listen(const char *src, uint8_t ch, gboolean defer,  	if (src)  		rc_srv = bt_io_listen(BT_IO_RFCOMM, conn, cfm,  					data, (GDestroyNotify) io_data_unref, +					NULL,  					BT_IO_OPT_SOURCE, src,  					BT_IO_OPT_CHANNEL, ch,  					BT_IO_OPT_INVALID);  	else  		rc_srv = bt_io_listen(BT_IO_RFCOMM, conn, cfm,  					data, (GDestroyNotify) io_data_unref, +					NULL,  					BT_IO_OPT_CHANNEL, ch,  					BT_IO_OPT_INVALID); | 
