Infrared Sockets

Infrared Sockets

Infrared sockets, or IrSock, are a new technology first introduced on the Windows CE platform. Infrared sockets allow two PCs to communicate with each other through an infrared serial port. Infrared sockets are now available on Windows 98, Windows Me, Windows 2000, and Windows XP. Infrared sockets differ from traditional sockets in that infrared sockets are designed to take into account the transient nature of portable computing. Infrared sockets present a new name resolution model that will be discussed in the next section.

Addressing

Because most computers with Infrared Data Association (IrDA) devices are likely to move around, traditional name-resolution schemes don't work well. Conventional resolution methods assume that the use of static resources such as name servers, which cannot be used when a person is moving a handheld PC or laptop computer running a network client. To circumvent this problem, IrSock is designed to browse in-range resources in an ad hoc manner without the overhead of a large network, and it doesn't use standard Winsock name service functions or even IP addressing. Instead, the name service has been incorporated into the communication stream, and a new address family has been introduced to support services bound to infrared serial ports. The IrSock address structure includes a service name that describes the application used in bind and connect calls and a device identifier that describes the device on which the service runs. This pair is analogous to the IP address and port number pair used by conventional TCP/IP sockets. The IrSock address structure is defined as

typedef struct _SOCKADDR_IRDA {     u_short     irdaAddressFamily;     u_char      irdaDeviceID[4];     char        irdaServiceName[25]; } SOCKADDR_IRDA, *PSOCKADDR_IRDA, FAR *LPSOCKADDR_IRDA;

The irdaAddressFamily field is always set to AF_IRDA. The irdaDeviceID is a four-character string that uniquely identifies the device on which a particular service is running. This field is ignored when an IrSock server is created. However, the field is significant for a client because it specifies which IrDA device to connect to. (There can be multiple devices in range.) Finally, the irdaServiceName field is the name of the service that the application either will register itself with or is trying to connect to.

Name Resolution

Addressing can be based on IrDA Logical Service Access Point Selectors (LSAP-SELs) or on services registered with the Information Access Services (IAS). The IAS abstracts a service from an LSAP-SEL into a user-friendly text service name, in much the same way that an Internet domain name server maps names to numeric IP addresses. You can use either an LSAP-SEL or a user-friendly name to connect successfully, but user-friendly names require name resolution. For the most part, you shouldn't use the direct LSAP-SEL “address” because its address space for IrDA services is limited. The Windows implementation allows LSAP-SEL integer identifiers in the range of 1 to 127. Essentially, an IAS server can be thought of as a WINS server because it associates an LSAP-SEL with a textual service name.

An actual IAS entry has three fields of importance: class name, attribute, and attribute value. For example, let's say a server wishes to register under the service name MyServer. This is accomplished when the server issues the bind call with the appropriate SOCKADDR_IRDA structure. Once this occurs, an IAS entry is added with a class name MyServer, the attribute Irda:TinyTP:LsapSel, and an attribute value of, say, 3. The attribute value is the next unused LSAP-SEL assigned by the system upon registration. The client, on the other hand, passes in a SOCKADDR_IRDA structure to the connect call. This initiates an IAS lookup for a service with the class name MyServer and the attribute Irda:TinyTP:LsapSel. The IAS query will return the value 3. You also can formulate your own IAS query by using the socket option IRLMP_IAS_QUERY in the getsockopt call.

If you want to bypass IAS altogether (which is not recommended), you can specify an LSAP-SEL address directly for a server name or an endpoint to which a client wants to connect. You should bypass IAS only to communicate with legacy IrDA devices that don't provide any kind of IAS registration (such as infrared-capable printers). You can bypass the IAS registration and lookup by specifying the service name in the SOCKADDR_IRDA structure as LSAP-SEL-xxx, in which xxx is the attribute value between 1 and 127. For a server, this would directly assign the server to the given LSAP-SEL address (assuming the LSAP-SEL address is unused). For a client, this bypasses the IAS lookup and causes an immediate attempt to connect to whatever service is running on that LSAP-SEL.

Enumerating IrDA Devices

Because infrared devices move in and out of range, a method of dynamically listing all available infrared devices within range is necessary. This section describes how to accomplish that. Let's begin with a few platform discrepancies between the Windows CE implementation and the Windows 98, Windows Me, Windows 2000, and Windows XP implementation. Windows CE supported IrSock before the other platforms and provided minimal information about infrared devices. Later, Windows 98, Windows Me, Windows 2000, and Windows XP provided support for IrSock, but they added additional “hint” information that the enumeration request returned. (This hint information will be discussed shortly.) As a result, the AF_IRDA.H header file for Windows CE contains the original, minimal structure definitions; however, the new header file for the other platforms contains conditional structure definitions for each platform that now supports IrSock. We recommend that you use the later AF_IRDA.H header file for consistency.

The way to enumerate nearby infrared devices is by using the IRLMP_ENUM_DEVICES command for getsockopt. A DEVICELIST structure is passed as the optval parameter. There are two structures, one for Windows 98, Windows Me, Windows 2000, and Windows XP and one for Windows CE. They are defined as

typedef struct _WINDOWS_DEVICELIST {     ULONG                       numDevice;     WINDOWS_IRDA_DEVICE_INFO    Device[1]; } WINDOWS_DEVICELIST, *PWINDOWS_DEVICELIST, FAR *LPWINDOWS_DEVICELIST; typedef struct _WCE_DEVICELIST {     ULONG                       numDevice;     WCE_IRDA_DEVICE_INFO        Device[1]; } WCE_DEVICELIST, *PWCE_DEVICELIST;

The only difference between the non–Windows CE platforms structure and the Windows CE structure is that the non–Windows CE structure contains an array of WINDOWS_IRDA_DEVICE_INFO structures as opposed to an array of WCE_IRDA_DEVICE_INFO structures. A conditional #define directive declares DEVICELIST as the appropriate structure depending on the target platform. Likewise, two declarations for the IRDA_DEVICE_INFO structures exist:

typedef struct _WINDOWS_IRDA_DEVICE_INFO {     u_char  irdaDeviceID[4];     char    irdaDeviceName[22];     u_char  irdaDeviceHints1;     u_char  irdaDeviceHints2;     u_char  irdaCharSet; } WINDOWS_IRDA_DEVICE_INFO, *PWINDOWS_IRDA_DEVICE_INFO,    FAR *LPWINDOWS_IRDA_DEVICE_INFO; typedef struct _WCE_IRDA_DEVICE_INFO {     u_char  irdaDeviceID[4];     char    irdaDeviceName[22];     u_char  Reserved[2]; } WCE_IRDA_DEVICE_INFO, *PWCE_IRDA_DEVICE_INFO;

Again, a conditional #define directive declares IRDA_DEVICE_INFO to the correct structure definition depending on the target platform.

As we mentioned earlier, the function to use for the actual enumeration of infrared devices is getsockopt with the option IRLMP_ENUM_DEVICES. The following piece of code lists the device IDs of all infrared devices nearby:

SOCKET      sock; DEVICELIST  devList; DWORD       dwListLen=sizeof(DEVICELIST); sock = WSASocket(AF_IRDA, SOCK_STREAM, 0, NULL, 0,      WSA_FLAG_OVERLAPPED); ... devList.numDevice = 0; dwRet = getsockopt(sock, SOL_IRLMP, IRLMP_ENUMDEVICES,      (char *)&devList, &dwListLen);

Before you pass a DEVICELIST structure into the getsockopt call, don't forget to set the numDevice field to 0. A successful enumeration will set the numDevice field to a value greater than 0 and set an equal number of IRDA_DEVICE_INFO structures in the Device field. Also, in an actual application you probably want to perform getsockopt more than once to check for devices that just moved into range. For example, attempting to discover an infrared device in five tries or less is a good heuristic. Simply place the call in a loop with a short call to the Sleep function after each unsuccessful enumeration.

Now that you know how to enumerate infrared devices, creating a client or a server is simple. The server side of the equation is a bit simpler because it looks like a “normal” server. That is, no extra steps are required. The five general steps for an IrSock server are as follows:

  1. Create a socket of address family AF_IRDA and of socket type SOCK_STREAM.

  2. Fill out a SOCKADDR_IRDA structure with the service name of the server.

  3. Call bind with the socket handle and the SOCKADDR_IRDA structure.

  4. Call listen with the socket handle and the backlog limit.

  5. Block on an accept call for incoming clients.

The steps for a client are a bit more involved because you must enumerate infrared devices. The following four steps are necessary for an IrSock client.

  1. Create a socket of address family AF_IRDA and socket type SOCK_STREAM.

  2. Enumerate available infrared devices by calling getsockopt with the IRLMP_ENUM_DEVICES option.

  3. For each device returned, fill out a SOCKADDR_IRDA structure with the device ID returned and the service name you want to connect to.

  4. Call the connect function with the socket handle and with the SOCKADDR_IRDA structure. Do this for each structure filled out in step 3 until a connect succeeds.

Querying IAS

There are two ways to find out if a given service is running on a particular device. The first method is to attempt a connection to the service; the other is to query IAS for the given service name. Both methods require you to enumerate all infrared devices and attempt a query (or connection) with each device until one of them succeeds or you have exhausted every device. Perform a query by calling getsockopt with the IRLMP_IAS_QUERY option. A pointer to an IAS_QUERY structure is passed as the optval parameter. Again, there are two IAS_QUERY structures, one for Windows 98, Windows Me, Windows 2000, and Windows XP, and another for Windows CE. Here are the definitions of each structure:

typedef struct _WINDOWS_IAS_QUERY {      u_char    irdaDeviceID[4];      char      irdaClassName[IAS_MAX_CLASSNAME];      char      irdaAttribName[IAS_MAX_ATTRIBNAME];      u_long    irdaAttribType;      union     {         LONG   irdaAttribInt;         struct         {             u_long   Len;             u_char   OctetSeq[IAS_MAX_OCTET_STRING];         } irdaAttribOctetSeq;         struct         {             u_long   Len;             u_long   CharSet;             u_char   UsrStr[IAS_MAX_USER_STRING];         } irdaAttribUsrStr;     } irdaAttribute; } WINDOWS_IAS_QUERY, *PWINDOWS_IAS_QUERY, FAR *LPWINDOWS_IAS_QUERY; typedef struct _WCE_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; } WCE_IAS_QUERY, *PWCE_IAS_QUERY;

As you can see, the two structure definitions are similar except for the lengths of certain character arrays.

Performing a query for the LSAP-SEL number of a particular service is simple: set the irdaClassName field to the property string for LSAP-SELs, which is “IrDA:IrLMP:LsapSel”, and set the irdaAttributeName field to the service name you want to query for. In addition, you have to set the irdaDeviceID with a valid device within range.

Creating a Socket

Creating an infrared socket is simple. Few options are required because IrSock supports only connection-oriented streams. The following code illustrates how to create an infrared socket using either the socket or WSASocket call. You must use socket for Windows CE because of its Winsock 1.1 limitation.

 s = socket(AF_IRDA, SOCK_STREAM, 0); s = WSASocket(AF_IRDA, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);

If you want to be specific, you can pass IRDA_PROTO_SOCK_STREAM as the protocol parameter of either function. However, the protocol parameter isn't required because the transport catalog has only one entry of address family AF_IRDA. Specifying AF_IRDA causes that transport entry to be used by default.

Socket Options

Many SO_ socket options aren't meaningful to IrDA. Only SO_LINGER and SO_DONTLINGER are specifically supported. The IrSock-specific socket options are of course supported only on sockets of the address family AF_IRDA. These options are also covered in Chapter 7, which summarizes all socket options and their parameters.

note

You will find a basic client and server IrSock application named IRCLIENT.CPP and IRSERVER.CPP, respectively, on the companion CD.



Network Programming for Microsoft Windows
Network Programming for Microsoft Windows (Microsoft Professional Series)
ISBN: 0735605602
EAN: 2147483647
Year: 2001
Pages: 172
Authors: Anthony Jones

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net