btio: Rescue lost errorneous numbers
The BT_IO_ERROR_* flags are not used for anything else and we just
loosing errorneous numbers set in the sockets that might be more
useful for handling specific errors.
A use case would be disconnect errors that should not allow BlueZ to
enable auto connections since the connection would never be possible in
some cases.
This patch removes BT_IO_ERROR_* flags and use the errors set in the
sockets instead. Now, the errors passed in connect/disconnect callbacks
should contain proper error numbers passed to them.
diff --git a/btio/btio.c b/btio/btio.c
index e81fb75..f2a9d4b 100644
--- a/btio/btio.c
+++ b/btio/btio.c
@@ -43,7 +43,7 @@
#endif
#define ERROR_FAILED(gerr, str, err) \
- g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_FAILED, \
+ g_set_error(gerr, BT_IO_ERROR, err, \
str ": %s (%d)", strerror(err), err)
#define DEFAULT_DEFER_TIMEOUT 30
@@ -124,19 +124,29 @@
gpointer user_data)
{
struct accept *accept = user_data;
- GError *err = NULL;
+ GError *gerr = NULL;
/* If the user aborted this accept attempt */
if ((cond & G_IO_NVAL) || check_nval(io))
return FALSE;
- if (cond & (G_IO_HUP | G_IO_ERR))
- g_set_error(&err, BT_IO_ERROR, BT_IO_ERROR_DISCONNECTED,
- "HUP or ERR on socket");
+ if (cond & (G_IO_HUP | G_IO_ERR)) {
+ int err, sk_err, sock = g_io_channel_unix_get_fd(io);
+ socklen_t len = sizeof(sk_err);
- accept->connect(io, err, accept->user_data);
+ if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
+ err = -errno;
+ else
+ err = -sk_err;
- g_clear_error(&err);
+ if (err < 0)
+ g_set_error(&gerr, BT_IO_ERROR, -err,
+ "HUP or ERR on socket");
+ }
+
+ accept->connect(io, gerr, accept->user_data);
+
+ g_clear_error(&gerr);
return FALSE;
}
@@ -146,14 +156,15 @@
{
struct connect *conn = user_data;
GError *gerr = NULL;
+ int err, sk_err, sock;
+ socklen_t len = sizeof(sk_err);
/* If the user aborted this connect attempt */
if ((cond & G_IO_NVAL) || check_nval(io))
return FALSE;
if (cond & G_IO_OUT) {
- int err, sk_err = 0, sock = g_io_channel_unix_get_fd(io);
- socklen_t len = sizeof(sk_err);
+ sock = g_io_channel_unix_get_fd(io);
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
err = -errno;
@@ -161,17 +172,24 @@
err = -sk_err;
if (err < 0)
- 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))
- g_set_error(&gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
- "HUP or ERR on socket");
+ g_set_error(&gerr, BT_IO_ERROR, -err, "%s (%d)",
+ strerror(-err), -err);
+ } else if (cond & (G_IO_HUP | G_IO_ERR)) {
+ sock = g_io_channel_unix_get_fd(io);
+
+ if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
+ err = -errno;
+ else
+ err = -sk_err;
+
+ if (err < 0)
+ g_set_error(&gerr, BT_IO_ERROR, -err,
+ "HUP or ERR on socket");
+ }
conn->connect(io, gerr, conn->user_data);
- if (gerr)
- g_error_free(gerr);
+ g_clear_error(&gerr);
return FALSE;
}
@@ -390,7 +408,7 @@
int ret;
if (level < BT_SECURITY_LOW || level > BT_SECURITY_HIGH) {
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ g_set_error(err, BT_IO_ERROR, EINVAL,
"Valid security level range is %d-%d",
BT_SECURITY_LOW, BT_SECURITY_HIGH);
return FALSE;
@@ -764,7 +782,7 @@
opts->priority = va_arg(args, int);
break;
default:
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ g_set_error(err, BT_IO_ERROR, EINVAL,
"Unknown option %d", opt);
return FALSE;
}
@@ -883,7 +901,7 @@
bacpy(va_arg(args, bdaddr_t *), &dst.l2_bdaddr);
break;
case BT_IO_OPT_DEST_TYPE:
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ g_set_error(err, BT_IO_ERROR, EINVAL,
"Not implemented");
return FALSE;
case BT_IO_OPT_DEFER_TIMEOUT:
@@ -961,7 +979,7 @@
*(va_arg(args, uint32_t *)) = priority;
break;
default:
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ g_set_error(err, BT_IO_ERROR, EINVAL,
"Unknown option %d", opt);
return FALSE;
}
@@ -1068,7 +1086,7 @@
memcpy(va_arg(args, uint8_t *), dev_class, 3);
break;
default:
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ g_set_error(err, BT_IO_ERROR, EINVAL,
"Unknown option %d", opt);
return FALSE;
}
@@ -1151,7 +1169,7 @@
memcpy(va_arg(args, uint8_t *), dev_class, 3);
break;
default:
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ g_set_error(err, BT_IO_ERROR, EINVAL,
"Unknown option %d", opt);
return FALSE;
}
@@ -1180,7 +1198,7 @@
return sco_get(sock, err, opt1, args);
}
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ g_set_error(err, BT_IO_ERROR, EINVAL,
"Unknown BtIO type %d", type);
return FALSE;
}
@@ -1245,7 +1263,7 @@
return sco_set(sock, opts.mtu, err);
}
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ g_set_error(err, BT_IO_ERROR, EINVAL,
"Unknown BtIO type %d", type);
return FALSE;
}
@@ -1334,7 +1352,7 @@
goto failed;
break;
default:
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ g_set_error(err, BT_IO_ERROR, EINVAL,
"Unknown BtIO type %d", type);
return NULL;
}
@@ -1392,14 +1410,14 @@
err = sco_connect(sock, &opts.dst);
break;
default:
- g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ g_set_error(gerr, BT_IO_ERROR, EINVAL,
"Unknown BtIO type %d", type);
return NULL;
}
if (err < 0) {
- g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
- "connect: %s (%d)", strerror(-err), -err);
+ g_set_error(gerr, BT_IO_ERROR, -err, "connect: %s (%d)",
+ strerror(-err), -err);
g_io_channel_unref(io);
return NULL;
}
@@ -1421,7 +1439,7 @@
gboolean ret;
if (type == BT_IO_L2RAW) {
- g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ g_set_error(err, BT_IO_ERROR, EINVAL,
"Server L2CAP RAW sockets not supported");
return NULL;
}
diff --git a/btio/btio.h b/btio/btio.h
index cf0e070..70b32d6 100644
--- a/btio/btio.h
+++ b/btio/btio.h
@@ -26,13 +26,6 @@
#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);