-- v2: ws2_32: Support bind for Bluetooth RFCOMM addresses. ws2_32: Add bind tests for Bluetooth RFCOMM sockets. server: Add support for creating Bluetooth RFCOMM sockets.
From: Vibhav Pant vibhavp@gmail.com
--- dlls/ws2_32/tests/sock.c | 48 ++++++++++++++++++++++++++++++++++++++++ include/ws2bth.h | 6 +++++ 2 files changed, 54 insertions(+)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 867a3a7c2e3..0cfe1b62155 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -32,6 +32,10 @@ #include <wsnwlink.h> #include <mswsock.h> #include <mstcpip.h> +#include <bthsdpdef.h> +#include <bluetoothapis.h> +#include <bthdef.h> +#include <ws2bth.h> #include <stdio.h> #include "wine/test.h"
@@ -3712,6 +3716,50 @@ static void test_WSASocket(void) closesocket(sock); } } + + /* Bluetooth RFCOMM socket tests */ + SetLastError(0xdeadbeef); + sock = WSASocketA(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM, NULL, 0, 0); + if (sock == INVALID_SOCKET) + { + ok(WSAGetLastError() == WSAEAFNOSUPPORT, "got error %d\n", WSAGetLastError()); + skip("Bluetooth is not supported\n"); + } + else + { + WSAPROTOCOL_INFOA info; + closesocket(sock); + + sock = WSASocketA(0, SOCK_STREAM, BTHPROTO_RFCOMM, NULL, 0, 0 ); + ok(sock != INVALID_SOCKET, "Failed to create socket: %d\n", WSAGetLastError()); + + size = sizeof(socktype); + socktype = 0xdead; + err = getsockopt(sock, SOL_SOCKET, SO_TYPE, (char *) &socktype, &size); + ok(!err,"getsockopt failed with %d\n", WSAGetLastError()); + ok(socktype == SOCK_STREAM, "Wrong socket type, expected %d received %d\n", + SOCK_STREAM, socktype); + + size = sizeof(WSAPROTOCOL_INFOA); + err = getsockopt(sock, SOL_SOCKET, SO_PROTOCOL_INFOA, (char *) &info, &size); + ok(!err,"getsockopt failed with %d\n", WSAGetLastError()); + ok(info.iProtocol == BTHPROTO_RFCOMM, "expected protocol %d, received %d\n", + BTHPROTO_RFCOMM, info.iProtocol); + ok(info.iAddressFamily == AF_BTH, "expected family %d, received %d\n", + AF_IPX, info.iProtocol); + ok(info.iSocketType == SOCK_STREAM, "expected type %d, received %d\n", + SOCK_DGRAM, info.iSocketType); + closesocket(sock); + + /* SOCK_DGRAM is not supported by Bluetooth */ + SetLastError(0xdeadbeef); + ok(WSASocketA(AF_BTH, SOCK_DGRAM, BTHPROTO_RFCOMM, NULL, 0, 0) == INVALID_SOCKET, + "WSASocketA should have failed\n"); + err = WSAGetLastError(); + ok(err == WSAEAFNOSUPPORT, "Expected 10047, received %d\n", err); + + closesocket(sock); + } }
static void test_WSADuplicateSocket(void) diff --git a/include/ws2bth.h b/include/ws2bth.h index ee28f0122cc..02965efa819 100644 --- a/include/ws2bth.h +++ b/include/ws2bth.h @@ -21,6 +21,12 @@
#include <pshpack1.h>
+#ifndef USE_WS_PREFIX +#define BTHPROTO_RFCOMM 0x03 +#else +#define WS_BTHPROTO_RFCOMM 0x03 +#endif + typedef struct _SOCKADDR_BTH { USHORT addressFamily;
From: Vibhav Pant vibhavp@gmail.com
--- configure | 19 +++++++++++++++ configure.ac | 8 +++++++ dlls/ws2_32/socket.c | 15 ++++++++++++ dlls/ws2_32/tests/sock.c | 3 +-- include/config.h.in | 6 +++++ server/sock.c | 50 +++++++++++++++++++++++++++++++++++++--- 6 files changed, 96 insertions(+), 5 deletions(-)
diff --git a/configure b/configure index 763ba364d3e..1d605f5536a 100755 --- a/configure +++ b/configure @@ -7703,6 +7703,12 @@ if test "x$ac_cv_header_asm_user_h" = xyes then : printf "%s\n" "#define HAVE_ASM_USER_H 1" >>confdefs.h
+fi +ac_fn_c_check_header_compile "$LINENO" "bluetooth/bluetooth.h" "ac_cv_header_bluetooth_bluetooth_h" "$ac_includes_default" +if test "x$ac_cv_header_bluetooth_bluetooth_h" = xyes +then : + printf "%s\n" "#define HAVE_BLUETOOTH_BLUETOOTH_H 1" >>confdefs.h + fi ac_fn_c_check_header_compile "$LINENO" "elf.h" "ac_cv_header_elf_h" "$ac_includes_default" if test "x$ac_cv_header_elf_h" = xyes @@ -8831,6 +8837,19 @@ then : fi
+ac_fn_c_check_header_compile "$LINENO" "bluetooth/rfcomm.h" "ac_cv_header_bluetooth_rfcomm_h" " +#ifdef HAVE_BLUETOOTH_BLUETOOTH_H +#include <bluetooth/bluetooth.h> +#endif + +" +if test "x$ac_cv_header_bluetooth_rfcomm_h" = xyes +then : + printf "%s\n" "#define HAVE_BLUETOOTH_RFCOMM_H 1" >>confdefs.h + +fi + + if test "x$ac_cv_header_sys_xattr_h" = xyes then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether getxattr takes additional arguments" >&5 diff --git a/configure.ac b/configure.ac index 9e32070f610..2c6b4835648 100644 --- a/configure.ac +++ b/configure.ac @@ -379,6 +379,7 @@ AC_CHECK_HEADERS(\ asm/termbits.h \ asm/types.h \ asm/user.h \ + bluetooth/bluetooth.h \ elf.h \ gettext-po.h \ link.h \ @@ -581,6 +582,13 @@ AC_CHECK_HEADERS([libprocstat.h],,, #include <sys/queue.h> #endif])
+AC_CHECK_HEADERS([bluetooth/rfcomm.h],,, +[ +#ifdef HAVE_BLUETOOTH_BLUETOOTH_H +#include <bluetooth/bluetooth.h> +#endif +]) + if test "x$ac_cv_header_sys_xattr_h" = xyes then AC_CACHE_CHECK([whether getxattr takes additional arguments], wine_cv_xattr_extra_args, diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index eb61c588c58..8a87805815c 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -167,6 +167,21 @@ static const WSAPROTOCOL_INFOW supported_protocols[] = .dwMessageSize = UINT_MAX, .szProtocol = L"SPX II", }, + { + .dwServiceFlags1 = XP1_IFS_HANDLES | XP1_GRACEFUL_CLOSE | XP1_GUARANTEED_ORDER | + XP1_GUARANTEED_DELIVERY, + .dwProviderFlags = PFL_MATCHES_PROTOCOL_ZERO, + .ProviderId = {0xadbb1448, 0x7c08, 0x7c08, {0x96, 0x96, 0xda, 0xdb, 0xf8, 0xf9, 0x44, 0x2a}}, + .dwCatalogEntryId = 1040, + .ProtocolChain.ChainLen = 1, + .iVersion = 2, + .iAddressFamily = AF_BTH, + .iMinSockAddr = sizeof(SOCKADDR_BTH), + .iMaxSockAddr = sizeof(SOCKADDR_BTH), + .iSocketType = SOCK_STREAM, + .iProtocol = BTHPROTO_RFCOMM, + .szProtocol = L"MSAFD RfComm [Bluetooth]", + }, };
DECLARE_CRITICAL_SECTION(cs_socket_list); diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 0cfe1b62155..578cc2e6907 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -3383,8 +3383,7 @@ static void test_WSASocket(void) { SetLastError( 0xdeadbeef ); sock = WSASocketA( tests[i].family, tests[i].type, tests[i].protocol, NULL, 0, 0 ); - todo_wine_if (i == 7) - ok(WSAGetLastError() == tests[i].error, "Test %u: got wrong error %u\n", i, WSAGetLastError()); + ok(WSAGetLastError() == tests[i].error, "Test %u: got wrong error %u\n", i, WSAGetLastError()); if (tests[i].error) { ok(sock == INVALID_SOCKET, "Test %u: expected failure\n", i); diff --git a/include/config.h.in b/include/config.h.in index a9a282040f3..7ac924a077c 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -21,6 +21,12 @@ /* Define to 1 if you have the <asm/user.h> header file. */ #undef HAVE_ASM_USER_H
+/* Define to 1 if you have the <bluetooth/bluetooth.h> header file. */ +#undef HAVE_BLUETOOTH_BLUETOOTH_H + +/* Define to 1 if you have the <bluetooth/rfcomm.h> header file. */ +#undef HAVE_BLUETOOTH_RFCOMM_H + /* Define to 1 if you have the <capi20.h> header file. */ #undef HAVE_CAPI20_H
diff --git a/server/sock.c b/server/sock.c index 32d622aaebc..909b10fed49 100644 --- a/server/sock.c +++ b/server/sock.c @@ -87,6 +87,14 @@ # define HAS_IRDA #endif
+#ifdef HAVE_BLUETOOTH_BLUETOOTH_H +# include <bluetooth/bluetooth.h> +# ifdef HAVE_BLUETOOTH_RFCOMM_H +# include <bluetooth/rfcomm.h> +# define HAS_BLUETOOTH +# endif +#endif + #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" @@ -98,6 +106,12 @@ #include "tcpmib.h" #include "wsipx.h" #include "af_irda.h" +#include "bthsdpdef.h" +#include "bluetoothapis.h" +#include "bthdef.h" +#ifdef HAS_BLUETOOTH +#include "ws2bth.h" +#endif #include "wine/afd.h" #include "wine/rbtree.h"
@@ -148,6 +162,9 @@ union unix_sockaddr #ifdef HAS_IRDA struct sockaddr_irda irda; #endif +#ifdef HAS_BLUETOOTH + struct sockaddr_rc rfcomm; +#endif };
static struct list poll_list = LIST_INIT( poll_list ); @@ -569,6 +586,21 @@ static int sockaddr_from_unix( const union unix_sockaddr *uaddr, struct WS_socka } #endif
+#ifdef HAS_BLUETOOTH + case AF_BLUETOOTH: + { + SOCKADDR_BTH win = {0}; + BLUETOOTH_ADDRESS addr = {0}; + + if (wsaddrlen < sizeof(win)) return -1; + win.addressFamily = WS_AF_BTH; + + memcpy( addr.rgBytes, uaddr->rfcomm.rc_bdaddr.b, sizeof( addr.rgBytes )); + win.btAddr = addr.ullLong; + win.port = uaddr->rfcomm.rc_channel; + return sizeof(win); + } +#endif case AF_UNSPEC: return 0;
@@ -1794,6 +1826,9 @@ static int get_unix_family( int family ) #endif #ifdef AF_IRDA case WS_AF_IRDA: return AF_IRDA; +#endif +#ifdef AF_BLUETOOTH + case WS_AF_BTH: return AF_BLUETOOTH; #endif case WS_AF_UNSPEC: return AF_UNSPEC; default: return -1; @@ -1811,11 +1846,16 @@ static int get_unix_type( int type ) } }
-static int get_unix_protocol( int protocol ) +static int get_unix_protocol( int family, int protocol ) { if (protocol >= WS_NSPROTO_IPX && protocol <= WS_NSPROTO_IPX + 255) return protocol;
+#ifdef HAS_BLUETOOTH + if (family == WS_AF_BTH) + return protocol == WS_BTHPROTO_RFCOMM ? BTPROTO_RFCOMM : -1; +#endif + switch (protocol) { case WS_IPPROTO_ICMP: return IPPROTO_ICMP; @@ -1868,11 +1908,13 @@ static int init_socket( struct sock *sock, int family, int type, int protocol )
unix_family = get_unix_family( family ); unix_type = get_unix_type( type ); - unix_protocol = get_unix_protocol( protocol ); + unix_protocol = get_unix_protocol( family, protocol );
if (unix_protocol < 0) { - if (type && unix_type < 0) + if (family && unix_family < 0) + set_win32_error( WSAEAFNOSUPPORT ); + else if (type && unix_type < 0) set_win32_error( WSAESOCKTNOSUPPORT ); else set_win32_error( WSAEPROTONOSUPPORT ); @@ -1908,6 +1950,8 @@ static int init_socket( struct sock *sock, int family, int type, int protocol ) if (sockfd == -1) { if (errno == EINVAL) set_win32_error( WSAESOCKTNOSUPPORT ); + else if (errno == ESOCKTNOSUPPORT && unix_family == AF_BLUETOOTH) + set_win32_error( WSAEAFNOSUPPORT ); else set_win32_error( sock_get_error( errno )); return -1; }
From: Vibhav Pant vibhavp@gmail.com
--- dlls/ws2_32/tests/sock.c | 40 ++++++++++++++++++++++++++++++++++++++++ include/ws2bth.h | 2 ++ 2 files changed, 42 insertions(+)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 578cc2e6907..2aaa64d47b2 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -12806,6 +12806,45 @@ static void test_bind(void) free(adapters); }
+static void test_bind_bluetooth(void) +{ + SOCKADDR_BTH addr = {0}; + SOCKET sock, sock2; + INT err, ret; + + sock = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); + err = WSAGetLastError(); + if (sock == INVALID_SOCKET) + { + ok(err == WSAEAFNOSUPPORT, "got error %d\n", err); + skip("Bluetooth is not supported\n"); + return; + } + + addr.addressFamily = AF_BTH; + addr.btAddr = 0; + addr.port = 200; + ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); + err = WSAGetLastError(); + ok(ret == -1, "expected bind to fail\n"); + todo_wine ok(err == WSAEADDRNOTAVAIL || err == WSAENETDOWN, "got error %d\n", err); + + addr.port = 20; + ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); + err = WSAGetLastError(); + todo_wine ok(!ret || err == WSAENETDOWN, "got error %d\n", err); + + sock2 = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); + ok(sock2 != INVALID_SOCKET, "got error %d\n", WSAGetLastError()); + addr.port = BT_PORT_ANY; + ret = bind(sock2, (struct sockaddr *)&addr, sizeof(addr)); + err = WSAGetLastError(); + todo_wine ok(!ret || err == WSAENETDOWN, "got error %d\n", err); + + closesocket(sock); + closesocket(sock2); +} + /* Test calling methods on a socket which is currently connecting. */ static void test_connecting_socket(void) { @@ -14495,6 +14534,7 @@ START_TEST( sock ) test_connect_completion_port(); test_shutdown_completion_port(); test_bind(); + test_bind_bluetooth(); test_connecting_socket(); test_WSAGetOverlappedResult(); test_nonblocking_async_recv(); diff --git a/include/ws2bth.h b/include/ws2bth.h index 02965efa819..28cb4430f0f 100644 --- a/include/ws2bth.h +++ b/include/ws2bth.h @@ -27,6 +27,8 @@ #define WS_BTHPROTO_RFCOMM 0x03 #endif
+#define BT_PORT_ANY -1 + typedef struct _SOCKADDR_BTH { USHORT addressFamily;
From: Vibhav Pant vibhavp@gmail.com
--- dlls/ws2_32/socket.c | 8 +++++- dlls/ws2_32/tests/sock.c | 6 ++--- server/sock.c | 53 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 4 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 8a87805815c..b51f05e3b5c 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -1173,7 +1173,13 @@ int WINAPI bind( SOCKET s, const struct sockaddr *addr, int len ) return -1; } break; - + case AF_BTH: + if (len < sizeof(SOCKADDR_BTH)) + { + SetLastError( WSAEFAULT ); + return -1; + } + break; default: FIXME( "unknown protocol %u\n", addr->sa_family ); SetLastError( WSAEAFNOSUPPORT ); diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 2aaa64d47b2..38cb9eafc6c 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -12827,19 +12827,19 @@ static void test_bind_bluetooth(void) ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); err = WSAGetLastError(); ok(ret == -1, "expected bind to fail\n"); - todo_wine ok(err == WSAEADDRNOTAVAIL || err == WSAENETDOWN, "got error %d\n", err); + ok(err == WSAEADDRNOTAVAIL || err == WSAENETDOWN, "got error %d\n", err);
addr.port = 20; ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); err = WSAGetLastError(); - todo_wine ok(!ret || err == WSAENETDOWN, "got error %d\n", err); + ok(!ret || err == WSAENETDOWN, "got error %d\n", err);
sock2 = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); ok(sock2 != INVALID_SOCKET, "got error %d\n", WSAGetLastError()); addr.port = BT_PORT_ANY; ret = bind(sock2, (struct sockaddr *)&addr, sizeof(addr)); err = WSAGetLastError(); - todo_wine ok(!ret || err == WSAENETDOWN, "got error %d\n", err); + ok(!ret || err == WSAENETDOWN, "got error %d\n", err);
closesocket(sock); closesocket(sock2); diff --git a/server/sock.c b/server/sock.c index 909b10fed49..181e4af8646 100644 --- a/server/sock.c +++ b/server/sock.c @@ -680,6 +680,24 @@ static socklen_t sockaddr_to_unix( const struct WS_sockaddr *wsaddr, int wsaddrl } #endif
+#ifdef HAS_BLUETOOTH + case WS_AF_BTH: + { + SOCKADDR_BTH win = {0}; + BLUETOOTH_ADDRESS addr = {0}; + + if (wsaddrlen != sizeof(win)) return 0; + memcpy( &win, wsaddr, sizeof(win) ); + addr.ullLong = win.btAddr; + + uaddr->rfcomm.rc_family = AF_BLUETOOTH; + memcpy( &uaddr->rfcomm.rc_bdaddr, addr.rgBytes, sizeof( addr.rgBytes ) ); + /* There can only be a maximum of 30 RFCOMM channels, so UINT8_MAX is safe to use here. */ + uaddr->rfcomm.rc_channel = win.port == BT_PORT_ANY ? UINT8_MAX : win.port; + return sizeof(uaddr->rfcomm); + } +#endif + case WS_AF_UNSPEC: switch (wsaddrlen) { @@ -3065,6 +3083,41 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) if (check_addr_usage( sock, &bind_addr, v6only )) return;
+#ifdef HAS_BLUETOOTH + if (unix_addr.rfcomm.rc_family == AF_BLUETOOTH + && !(unix_addr.rfcomm.rc_channel >= 1 && unix_addr.rfcomm.rc_channel <= 30)) + { + int i; + if (unix_addr.rfcomm.rc_channel != UINT8_MAX) + { + set_error( sock_get_ntstatus( EADDRNOTAVAIL ) ); + return; + } + /* If the RFCOMM channel was set to BT_PORT_ANY, we need to find an available RFCOMM + * channel. The Linux kernel has a similar mechanism, but the channel is only assigned + * on listen(), which we cannot call yet. The other, albeit hacky/race-y way to find an available + * channel is to loop through all valid channel values (1 to 30) until bind() succeeds. + */ + for (i = 1; i <= 30; i++) + { + bind_addr.rfcomm.rc_channel = i; + if (!bind( unix_fd, &bind_addr.addr, unix_len )) + break; + if (errno != EADDRINUSE) + { + set_error( sock_get_ntstatus( errno ) ); + return; + } + } + if (i > 30) + { + + set_error( sock_get_ntstatus( EADDRINUSE ) ); + return; + } + } + else +#endif if (bind( unix_fd, &bind_addr.addr, unix_len ) < 0) { if (errno == EADDRINUSE && sock->reuseaddr)