< Winsock 2 & Bluetooth APIs | Winsock2 Supported Protocols Main | Bluetooth Win32 Example >
What do we have in this chapter 4 part 17?
|
Bluetooth and Socket Options
Socket options are set and queried using the setsockopt() and getsockopt() functions, respectively. All of the following options can be used with the setsockopt() function, but only the SO_BTH_MTU option is available for use with the getsockopt() function. The following settings are required for working with Bluetooth socket options:
SO_BTH_AUTHENTICATE
For disconnected sockets, the SO_BTH_AUTHENTICATE specifies that authentication is required for a connect() or accept() operation to complete successfully. Setting this socket option actively initiates authentication during connection establishment, if the two Bluetooth devices were not previously authenticated. The user interface for passkey exchange, if necessary, is provided by the operating system outside the application context. For outgoing connections that require authentication, the connect() operation fails with WSAEACCES if authentication is not successful. In response, the application may prompt the user to authenticate the two Bluetooth devices before connection. For incoming connections, the connection is rejected if authentication cannot be established and returns a WSAEHOSTDOWN error. The BluetoothAuthenticateDevice function can be used to send an authentication request to a remote Bluetooth device. For the SO_BTH_AUTHENTICATE socket option, optval is a pointer to ULONG bAuthenticate and must be TRUE; optlen is equivalent to "sizeof(ULONG)". For Windows XP with SP2, the SO_BTH_AUTHENTICATE starts authentication for connected sockets, and forces authentication upon connection for unconnected sockets. For incoming connections, the connection is rejected if authentication cannot be performed.
SO_BTH_ENCRYPT
On unconnected sockets, the SO_BTH_ENCRYPT socket option enforces encryption to establish a connection. Encryption is only available for authenticated connections. For incoming connections, a connection for which encryption cannot be established is automatically rejected and returns WSAEHOSTDOWN as the error. For outgoing connections, the connect function fails with WSAEACCES if encryption cannot be established. In response, the application may prompt the user to authenticate the two Bluetooth devices before connection. For the SO_BTH_ENCRYPT socket option, optval is a pointer to ULONG bEncrypt and must be TRUE; optlen is equivalent to sizeof(ULONG). For Windows XP with SP2, a socket that is connected and authenticated, SO_BTH_ENCRYPT starts encryption. |
The SO_BTH_MTU socket option is an advanced option used primarily for validation. The SO_BTH_MTU option obtains or sets default RFCOMM MTU (maximum transmission unit) for connection negotiation to a value different than the RFCOMM protocol-default value.
Because RFCOMM MTU is affected by the underlying L2CAP MTU, and protocol and application minimums and maximums, the default value for SO_BTH_MTU is only a starting point for negotiation with the remote peer, and the final negotiated MTU is likely to vary from the default. Setting the SO_BTH_MTU value may negatively affect throughput, and as such, any modification should be performed with knowledge of the underlying Bluetooth protocol.
The SO_BTH_MTU socket option can be performed on connected sockets, but has no effect if the negotiation has already completed. Setting it on the listening (server) socket has no effect.
The amount of data that an application can send or receive in a single socket call is not affected by the MTU; MTU only affects how the underlying Windows Sockets service provider segments packets for transport. Both the proposed MTU and the MTU ultimately negotiated must be between RFCOMM_MIN_MTU and RFCOMM_MAX_MTU, as defined in the Ws2bth.h header file.
For the SO_BTH_MTU socket option, optval is a pointer to ULONG mtu; optlen is equivalent to "sizeof(ULONG)".
The SO_BTH_MTU_MAX socket option is an advanced option used primarily for validation. The SO_BTH_MTU_MAX socket option sets the maximum RFCOMM MTU (maximum transmission unit) for connection negotiation. Connections with an RFCOMM MTU equal to or greater than this value fail during the connect/accept process. While setting this socket option is allowed for a connected socket, it has no effect if the negotiation has completed. Setting this socket option on a listening socket propagates the value for all incoming connections. The MAX MTU value must be between RFCOMM_MIN_MTU and RFCOMM_MAX_MTU, as defined in the Ws2bth.h header file. For the SO_BTH_MTU_MAX socket option, optval is a pointer to ULONG max_mtu; optlen is equivalent to "sizeof(ULONG)".
The SO_BTH_MTU_MIN socket option is an advanced option used primarily for validation. The SO_BTH_MTU_MIN socket option sets the minimum RFCOMM MTU (maximum transmission unit) for connection negotiation. Connections with an RFCOMM MTU smaller than this value fail during the connect/accept process. While setting this socket option is allowed for a connected socket, it has no effect if the negotiation has completed. Setting this socket option on a listening socket propagates the value for all incoming connections.
Only a listening socket can revise the MTU downward, therefore if the value proposed by the connecting socket is less than the value set for SO_BTH_MTU_MIN on the listening socket, the connection is refused. The minimum MTU must be between RFCOMM_MIN_MTU and RFCOMM_MAX_MTU, as defined in the Ws2bth.h header file. For the SO_BTH_MTU_MIN socket option, optval is a pointer to ULONG min_mtu; optlen is equivalent to "sizeof(ULONG)".
The following sender and receiver program examples are using Microsoft Bluetooth stack. This means the program run will fail on the machine which using WIDCOMM stack.
Add the following source code.
// Link to ws2_32.lib
#include <winsock2.h>
#include <ws2bth.h>
#include <BluetoothAPIs.h>
#include <stdio.h>
#define DEFAULT_BUFLEN 512
int main(int argc, char **argv)
{
WSADATA wsd;
SOCKET s, s2;
SOCKADDR_BTH sab, sab2;
// NULL_GUID
GUID nguiD = {00000000-0000-0000-0000-000000000000};
int ilen, iResult;
// This should be const void * type for non-char data
char *sendbuf = "Test data from receiver...";
int recvbuflen = DEFAULT_BUFLEN;
// Change the type accordingly for non-char data
char recvbuf[DEFAULT_BUFLEN] = "";
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
{
printf("Unable to load Winsock! Error code is %d\n", WSAGetLastError());
return 1;
}
else
printf("WSAStartup() is OK, Winsock lib loaded!\n");
s = socket (AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
if (s == INVALID_SOCKET)
{
printf ("Socket creation failed, error %d\n", WSAGetLastError());
return 1;
}
else
printf ("socket() looks fine!\n");
memset (&sab, 0, sizeof(sab));
sab.addressFamily = AF_BTH;
// We hardcoded it
sab.port = 1;
if (0 != bind(s, (SOCKADDR *) &sab, sizeof(sab)))
{
printf ("bind() failed with error code %d\n", WSAGetLastError());
closesocket (s);
return;
}
else
printf ("bind() looks fine!\n");
if(listen (s, 5) == 0)
printf("listen() is OK! Listening for connection...\n");
else
printf("listen() failed with error code %d\n", WSAGetLastError());
for ( ; ; )
{
// Get information on the port assigned
ilen = sizeof(sab2);
s2 = accept (s, (SOCKADDR *)&sab2, &ilen);
if (s2 == INVALID_SOCKET)
{
printf ("accept() failed with error code %d\n", WSAGetLastError ());
break;
}
else
printf ("accept(), is OK buddy!\n");
// Print the info
printf ("Connection came from %04x%08x to channel %d\n", GET_NAP(sab2.btAddr), GET_SAP(sab2.btAddr), sab2.port);
}
// Receive until the peer closes the connection
do {
iResult = recv(s2, recvbuf, recvbuflen, 0);
if (iResult > 0)
printf(" %d Bytes received from sender\n", iResult);
else if ( iResult == 0 )
printf("Connection closed by peer!\n");
else
printf("recv() failed with error code %d\n", WSAGetLastError());
} while(iResult > 0);
// Echo back the data
iResult = send(s2, recvbuf, recvbuflen, 0 );
if (iResult == SOCKET_ERROR)
{
printf("send() failed with error code %d\n", WSAGetLastError());
closesocket(s2);
WSACleanup();
return 1;
}
else
{
printf("send() is OK!\n");
printf("Bytes Sent: %d\n", iResult);
}
if(closesocket(s) == 0)
printf("closesocket() pretty fine!\n");
if(WSACleanup () == 0)
printf("WSACleanup() is OK!\n");
return 0;
}
Build and run the project and the following is a sample output.
-------------------------------------------------------
Create a new empty Win32 console mode application and add the project/solution name.
Add the following source code.
// Link to ws2_32.lib
#include <winsock2.h>
#include <ws2bth.h>
#include <BluetoothAPIs.h>
#include <stdio.h>
#define DEFAULT_BUFLEN 512
typedef ULONGLONG bt_addr, *pbt_addr, BT_ADDR, *PBT_ADDR;
int main(int argc, char **argv)
{
WSADATA wsd;
SOCKET s;
SOCKADDR_BTH sab;
// Hard coded directly, got it from the receiver/server
BT_ADDR aSddr = 0X001DD9EA24D8;
int iResult;
// This should be const void * type for non-char data
char *sendbuf = "Test data from client...";
int recvbuflen = DEFAULT_BUFLEN;
// Change the type accordingly for non-char data
char recvbuf[DEFAULT_BUFLEN] = "";
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
{
printf("Unable to load Winsock! Error code is %d\n", WSAGetLastError());
return 1;
}
else
printf("WSAStartup() is OK, Winsock lib loaded!\n");
s = socket (AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
if (s == INVALID_SOCKET)
{
printf ("Socket creation failed, error %d\n", WSAGetLastError());
WSACleanup();
return 1;
}
else
printf ("socket() looks fine!\n");
memset (&sab, 0, sizeof(sab));
sab.addressFamily = AF_BTH;
// Set the btAddr member to a BT_ADDR variable that
// contains the address of the target device. App
// can accept the device address as a string but must convert
// the address and store it in a variable of type BT_ADDR.
sab.btAddr = aSddr;
// If the service identifier is available, then set the
// serviceClassId member of SOCKADDR_BTH to the GUID of
// the RFCOMM-based service. In this case, the client
// performs an SDP query and then uses the resulting server channel.
// sab.serviceClassId = nguiD;
// Or If you want to use a hard-coded channel number, set the
// port member of SOCKADDR_BTH to the server channel number (1-31)
sab.port = 1;
// Connect to the Bluetooth socket, created previously
if (connect (s, (SOCKADDR *)&sab, sizeof(sab)) == SOCKET_ERROR)
{
printf("connect() failed with error code %d\n", WSAGetLastError ());
closesocket(s);
WSACleanup();
return 1;
}
else
printf("connect() should be fine!\n");
// Send some data
iResult = send(s, sendbuf, (int)strlen(sendbuf), 0 );
if (iResult == SOCKET_ERROR) {
printf("send() failed with error code %d\n", WSAGetLastError());
closesocket(s);
WSACleanup();
return 1;
}
else
{
printf("send() is OK!\n");
printf("Bytes Sent: %d\n", iResult);
}
// shutdown the stream connection since no more data will be sent
iResult = shutdown(s, SD_SEND);
if (iResult == SOCKET_ERROR)
{
printf("shutdown() failed with error code %d\n", WSAGetLastError());
closesocket(s);
WSACleanup();
return 1;
}
else
printf("shutdown() is working!\n");
// receive
// Receive until the peer closes the connection
do {
iResult = recv(s, recvbuf, recvbuflen, 0);
if (iResult > 0)
printf(" %d Bytes received from sender\n", iResult);
else if (iResult == 0)
printf("Connection was closed by peer!\n");
else
printf("recv() failed with error code %d\n", WSAGetLastError());
} while(iResult > 0);
// Do all the cleanup
if(closesocket(s) == 0)
printf("closesocket() pretty fine!\n");
if(WSACleanup () == 0)
printf("WSACleanup() is OK!\n");
return 0;
}
The receiver address has been hardcoded and there is no authentication for the sending. Build and run the project and the following screenshot shows a sample output.
< Winsock 2 & Bluetooth APIs | Winsock2 Supported Protocols Main | Bluetooth Win32 Example >