Figure 13   IAS_Query Structure

typedef struct _IAS_QUERY
{
    u_char  irdaDeviceID[4];
    char    irdaClassName[61];
    char    irdaAttribName[61];
    u_short irdaAttribType;
    union
    {
        int irdaAttribInt;
        struct
        {
            int     Len;
            u_char  OctetSeq[1];
            u_char  Reserved[3];
        } irdaAttribOctetSeq;
        struct
        {
            int     Len;
            u_char  CharSet;
            u_char  UsrStr[1];
            u_char  Reserved[2];
        } irdaAttribUsrStr;
    } irdaAttribute;
} IAS_QUERY, *PIAS_QUERY, FAR *LPIAS_QUERY;


Figure 14   build_protocol_list


void build_protocol_list(string &new_list)
{
    new_list="";

    // initialize the transport protocol data structure
    WSAPROTOCOL_INFO spi;
    unsigned long size=sizeof(spi);

    // query WinSock for the number of protocols
    int num=WSAEnumProtocols(0,&spi,&size);
    if (num==SOCKET_ERROR)
    {
        // allocate enough space for all the data structures
        char *buf=new char[size];
        WSAPROTOCOL_INFO *pi=(WSAPROTOCOL_INFO*)buf;

        // start the actual enumeration
        num=WSAEnumProtocols(0,pi,&size);
        for (int i=0;i<num;i++)
        {
            // the szProtocol Field is not Unicode, convert it
            TCHAR wdesc[300];
            wsprintf(wdesc,
                     TEXT("%d;%s\n"),
                     (pi+i)->iAddressFamily,
                     (pi+i)->szProtocol);

            // must convert back to non-Unicode for append
            char desc[sizeof(wdesc)];
            wcstombs(desc,wdesc,wcslen(wdesc)+1);

            new_list+=desc;
        }

        delete [] buf;
    }
}


Figure 15   get_irda_family_id


int get_irda_family_id(string &protocol_list)
{
    // default return value
    int family=-1;

    // look for the id of this service provider
    const char targetServiceProvider[]="MSAFD Irda [IrDA]";

    const char *pstr=protocol_list.c_str();
    while (*pstr && family==-1)
    {
        // identify end of current item
        char *pendstr=strchr(pstr,'\n');
        *pendstr=0;

        // find and remove ';'
        char *ptr=strchr(pstr,';');
        *ptr=0;

        // compare
        if (!strcmp(ptr+1,targetServiceProvider))
        {
            // found it!
            family=atoi(pstr);
        }

        // restore string
        *ptr=';';
        *pendstr='\n';

        // bump to next string
        pstr=pendstr+1;
    }

    return family;
}


Figure 16   Calling the Connect Function


// open a socket
SOCKET sock=socket(AF_IRDA,SOCK_STREAM,0);
if (SOCKET_ERROR!=sock)
{
    // get device info from the devices listbox
    WCHAR wdeviceinfo[100];
    SendMessage(hwnddevices,
                LB_GETTEXT,                                    
                static_cast<WPARAM>(SendMessage(hwnddevices,
                                                LB_GETCURSEL, 0,0)),
                reinterpret_cast<LPARAM>(wdeviceinfo));
    wdeviceinfo[10]=0;

    // convert acsii device ID to binary
    WCHAR* stoppedhere;
    DWORD wdeviceid=(DWORD)wcstol(wdeviceinfo+2,                                 
                                  &stoppedhere,16);

    // fill out address structure with device id and service
    _SOCKADDR_IRDA dest;
    dest.irdaAddressFamily=AF_IRDA;
    memcpy(dest.irdaDeviceID,&wdeviceid,sizeof(wdeviceid));
    strcpy(dest.irdaServiceName,"basic_irda_server");

    // attempt the connection
    if (SOCKET_ERROR!=connect(sock,
                              reinterpret_cast<struct sockaddr *>(&dest),
                              sizeof(dest)))
    {
•••


Figure 17   SOCKADR_IRDA Fragment


SOCKET sock=socket(irda_family_id,SOCK_STREAM,0);
if (sock!=SOCKET_ERROR)
{
    // bind to irda, service name="basic_irda_server"
    _SOCKADDR_IRDA sa;
    memset(&sa,0,sizeof(sa));
    sa.irdaAddressFamily=irda_family_id;
    strcpy(sa.irdaServiceName,"basic_irda_server");

    if (bind(sock,
             reinterpret_cast<struct sockaddr *>(&sa),
             sizeof(sa))!=SOCKET_ERROR)
    {
        // set async for connects
        if (WSAAsyncSelect(sock,
                           hwnd,
                           WM_ASYNC_SOCKMSG,
                           FD_ACCEPT)!=SOCKET_ERROR)
        {
            // listen for connections
            if (listen(sock,
                       min(SOMAXCONN,MAX_SUPPORTED_CONNECTIONS))                 
                !=SOCKET_ERROR)
            {
•••


Figure 18   build_device_list


void build_device_list(string &new_device_list)
{
    // new device list string
    new_device_list="";

    if (irda_family_id!=-1)
    {
        // IrDA is running on this system

        SOCKET sock=socket(irda_family_id,SOCK_STREAM,0);
        if (sock!=SOCKET_ERROR)
        {
            // build device list structure - allow room for 50 devices
            int dl_len=sizeof(DEVICELIST)*sizeof(IRDA_DEVICE_INFO)*49;
            char *buf=new char[dl_len];

            // query for the device list
            int err=getsockopt(sock,
                               SOL_IRLMP,
                               IRLMP_ENUMDEVICES,
                               buf,
                               &dl_len);
            if (err!=SOCKET_ERROR)
            {
                // got the device list
                DEVICELIST *pdl=reinterpret_cast<DEVICELIST*>(buf);
                if (pdl->numDevice)
                {
                    // there are devices, iterate through them
                    for (int i=0;i<pdl->numDevice;i++)
                    {
                        // form a reference to the appropriate device
                        IRDA_DEVICE_INFO &di=pdl->Device[i]; 

                        // format the info into a string, and append to list
                       char buf[100];
                       sprintf(buf,"0x%08x; %04x %04x %04x; %s\n",
                                    *reinterpret_cast<DWORD*>(&di.irdaDeviceID),
                                    (WORD)di.irdaDeviceHints1,
                                    (WORD)di.irdaDeviceHints2,
                                    (WORD)di.irdaCharSet,
                                    di.irdaDeviceName);
                        new_device_list+=buf;
                    }
                }
            }

            delete [] buf; // delete the device buffer

            closesocket(sock);
        }
    }
}


Figure 19   getsockopt and IAS_QUERY


SOCKET sock=socket(AF_IRDA,SOCK_STREAM,0);
 if (SOCKET_ERROR!=sock) {
     // get device info from the devices listbox
     WCHAR wdeviceinfo[100];
     SendMessage(hwnddevices,
                 LB_GETTEXT,
                 static_cast<WPARAM>(SendMessage(hwnddevices,LB_GETCURSEL,0,0)),
                 reinterpret_cast<LPARAM>(wdeviceinfo));
     wdeviceinfo[10]=0;

     // convert acsii device ID to binary
     WCHAR* stoppedhere;
     DWORD wdeviceid=(DWORD)wcstol(wdeviceinfo+2,&stoppedhere,16);

     // the content of the edit box specifies the class to verify
     WCHAR wclassname[200];
     GetWindowText(hwnddata,wclassname,sizeof(wclassname));

     // convert the class name to mbcs
     char classname[200];
     wcstombs(classname,wclassname,wcslen(wclassname)+1);

     // initialize the query structure
     _IAS_QUERY iasq;
     memset(&iasq,0,sizeof(iasq));
     int iasqlen=sizeof(iasq);

     // copy in the device id, classname, and attribute
     memcpy(iasq.irdaDeviceID,&wdeviceid,sizeof(wdeviceid));
     strcpy(iasq.irdaClassName,classname);

     // this means: return me the LSAP-SEL for the above class
     strcpy(iasq.irdaAttribName,"IrDA:TinyTP:LsapSel");

     // do the query
     if (SOCKET_ERROR!=getsockopt(sock,
                                  SOL_IRLMP,
                                  IRLMP_IAS_QUERY,
                                  reinterpret_cast<char*>(&iasq),
                                  &iasqlen)==SOCKET_ERROR)
     {
         // the query worked
         switch (iasq.irdaAttribType) {
             case IAS_ATTRIB_NO_CLASS: {
                 // the class does not exist on the remote machine
                 MessageBox(hwnd,TEXT("Could not find class."),
                                 TEXT("IAS Query Result:"),
                                 MB_OK);
             } break;

             case IAS_ATTRIB_NO_ATTRIB: {
                 MessageBox(hwnd,TEXT("Could not find attribute."),
                                 TEXT("IAS Query Result:"),
                                 MB_OK);
             } break;

             default: {
                 // otherwise, that machine is running that service!
                 MessageBox(hwnd,TEXT("Class / Attribute found"),
                                 TEXT("IAS Query Result:"),
                                 MB_OK);
             } break;
         }
     }
•••