< Bluetooth & Socket Options | Winsock2 Supported Protocols Main | Bluetooth Win32 Example (cont.) >


 

 

Winsock 2: Other Supported Protocols 4 Part 18

 

 

What do we have in this chapter 4 part 18?

  1. The Microsoft SDK Classic Sample

 

The Microsoft SDK Classic Sample

 

Create a new empty Win32 console mode application and add the project/solution name.

 

The Microsoft SDK Classic Sample: Creating a new empty Win32 console mode application and adding the project/solution name.

 

Add the following source code.

 

// BTHCxnDemo.cpp - Simple Bluetooth application using Winsock 2.2 and RFCOMM protocol

//

//      This is a part of the Microsoft Source Code Samples.

//      Copyright 1996 - 2002 Microsoft Corporation.

//      All rights reserved.

//      This source code is only intended as a supplement to

//      Microsoft Development Tools and/or WinHelp documentation.

//      See these sources for detailed information regarding the

//      Microsoft samples programs.

//

//      This example demonstrates how to use Winsock-2.2 APIs to connect

//      between two remote bluetooth devices and transfer data between them.

//      This example only supports address family of type AF_BTH,

//      socket of type SOCK_STREAM, protocol of type BTHPROTO_RFCOMM.

//

//      Once this source code is built, the resulting application can be

//      run either in server mode or in client mode.  See command line help

//      for command-line-examples and detailed explanation about all options.

 

#include <stdio.h>

#include <initguid.h>

// Link to ws2_32.lib

#include <winsock2.h>

#include <ws2bth.h>

 

// {B62C4E8D-62CC-404b-BBBF-BF3E3BBB1374}

DEFINE_GUID(g_guidServiceClass, 0xb62c4e8d, 0x62cc, 0x404b, 0xbb, 0xbf, 0xbf, 0x3e, 0x3b, 0xbb, 0x13, 0x74);

 

#define CXN_BDADDR_STR_LEN                17   // 6 two-digit hex values plus 5 colons

#define CXN_TRANSFER_DATA_LENGTH          100  // length of the data to be transferred

#define CXN_MAX_INQUIRY_RETRY             3

#define CXN_DELAY_NEXT_INQUIRY            15

 

char g_szRemoteName[BTH_MAX_NAME_SIZE + 1] = {0};  // 1 extra for trailing NULL character

char g_szRemoteAddr[CXN_BDADDR_STR_LEN + 1] = {0}; // 1 extra for trailing NULL character

// This just redundant!!!!

int  g_ulMaxCxnCycles = 1, g_iOutputLevel = 0;

 

ULONG NameToBthAddr( const char * pszRemoteName,  BTH_ADDR * pRemoteBthAddr);

ULONG AddrStringToBtAddr(IN const char * pszRemoteAddr, OUT BTH_ADDR * pRemoteBtAddr);

// ULONG RunClientMode( ULONGLONG ululRemoteBthAddr,  int iMaxCxnCycles = 1);

ULONG RunClientMode( ULONGLONG ululRemoteBthAddr,  int iMaxCxnCycles);

// ULONG RunServerMode( int iMaxCxnCycles = 1);

ULONG RunServerMode( int iMaxCxnCycles);

void  ShowCmdLineHelp(void);

ULONG ParseCmdLine( int argc, char * argv[]);

 

int main(int argc, char *argv[])

{

    ULONG      ulRetCode = 0;

    WSADATA    WSAData = {0};

    ULONGLONG  ululRemoteBthAddr = 0;

 

     ShowCmdLineHelp();

    // Parse the command line

    if (  ( ulRetCode = ParseCmdLine(argc, argv) ) == 0 )

    {

        // Ask for Winsock version 2.2.

        if ( ( ulRetCode = WSAStartup(MAKEWORD(2, 2), &WSAData) ) != 0 )

        {

            printf("-FATAL- | Unable to initialize Winsock version 2.2\n");

            goto CleanupAndExit;

        }

        else

            printf("WSAStartup() is OK!\n");

 

        if ( g_szRemoteName[0] != '\0' )

        {

            printf("Running in the client mode...\n");

            // Get address from name of the remote device and run the application in client mode

            if ( ( ulRetCode = NameToBthAddr(g_szRemoteName, (BTH_ADDR *) &ululRemoteBthAddr) ) != 0)

            {

                printf("-FATAL- | Unable to get address of the remote radio having name %s\n", g_szRemoteName);

                goto CleanupAndExit;

            }

 

            ulRetCode = RunClientMode(ululRemoteBthAddr, g_ulMaxCxnCycles);

        }

        else if ( g_szRemoteAddr[0] != '\0' )

       {

            printf("Running in the client mode...\n");

            // Get address from formatted address-string of the remote device and run the application in client mode

            //  should be calling the WSAStringToAddress()

            if ( 0 != ( ulRetCode = AddrStringToBtAddr(g_szRemoteAddr, (BTH_ADDR *) &ululRemoteBthAddr) ) )

            {

                printf("-FATAL- | Unable to get address of the remote radio having formatted address-string %s\n", g_szRemoteAddr);

                goto CleanupAndExit;

            }

 

            ulRetCode = RunClientMode(ululRemoteBthAddr, g_ulMaxCxnCycles);

        }

        else

        {

            // No remote name/address specified.  Run the application in server mode

            printf("No remote name/address specified, running the server mode...\n");

            ulRetCode = RunServerMode(g_ulMaxCxnCycles);

        }

    }

    else if ( ulRetCode == 1)

    {

        // Command line syntax error.  Display cmd line help

        ShowCmdLineHelp();

    }

    else

    {

        printf("-FATAL- | Error in parsing the command line!\n");

    }

 

    CleanupAndExit:

    return (int) (ulRetCode);

}

 

// This just redundant!!!!

//

// TODO: use inquiry timeout SDP_DEFAULT_INQUIRY_SECONDS

// NameToBthAddr converts a bluetooth device name to a bluetooth address,

// if required by performing inquiry with remote name requests.

// This function demonstrates device inquiry, with optional LUP flags.

ULONG NameToBthAddr(const char * pszRemoteName, BTH_ADDR * pRemoteBtAddr)

{

    INT          iResult = 0, iRetryCount = 0;

    BOOL         bContinueLookup = FALSE, bRemoteDeviceFound = FALSE;

    ULONG        ulFlags = 0, ulPQSSize = sizeof(WSAQUERYSET);

    HANDLE       hLookup = 0;

    PWSAQUERYSET pWSAQuerySet = NULL;

 

    if ( ( pszRemoteName == NULL) || ( pRemoteBtAddr == NULL) )

    {

        printf("Remote name or address is NULL!\n");

        goto CleanupAndExit;

    }

 

    if ( ( pWSAQuerySet = (PWSAQUERYSET) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ulPQSSize) )  == NULL)

    {

        printf("!ERROR! | Unable to allocate memory for WSAQUERYSET!\n");

        goto CleanupAndExit;

    }

    else

        printf("HeapAlloc() for WSAQUERYSET is OK!\n");

 

    // Search for the device with the correct name

    for (iRetryCount = 0; !bRemoteDeviceFound && (iRetryCount < CXN_MAX_INQUIRY_RETRY); iRetryCount++)

    {

        // WSALookupServiceXXX() is used for both service search and device inquiry

        // LUP_CONTAINERS is the flag which signals that we're doing a device inquiry. 

        ulFlags = LUP_CONTAINERS;

        // Friendly device name (if available) will be returned in lpszServiceInstanceName

        ulFlags |= LUP_RETURN_NAME;

        // BTH_ADDR will be returned in lpcsaBuffer member of WSAQUERYSET

        ulFlags |= LUP_RETURN_ADDR;

        // Similar to:

        // ulFlags = LUP_CONTAINERS | LUP_RETURN_NAME | LUP_RETURN_ADDR;

 

        if ( iRetryCount == 0)

        {

            printf("*INFO* | Inquiring device from cache...\n");

        }

        else

        {

            // Flush the device cache for all inquiries, except for the first inquiry

            //

            // By setting LUP_FLUSHCACHE flag, we're asking the lookup service to do

            // a fresh lookup instead of pulling the information from device cache.

            ulFlags |= LUP_FLUSHCACHE;

 

            // Pause for some time before all the inquiries after the first inquiry

            //

            // Remote Name requests will arrive after device inquiry has

            // completed.  Without a window to receive IN_RANGE notifications,

            // we don't have a direct mechanism to determine when remote

            // name requests have completed.

            printf("*INFO* | Unable to find device.  Waiting for %d seconds before re-inquiry...\n", CXN_DELAY_NEXT_INQUIRY);

            printf("I am sleeping for a while...\n");

            Sleep(CXN_DELAY_NEXT_INQUIRY * 1000);

 

            printf("*INFO* | Inquiring device ...\n");

        }

 

        // Start the lookup service

        iResult = 0;

        hLookup = 0;

        bContinueLookup = FALSE;

        ZeroMemory(pWSAQuerySet, ulPQSSize);

        pWSAQuerySet->dwNameSpace = NS_BTH;

        pWSAQuerySet->dwSize = sizeof(WSAQUERYSET);

 

        iResult = WSALookupServiceBegin(pWSAQuerySet, ulFlags, &hLookup);

 

        if ( ( iResult == NO_ERROR) && (hLookup != NULL) )

        {

            printf("WSALookupServiceBegin() is fine!\n");

            bContinueLookup = TRUE;

        }

        else if ( 0 < iRetryCount )

        {

            printf("=CRITICAL= | WSALookupServiceBegin() failed with error code %d, Error = %d\n", iResult, WSAGetLastError());

            goto CleanupAndExit;

        }

 

        while ( bContinueLookup )

        {

            // Get information about next bluetooth device

            //

            // Note you may pass the same WSAQUERYSET from LookupBegin

            // as long as you don't need to modify any of the pointer

            // members of the structure, etc.

            //

            // ZeroMemory(pWSAQuerySet, ulPQSSize);

            // pWSAQuerySet->dwNameSpace = NS_BTH;

            // pWSAQuerySet->dwSize = sizeof(WSAQUERYSET);

            if ( WSALookupServiceNext(hLookup, ulFlags, &ulPQSSize, pWSAQuerySet) == NO_ERROR)

            {

                printf("WSALookupServiceNext() is OK lol!\n");

 

                if ( ( pWSAQuerySet->lpszServiceInstanceName != NULL ))

                {

                    // Found a remote bluetooth device with matching name.

                    // Get the address of the device and exit the lookup.

                    printf("Again, remote name: %S\n",pWSAQuerySet->lpszServiceInstanceName);

                    // Need to convert to the 'standard' address format

                    printf("Local address: %012X\n",pWSAQuerySet->lpcsaBuffer->LocalAddr);

                    printf("Remote address: %012X\n",pWSAQuerySet->lpcsaBuffer->RemoteAddr);

                    CopyMemory(pRemoteBtAddr, &((PSOCKADDR_BTH) pWSAQuerySet->lpcsaBuffer->RemoteAddr.lpSockaddr)->btAddr,

                                                 sizeof(*pRemoteBtAddr));

                    bRemoteDeviceFound = TRUE;

                    bContinueLookup = FALSE;

                }

            }

            else

            {

                if ( ( iResult = WSAGetLastError() ) == WSA_E_NO_MORE) //No more data

                {

                    // No more devices found.  Exit the lookup.

                    printf("No more device found...\n");

                    bContinueLookup = FALSE;

                }

                else if ( iResult == WSAEFAULT)

                {

                    // The buffer for QUERYSET was insufficient.

                    // In such case 3rd parameter "ulPQSSize" of function "WSALookupServiceNext()" receives

                    // the required size.  So we can use this parameter to reallocate memory for QUERYSET.

                    HeapFree(GetProcessHeap(), 0, pWSAQuerySet);

                    pWSAQuerySet = NULL;

                    if ( NULL == ( pWSAQuerySet = (PWSAQUERYSET) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ulPQSSize) ) )

                    {

                        printf("!ERROR! | Unable to allocate memory for WSAQERYSET...\n");

                        bContinueLookup = FALSE;

                    }

                    else

                        printf("HeapAlloc() for WSAQERYSET is OK!\n");

                }

                else

                {

                    printf("=CRITICAL= | WSALookupServiceNext() failed with error code %d\n", iResult);

                    bContinueLookup = FALSE;

                }

            }

        }

        // End the lookup service

        WSALookupServiceEnd(hLookup);

    }

 

CleanupAndExit:

    if ( NULL != pWSAQuerySet )

    {

        HeapFree(GetProcessHeap(), 0, pWSAQuerySet);

        pWSAQuerySet = NULL;

    }

 

    if ( bRemoteDeviceFound )

    {

        return(0);

    }

    else

    {

        return(1);

    }

}

 

// This just redundant!!!!

//

// Convert a formatted BTH address string to populate a BTH_ADDR (actually a ULONGLONG)

ULONG AddrStringToBtAddr(const char * pszRemoteAddr, BTH_ADDR * pRemoteBtAddr)

{

    ULONG ulAddrData[6], ulRetCode = 0;

    BTH_ADDR BtAddrTemp = 0;

            int i;

 

    if ( ( pszRemoteAddr == NULL) || ( pRemoteBtAddr == NULL) )

    {

        ulRetCode = 1;

        goto CleanupAndExit;

    }

 

    *pRemoteBtAddr = 0;

 

    // Populate a 6 membered array of unsigned long integers

    // by parsing the given address in string format

    sscanf_s(pszRemoteAddr, "%02x:%02x:%02x:%02x:%02x:%02x", &ulAddrData[0],&ulAddrData[1],&ulAddrData[2],

                                        &ulAddrData[3],&ulAddrData[4],&ulAddrData[5]);

 

    // Construct a BTH_ADDR from 6 integers stored in the array

    printf("Constructing the BTH_ADDR...\n");

    for ( i=0; i<6; i++ )

    {

        // Extract data from the first 8 lower bits.

        BtAddrTemp = (BTH_ADDR)( ulAddrData[i] & 0xFF );

        // Push 8 bits to the left

        *pRemoteBtAddr = ( (*pRemoteBtAddr) << 8 ) + BtAddrTemp;

    }

            printf("Remote address: 0X%X\n", pRemoteBtAddr);

 

    CleanupAndExit:

    return ulRetCode;

}

 

// RunClientMode runs the application in client mode.  It opens a socket, connects it to a

// remote socket, transfer some data over the connection and closes the connection.

ULONG RunClientMode(ULONGLONG ululRemoteAddr, int iMaxCxnCycles)

{

    ULONG              ulRetCode = 0;

    int                iCxnCount = 0;

    char               szData[CXN_TRANSFER_DATA_LENGTH] = {0};

    SOCKET             LocalSocket = INVALID_SOCKET;

    SOCKADDR_BTH       SockAddrBthServer = {0};

 

    // Setting address family to AF_BTH indicates winsock2 to use Bluetooth sockets

    // Port should be set to 0 if ServiceClassId is spesified.

    SockAddrBthServer.addressFamily = AF_BTH;

    SockAddrBthServer.btAddr = (BTH_ADDR) ululRemoteAddr;

    SockAddrBthServer.serviceClassId = g_guidServiceClass;

    // Valid ports are 1 - 31

    SockAddrBthServer.port = 1;

 

    // Create a static data-string, which will be transferred to the remote Bluetooth device

    //  may make this #define and do strlen() of the string

    strncpy_s(szData, sizeof(szData), "~!@#$%^&*()-_=+?<>1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",

                            CXN_TRANSFER_DATA_LENGTH - 1);

 

    // Run the connection/data-transfer for user specified number of cycles

    for ( iCxnCount = 0; (0 == ulRetCode) && (iCxnCount < iMaxCxnCycles || iMaxCxnCycles == 0); iCxnCount++ )

    {

        printf("\n");

 

        // Open a bluetooth socket using RFCOMM protocol

        if ( ( LocalSocket = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM) ) == INVALID_SOCKET)

        {

            printf("=CRITICAL= | socket() call failed. Error = [%d]\n", WSAGetLastError());

            ulRetCode = 1;

            goto CleanupAndExit;

        }

 

        if ( (2 <= g_iOutputLevel) | (LocalSocket != INVALID_SOCKET))

        {

            printf("*INFO* | socket() call succeeded. Socket = [0x%X]\n", LocalSocket);

        }

 

        if ( 1 <= g_iOutputLevel )

        {

            printf("*INFO* | connect() attempt with Remote BTHAddr = [0x%X]\n", ululRemoteAddr);

        }

 

        // Connect the socket (pSocket) to a given remote socket represented by address (pServerAddr)

        if ( connect(LocalSocket, (struct sockaddr *) &SockAddrBthServer, sizeof(SOCKADDR_BTH)) == SOCKET_ERROR)

        {

            printf("=CRITICAL= | connect() call failed. Error=[%d]\n", WSAGetLastError());

            ulRetCode = 1;

            goto CleanupAndExit;

        }

 

        if ( (2 <= g_iOutputLevel) | (connect(LocalSocket, (struct sockaddr *) &SockAddrBthServer, sizeof(SOCKADDR_BTH)) != SOCKET_ERROR) )

        {

            printf("*INFO* | connect() call succeeded!\n");

        }

 

        // send() call indicates winsock2 to send the given data

        // of a specified length over a given connection.

        printf("*INFO* | Sending the following data string:\n\t%s\n", szData);

        if ( send(LocalSocket, szData, CXN_TRANSFER_DATA_LENGTH, 0) == SOCKET_ERROR)

        {

            printf("=CRITICAL= | send() call failed w/socket = [0x%X], szData = [%p], dataLen = [%d]. WSAGetLastError=[%d]\n",

                        LocalSocket, szData, CXN_TRANSFER_DATA_LENGTH, WSAGetLastError());

            ulRetCode = 1;

            goto CleanupAndExit;

        }

 

        if ( 2 <= g_iOutputLevel )

        {

            printf("*INFO* | send() call succeeded\n");

        }

 

        // Close the socket

        if ( SOCKET_ERROR == closesocket(LocalSocket) )

        {

            printf("=CRITICAL= | closesocket() call failed w/socket = [0x%X]. Error=[%d]\n", LocalSocket, WSAGetLastError());

            ulRetCode = 1;

            goto CleanupAndExit;

        }

 

        LocalSocket = INVALID_SOCKET;

 

        if ( 2 <= g_iOutputLevel )

        {

            printf("*INFO* | closesocket() call succeeded!");

        }

    }

 

CleanupAndExit:

    if ( LocalSocket != INVALID_SOCKET)

    {

        closesocket(LocalSocket);

        LocalSocket = INVALID_SOCKET;

    }

 

    return ulRetCode;

}

// RunServerMode runs the application in server mode.  It opens a socket, connects it to a

// remote socket, transfer some data over the connection and closes the connection.

ULONG RunServerMode(int iMaxCxnCycles)

{

    ULONG              ulRetCode = 0;

    int                iAddrLen = sizeof(SOCKADDR_BTH), iCxnCount = 0, iLengthReceived = 0, iTotalLengthReceived = 0;

    char               szDataBuffer[CXN_TRANSFER_DATA_LENGTH] = {0};

    char *             pszDataBufferIndex = NULL;

    LPTSTR             lptstrThisComputerName = NULL;

    DWORD              dwLenComputerName = MAX_COMPUTERNAME_LENGTH + 1;

    SOCKET             LocalSocket = INVALID_SOCKET, ClientSocket = INVALID_SOCKET;

    WSAVERSION         wsaVersion = {0};

    WSAQUERYSET        wsaQuerySet = {0};

    SOCKADDR_BTH       SockAddrBthLocal = {0};

    LPCSADDR_INFO      lpCSAddrInfo = NULL;

    BOOL bContinue;

 

    // Both of these fixed-size allocations can be on the stack

    if ( ( lpCSAddrInfo = (LPCSADDR_INFO) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CSADDR_INFO) ) ) == NULL)

    {

        printf("!ERROR! | Unable to allocate memory for CSADDR_INFO\n");

        ulRetCode = 1;

        goto CleanupAndExit;

    }

    else

       printf("HeapAlloc() for CSADDR_INFO (address) is OK!\n");

 

    if ( ( lptstrThisComputerName = (LPTSTR) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwLenComputerName ) ) == NULL)

    {

        printf("!ERROR! | Unable to allocate memory for CSADDR_INFO\n");

        ulRetCode = 1;

        goto CleanupAndExit;

    }

    else

        printf("HeapAlloc() for CSADDR_INFO (local computer name) is OK!\n");

 

    if ( !GetComputerName(lptstrThisComputerName, &dwLenComputerName) )

    {

        printf("=CRITICAL= | GetComputerName() call failed. WSAGetLastError=[%d]\n", WSAGetLastError());

        ulRetCode = 1;

        goto CleanupAndExit;

    }

    else

    {

        printf("GetComputerName() is pretty fine!\n");

        printf("Local computer name: %S\n", lptstrThisComputerName);

    }

 

    // Open a bluetooth socket using RFCOMM protocol

    printf("Opening local socket using socket()...\n");

    if ( ( LocalSocket = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM) ) == INVALID_SOCKET)

    {

        printf("=CRITICAL= | socket() call failed. WSAGetLastError = [%d]\n", WSAGetLastError());

        ulRetCode = 1;

        goto CleanupAndExit;

    }

 

    if ( (2 <= g_iOutputLevel) | (LocalSocket != INVALID_SOCKET))

    {

        printf("*INFO* | socket() call succeeded! Socket = [0x%X]\n", LocalSocket);

    }

 

    // Setting address family to AF_BTH indicates winsock2 to use Bluetooth port

    SockAddrBthLocal.addressFamily = AF_BTH;

    // Valid ports are 1 - 31

    // SockAddrBthLocal.port = BT_PORT_ANY;

    SockAddrBthLocal.port = 1;

 

    // bind() associates a local address and port combination

    // with the socket just created. This is most useful when

    // the application is a server that has a well-known port

    // that clients know about in advance.

    if ( bind(LocalSocket, (struct sockaddr *) &SockAddrBthLocal, sizeof(SOCKADDR_BTH) )  == SOCKET_ERROR)

    {

        printf("=CRITICAL= | bind() call failed w/socket = [0x%X]. Error=[%d]\n", LocalSocket, WSAGetLastError());

        ulRetCode = 1;

        goto CleanupAndExit;

    }

 

    if ( (2 <= g_iOutputLevel) | (bind(LocalSocket, (struct sockaddr *) &SockAddrBthLocal, sizeof(SOCKADDR_BTH) )  != SOCKET_ERROR))

    {

        printf("*INFO* | bind() call succeeded!\n");

    }

 

    if ( ( ulRetCode = getsockname(LocalSocket, (struct sockaddr *)&SockAddrBthLocal, &iAddrLen) ) == SOCKET_ERROR)

    {

        printf("=CRITICAL= | getsockname() call failed w/socket = [0x%X]. WSAGetLastError=[%d]\n", LocalSocket, WSAGetLastError());

        ulRetCode = 1;

        goto CleanupAndExit;

    }

    else

     {

         printf("getsockname() is pretty fine!\n");

         printf("Local address: 0x%x\n", SockAddrBthLocal.btAddr);

     }

 

    // CSADDR_INFO

    lpCSAddrInfo[0].LocalAddr.iSockaddrLength = sizeof( SOCKADDR_BTH );

    lpCSAddrInfo[0].LocalAddr.lpSockaddr = (LPSOCKADDR)&SockAddrBthLocal;

    lpCSAddrInfo[0].RemoteAddr.iSockaddrLength = sizeof( SOCKADDR_BTH );

    lpCSAddrInfo[0].RemoteAddr.lpSockaddr = (LPSOCKADDR)&SockAddrBthLocal;

    lpCSAddrInfo[0].iSocketType = SOCK_STREAM;

    lpCSAddrInfo[0].iProtocol = BTHPROTO_RFCOMM;

 

    // If we got an address, go ahead and advertise it.

    ZeroMemory(&wsaQuerySet, sizeof(WSAQUERYSET));

    wsaQuerySet.dwSize = sizeof(WSAQUERYSET);

    wsaQuerySet.lpServiceClassId = (LPGUID) &g_guidServiceClass;

    // should be something like "Sample Bluetooth Server"

    wsaQuerySet.lpszServiceInstanceName = lptstrThisComputerName;

    wsaQuerySet.lpszComment = L"Example Service instance registered in the directory service through RnR";

    wsaQuerySet.dwNameSpace = NS_BTH;   

    wsaQuerySet.dwNumberOfCsAddrs = 1;      // Must be 1.

    wsaQuerySet.lpcsaBuffer = lpCSAddrInfo; // Required.

 

    // As long as we use a blocking accept(), we will have a race

    // between advertising the service and actually being ready to

    // accept connections.  If we use non-blocking accept, advertise

    // the service after accept has been called.

    if ( WSASetService(&wsaQuerySet, RNRSERVICE_REGISTER, 0) == SOCKET_ERROR)

    {

        printf("=CRITICAL= | WSASetService() call failed. Error=[%d]\n", WSAGetLastError());

        ulRetCode = 1;

        goto CleanupAndExit;

    }

    else

        printf("WSASetService() looks fine!\n");

 

    // listen() call indicates winsock2 to listen on a given socket for any incoming connection.

    if ( listen(LocalSocket, SOMAXCONN) == SOCKET_ERROR)

    {

        printf("=CRITICAL= | listen() call failed w/socket = [0x%X]. Error=[%d]\n", LocalSocket, WSAGetLastError());

        ulRetCode = 1;

        goto CleanupAndExit;

    }

 

    if ( (2 <= g_iOutputLevel) |  (listen(LocalSocket, SOMAXCONN) != SOCKET_ERROR))

    {

        printf("*INFO* | listen() call succeeded!\n");

    }

 

    for ( iCxnCount = 0; (0 == ulRetCode) && ( (iCxnCount < iMaxCxnCycles) || (iMaxCxnCycles == 0) ); iCxnCount++ )

    {

        printf("\n");

 

        // accept() call indicates winsock2 to wait for any 

        // incoming connection request from a remote socket.

        // If there are already some connection requests on the queue,

        // then accept() extracts the first request and creates a new socket and

        // returns the handle to this newly created socket. This newly created

        // socket represents the actual connection that connects the two sockets.

        if ( ( ClientSocket = accept(LocalSocket, NULL, NULL) ) == INVALID_SOCKET)

        {

            printf("=CRITICAL= | accept() call failed. Error=[%d]\n", WSAGetLastError());

            ulRetCode = 1;

            break; // Break out of the for loop

        }

 

        if ( (2 <= g_iOutputLevel) | (ClientSocket != INVALID_SOCKET))

        {

            printf("*INFO* | accept() call succeeded. CientSocket = [0x%X]\n", ClientSocket);

        }

 

        // Read data from the incoming stream

        bContinue = TRUE;

        pszDataBufferIndex = &szDataBuffer[0];

        while ( bContinue && (iTotalLengthReceived < CXN_TRANSFER_DATA_LENGTH) )

        {

            // recv() call indicates winsock2 to receive data

            // of an expected length over a given connection.

            // recv() may not be able to get the entire length

            // of data at once.  In such case the return value,

            // which specifies the number of bytes received,

            // can be used to calculate how much more data is

            // pending and accordingly recv() can be called again.

            iLengthReceived = recv(ClientSocket, pszDataBufferIndex, (CXN_TRANSFER_DATA_LENGTH - iTotalLengthReceived), 0);

 

            switch ( iLengthReceived )

            {

                case 0: // socket connection has been closed gracefully

                    printf("Socket connection has been closed gracefully!\n");

                    bContinue = FALSE;

                    break;

                case SOCKET_ERROR:

                    printf("=CRITICAL= | recv() call failed. Error=[%d]\n", WSAGetLastError());

                    bContinue = FALSE;

                    ulRetCode = 1;

                    break;

                default: // most cases when data is being read

                    pszDataBufferIndex += iLengthReceived;

                    iTotalLengthReceived += iLengthReceived;

                    if ( (2 <= g_iOutputLevel) |  (iLengthReceived != SOCKET_ERROR))

                    {

                        printf("*INFO* | Receiving data of length = [%d]. Current Total = [%d]\n", iLengthReceived, iTotalLengthReceived);

                    }

                    break;

            }

        }

 

        if (ulRetCode == 0)

        {

            if ( CXN_TRANSFER_DATA_LENGTH != iTotalLengthReceived )

            {

                printf("+WARNING+ | Data transfer aborted mid-stream. Expected Length = [%d], Actual Length = [%d]\n",

                        CXN_TRANSFER_DATA_LENGTH, iTotalLengthReceived);

            }

 

            printf("*INFO* | Received following data string from remote device:\n%s\n", szDataBuffer);

 

            // Close the connection

            if ( closesocket(ClientSocket) == SOCKET_ERROR)

            {

                printf("=CRITICAL= | closesocket() call failed w/socket = [0x%X]. Error=[%d]\n", LocalSocket, WSAGetLastError());

                ulRetCode = 1;

            }

            else

            {

                // Make the connection invalid regardless

                ClientSocket = INVALID_SOCKET;

 

                if ( (2 <= g_iOutputLevel) | (closesocket(ClientSocket) != SOCKET_ERROR) )

                {

                    printf("*INFO* | closesocket() call succeeded w/socket=[0x%X]\n", ClientSocket);

                }

            }

        }

    }

 

    CleanupAndExit:

    if ( INVALID_SOCKET != ClientSocket )

    {

        closesocket(ClientSocket);

        ClientSocket = INVALID_SOCKET;

    }

 

    if ( INVALID_SOCKET != LocalSocket )

    {

        closesocket(LocalSocket);

        LocalSocket = INVALID_SOCKET;

    }

 

    if ( NULL != lptstrThisComputerName )

    {

        HeapFree(GetProcessHeap(), 0, lptstrThisComputerName);

        lptstrThisComputerName = NULL;

    }

 

    if ( NULL != lpCSAddrInfo )

    {

        HeapFree(GetProcessHeap(), 0, lpCSAddrInfo);

        lpCSAddrInfo = NULL;

    }

 

    return ulRetCode;

}

 

// ShowCmdLineSyntaxHelp displays the command line usage

void ShowCmdLineHelp(void)

{

    printf(

          "  Bluetooth example application for demonstrating connection and data transfer."

          "\n"

          "\n  BTHCxnDemo        [-n<RemoteName> | -a<RemoteAddress>] "

          "\n                 [-c<ConnectionCycles>] [-o<Output Level>]"

          "\n"

          "\n  Switches applicable for Client mode:"

          "\n    -n<RemoteName>        Specifies name of remote BlueTooth-Device."

          "\n"

          "\n    -a<RemoteAddress>     Specifies address of remote BlueTooth-Device."

          "\n                          The address is in form XX:XX:XX:XX:XX:XX"

          "\n                          where XX is a hexidecimal byte"

          "\n"

          "\n    One of the above two switches is required for client."

          "\n"

          "\n  Switches applicable for both Client and Server mode:"

          "\n    -c<ConnectionCycles>  Specifies number of connection cycles."

          "\n                          Default value for this parameter is 1.  Specify 0 to "

          "\n                          run infinite number of connection cycles."

          "\n"

          "\n    -o<OutputLevel>       Specifies level of information reporting in cmd window."

          "\n                          Default value for this parameter is 0 (minimal info)."

          "\n                          Possible values: 1 (more info), 2 (all info)."

          "\n"

          "\n  Command Line Examples:"

          "\n    \"BTHCxnDemo -c0\""

          "\n    Runs the BTHCxnDemo server for infinite connection cycles."

          "\n    The application reports minimal information onto the cmd window."

          "\n"

          "\n    \"BTHCxnDemo -nServerDevice -c50 -o2\""

          "\n    Runs the BTHCxnDemo client connecting to remote device (having name "

          "\n    \"ServerDevice\" for 50 connection cycles."

          "\n    The application reports minimal information onto the cmd window."

          "\n\n"

          );

}

 

// ParseCmdLine parses the command line and sets the global variables accordingly.

// It returns 0 if successful, returns 1 if command line usage is to be displayed,

// returns 2 in case of any other error while parsing

ULONG ParseCmdLine (int argc, char * argv[])

{

    int   iStrLen = 0;

    ULONG ulRetCode = 0;

            int i;

 

    for ( i = 1; i < argc; i++ )

    {

        char * pszToken = argv[i];

        if ( *pszToken == '-' || *pszToken == '/' )

        {

            char token;

 

            // skip over the "-" or "/"

            pszToken++;

            // Get the command line option

            token = *pszToken;

            // Go one past the option the option-data

            pszToken++;

            // Get the option-data

            switch ( token )

            {

                case 'n':

                    iStrLen = lstrlen((LPCWSTR)pszToken);

                    if ( (0 < iStrLen) && (BTH_MAX_NAME_SIZE >= iStrLen)  )

                    {

                        lstrcpy((LPWSTR)g_szRemoteName, (LPCWSTR)pszToken);

                        printf("The remote name is %s\n", g_szRemoteName);

                    }

                    else

                    {

                        ulRetCode = 2;

                        printf("!ERROR! | cmd line | Unable to parse -n<RemoteName>, length error (min 1 char, max %d chars)\n", BTH_MAX_NAME_SIZE);

                    }

                    break;

                case 'a':

                    iStrLen = lstrlen((LPCWSTR)pszToken);

                    if ( CXN_BDADDR_STR_LEN == iStrLen )

                    {

                        lstrcpy((LPWSTR)g_szRemoteAddr, (LPCWSTR)pszToken);

                    }

                    else

                    {

                        ulRetCode = 2;

                        printf("!ERROR! | cmd line | Unable to parse -a<RemoteAddress>, Remote bluetooth radio address string length expected %d | Found: %d)\n",

                                    CXN_BDADDR_STR_LEN, iStrLen);

                    }

                    break;

                case 'c':

                    if ( 0 < lstrlen((LPCWSTR)pszToken) )

                    {

                        sscanf_s(pszToken,"%d", &g_ulMaxCxnCycles);

                        if ( 0 > g_ulMaxCxnCycles )

                        {

                            ulRetCode = 2;

                            printf("!ERROR! | cmd line | Must provide +ve or 0 value with -c option\n");

                        }

                    }

                    else

                    {

                        ulRetCode = 2;

                        printf("!ERROR! | cmd line | Must provide a value with -c option\n");

                    }

                    break;

                case 'o':

                    if ( 0 < lstrlen((LPCWSTR)pszToken) )

                    {

                        sscanf_s(pszToken,"%d", &g_iOutputLevel);

                        if ( 0 > g_iOutputLevel )

                        {

                            ulRetCode = 2;

                            printf("!ERROR! | cmd line | Must provide a +ve or 0 value with -o option");

                        }

                    }

                    else

                    {

                        ulRetCode = 2;

                        printf("!ERROR! | cmd line | Must provide a value with -o option");

                    }

                    break;

                case '?':

                case 'h':

                case 'H':

                default:

                    ulRetCode = 1;

            }

        }

        else

        {

            ulRetCode = 1;

            printf("!ERROR! | cmd line | Bad option prefix, use '/' or '-' \n");

        }

    }

 

    return ulRetCode;

}

 

 

 


< Bluetooth & Socket Options | Winsock2 Supported Protocols Main | Bluetooth Win32 Example (cont.) >