< Another AppleTalk Example | Winsock2 Supported Protocols Main | Bluetooth >


 

 

Winsock 2: Other Supported Protocols 4 Part 10

 

 

What do we have in this chapter 4 part 10?

  1. Asynchronous Transfer Mode (ATM)

  2. The Addressing Scheme

  3. Creating a Socket

  4. Binding a Socket to an SAP

  5. Name Resolution

  6. ATM and Winsock Program Example

 

Asynchronous Transfer Mode (ATM)

 

The Asynchronous Transfer Mode (ATM) protocol is one of the protocols available that is supported by Winsock 2 on Windows 98, Windows Me, Windows 2000, and Windows XP however Asynchronous Transfer Mode (ATM) has been removed in Vista. ATM is usually used for high-speed networking on LANs and WANs and can be used for all types of communication, such as voice, video, and data requiring high-speed communication. In the real application ATM mostly adopted for the trunk or backbone line.

In general, ATM provides guaranteed QOS using Virtual Connections (VCs) on a network. As you will see in a moment, Winsock is capable of using VCs on an ATM network through the ATM address family. An ATM network, as shown in Figure 4-1, typically comprises endpoints (or computers) that are interconnected by switches that bridge an ATM network together.

 

The Asynchronous Transfer Mode (ATM) network

 

Figure 4-1 ATM network

 

There are a few points to be aware of when programming for the ATM protocol. First, ATM is a media type and not really a protocol. That is, ATM is similar to writing Ethernet frames directly on an Ethernet network. Like Ethernet, the ATM protocol doesn't provide flow control. It is a connection-oriented protocol that provides either message or stream modes. This also means that a sending application might overrun the local buffers if data cannot be sent quickly enough. Likewise, a receiving application must post receives frequently; otherwise, when the receiving buffers become full, any additional incoming data might be dropped. If your application requires flow control, one alternative is to use IP over ATM, which is simply the IP protocol running over an ATM network. As a result, the application follows the IP address family. Of course, ATM does offer some advantages over IP, such as a rooted multicast scheme; however, the protocol that best suits you depends on your application's needs.

 

The Addressing Scheme

 

An ATM network has two network interfaces: the user network interface (UNI) and the network node interface (NNI). The UNI interface is the communication established between an endpoint and an ATM switch, while the NNI interface is the communication established between two switches. Each of these interfaces has a related communication protocol. These are described here:

 

  1. UNI signaling protocol: Allows an endpoint to establish communication on an ATM network by sending setup and control information between an endpoint and an ATM switch. Note that this protocol is limited to transmissions between an endpoint and an ATM switch and isn't directly transmitted over an ATM network through switches.
  2. NNI signaling protocol: Allows an ATM switch to communicate routing and control information between two switches.

 

For purposes of setting up an ATM connection through Winsock, we will only discuss certain information elements in the UNI signaling protocol. Winsock on Windows XP, Windows 2000, Windows Me, and Windows 98 (service pack 1) supports the UNI version 3.1 signaling protocol.

Winsock allows a client/server application to communicate over an ATM network by setting up an SAP to form connections using the ATM UNI signaling protocol. ATM is a connection-oriented protocol that requires endpoints to establish virtual connections across an ATM network for communication. An SAP simply allows Winsock applications to register and identify a socket interface for communication on an ATM network through a SOCKADDR_ATM address structure. Once an SAP is established, Winsock uses the SAP to establish a virtual connection between a Winsock client and server over ATM by making calls to the ATM network using the UNI signaling protocol. The SOCKADDR_ATM structure is defined as:

 

typedef struct sockaddr_atm

{

    u_short      satm_family;

    ATM_ADDRESS  satm_number;

    ATM_BLLI     satm_blli;

    ATM_BHLI     satm_bhli;

} sockaddr_atm, SOCKADDR_ATM, *PSOCKADDR_ATM, *LPSOCKADDR_ATM;

 

The satm_family field should always be set to AF_ATM. The satm_number field represents an actual ATM address represented as an ATM_ADDRESS structure using one of two basic ATM addressing schemes: E.164 and Network Service Access Point (NSAP). NSAP addresses are also referred to as an NSAP-style ATM Endsystem Address (AESA). The ATM_ADDRESS structure is defined as:

 

typedef struct

{

    DWORD AddressType;

    DWORD NumofDigits;

    UCHAR Addr[ATM_ADDR_SIZE];

} ATM_ADDRESS;

 

The AddressType field defines the specified addressing scheme. This should be set to ATM_E164 for the E.164 addressing scheme and ATM_NSAP for the NSAP-style addressing scheme. In addition, the AddressType field can be set to other values defined in Table 4-2 when an application tries to bind a socket to an SAP, which we will discuss in more detail later in this chapter. The NumofDigits field should always be set to ATM_ADDR_SIZE. The Addr field represents an actual ATM 20-byte E.164 or NSAP address.

The satm_blli and satm_bhli fields of the SOCKADDR_ATM structure represent Broadband Lower Layer Information (BLLI) and Broadband Higher Layer Information (BHLI) in ATM UNI signaling, respectively. In general, these structures are used to identify the protocol stack that operates over an ATM connection. Several well-known combinations of BHLI and BLLI values are described in ATM Form/IETF documents. (A particular combination of values identifies a connection as being used by LAN Emulation over ATM, another combination identifies native IP over ATM, and so on.) Complete ranges of values for the fields in these structures are given in the ATM UNI 3.1 standards book. ATM Form/IETF documents can be found at www.ietf.org.

 

Table 4-2 ATM Socket Address Types

 

ATM_ADDRESS AddressType Setting

Type of Address

ATM_E164

An E.164 address; applies when connecting to an SAP

ATM_NSAP

An NSAP-style ATM Endsystem Address (AESA); applies when connecting to an SAP

SAP_FIELD_ANY_AESA_SEL

An NSAP-style ATM Endsystem Address with the selector octet wildcarded; applies to binding a socket to an SAP

SAP_FIELD_ANY_AESA_REST

An NSAP-style ATM Endsystem Address with all the octets except for the selector octet wildcarded; applies to binding a socket to an SAP

 

The BHLI and BLLI data structures are defined as:

 

typedef struct

{

    DWORD HighLayerInfoType;

    DWORD HighLayerInfoLength;

    UCHAR HighLayerInfo[8];

} ATM_BHLI;

 

typedef struct

{

    DWORD Layer2Protocol;

    DWORD Layer2UserSpecifiedProtocol;

    DWORD Layer3Protocol;

    DWORD Layer3UserSpecifiedProtocol;

    DWORD Layer3IPI;

    UCHAR SnapID[5];

} ATM_BLLI;

 

Further details of the definition and use of these fields are beyond the scope of this book. An application that simply wants to form Winsock communication over an ATM network should set the following fields in the BHLI and BLLI structures to the SAP_FIELD_ABSENT value:

 

  1. ATM_BLLI - Layer2Protocol
  2. ATM_BLLI - Layer3Protocol
  3. ATM_BHLI - HighLayerInfoType

 

When these fields are set to this value, none of the other fields in either structure are used. The following pseudocode demonstrates how an application might use the SOCKADDR_ATM structure to set up an SAP for an NSAP address:

 

SOCKADDR_ATM atm_addr;

UCHAR MyAddress[ATM_ADDR_SIZE];

 

atm_addr.satm_family                 = AF_ATM;

atm_addr.satm_number.AddressType     = ATM_NSAP;

atm_addr.satm_number.NumofDigits     = ATM_ADDR_SIZE;

atm_addr.satm_blli.Layer2Protocol    = SAP_FIELD_ABSENT;

atm_addr.satm_blli.Layer3Protocol    = SAP_FIELD_ABSENT;

atm_addr.satm_bhli.HighLayerInfoType = SAP_FIELD_ABSENT;

 

memcpy(&atm_addr.satm_number.Addr, MyAddress, ATM_ADDR_SIZE);

 

ATM addresses are normally represented as a hexadecimal ASCII string of 40 characters, which corresponds to the 20 bytes that make up either an NSAP-style or an E.164 address in an ATM_ADDRESS structure. For example, an ATM NSAP-style address might look like this:

 

47000580FFE1000000F21A1D540000D10FED5800

 

Converting this string to a 20-byte address can be a tedious task. However, Winsock provides a protocol-independent API function, WSAStringToAddress(), which can allow you to convert a 40-character ATM hexadecimal ASCII string to an ATM_ADDRESS structure. Another way to convert a hexadecimal ASCII string to hexadecimal (binary) format is to use the function AtoH() defined in the following code. This function isn't part of Winsock. However, it is simple enough to develop, and you will see it used in the ATM sample described later.

 

// Function: AtoH

//

// Description: This function coverts the ATM

// address specified in string (ASCII) format to

// binary (hexadecimal) format

void AtoH(CHAR *szDest, CHAR *szSource, INT iCount)

{

    while (iCount--)

    {

        *szDest++ = (BtoH (*szSource++) << 4)

            + BtoH (*szSource++);

    }

    return;

}

 

// Function: BtoH

// Description: This function returns the equivalent

// binary value for an individual character specified

// in ASCII format

UCHAR BtoH (CHAR ch)

{

    if ( ch >= '0' && ch <= '9' )

    {

        return (ch - ‘0’);

    }

 

    if ( ch >= 'A' && ch <= 'F' )

    {

        return (ch - 'A' + 0xA );

    }

 

    if (ch >= 'a' && ch <= 'f' )

    {

        return (ch - 'a' + 0xA);

    }

 

    // Illegal values in the address will not be accepted

    return -1;

}

 

 

Creating a Socket

 

In ATM, applications can create only connection-oriented sockets because ATM allows communication only over a VC. Therefore, data can be transmitted either as a stream of bytes or in a message-oriented fashion. To open a socket using the ATM protocol, call the socket function or the WSASocket() function with the address family AF_ATM and the socket type SOCK_RAW, and set the protocol field to ATMPROTO_AAL5. For example:

 

s = socket(AF_ATM, SOCK_RAW, ATMPROTO_AAL5);

 

s = WSASocket(AF_ATM, SOCK_RAW, ATMPROTO_AAL5, NULL, 0, WSA_FLAG_OVERLAPPED);

 

By default, opening a socket (as in the example) creates a stream-oriented ATM socket. Windows also features an ATM provider that can perform message-oriented data transfers. Using the message-oriented provider requires you to explicitly specify the native ATM protocol provider to the WSASocket() function by using a WSAPROTOCOL_INFO structure. This is necessary because the three elements in the socket call and the WSASocket() call (address family, socket type, and protocol) match every ATM provider available in Winsock. By default, Winsock returns the protocol entry that matches those three attributes and is marked as default, which in this case is the stream-oriented provider. The following pseudocode demonstrates how to retrieve the ATM message-oriented provider and establish a socket:

 

dwRet = WSAEnumProtocols(NULL, lpProtocolBuf, &dwBufLen);

 

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

{

    if ((lpProtocolBuf[i].iAddressFamily == AF_ATM) &&

       (lpProtocolBuf[i].iSocketType == SOCK_RAW) &&

       (lpProtocolBuf[i].iProtocol == ATMPROTO_AAL5) &&

       (lpProtocolBuf[i].dwServiceFlags1 & XP1_MESSAGE_ORIENTED))

    {

        s = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,

            FROM_PROTOCOL_INFO, lpProtocolBuf[i], 0, WSA_FLAG_OVERLAPPED);

    }

}

 

Binding a Socket to an SAP

 

ATM addresses are actually quite complicated because the 20 bytes they comprise contain many informational elements. Winsock application programmers need not worry about all the specific details of these elements with the exception of the last byte. The last byte in NSAP-style and E.164 addresses represents a selector value that uniquely allows your application to define and specify a particular SAP on an endpoint. As we described earlier, Winsock uses an SAP to form communication over an ATM network.

When Winsock applications want to communicate over ATM, a server application must register an SAP on an endpoint and wait for a client application to connect on the registered SAP. For a client application, this simply involves setting up a SOCKADDR_ATM structure with the ATM_E164 or ATM_NSAP address type and supplying the ATM address associated with the server's SAP. To create an SAP to listen for connections, your application must first create a socket for the AF_ATM address family. Once the socket is created, your application must define a SOCKADDR_ATM structure using the SAP_FIELD_ANY_AESA_SEL, SAP_FIELD_ANY_AESA_REST, ATM_E164, or ATM_ NSAP address type as defined in Table 4-2. For an ATM socket, an SAP will be created once your application calls the Winsock bind() API function and these address types define how Winsock creates an SAP on your endpoint.

The address type SAP_FIELD_ANY_AESA_SEL tells Winsock to create an SAP that is capable of listening for any incoming ATM Winsock connection, which is known as wildcarding an ATM address and the selector. This means that only one socket can be bound to this endpoint listening for any connection; if another socket tries to bind with this address type, it will fail with Winsock error WSAEADDRINUSE. However, you can have another socket bound explicitly to your endpoint on a particular selector. The address type SAP_FIELD_ANY_AESA_REST can be used to create an SAP that is explicitly bound to a specified selector on an endpoint. This is known as wildcarding only the ATM address and not the selector. You can have only one socket at a time bound to a particular selector on an endpoint or the bind call will fail with error WSAEADDRINUSE. When you use the SAP_FIELD_ANY_AESA_SEL type, you should specify an ATM address of all zeros in the ATM_ADDRESS structure. If you use SAP_FIELD_ANY_AESA_REST, you should specify all zeros for the first 19 bytes of the ATM address and the last byte should indicate which selector number you plan to use.

Sockets that are bound to explicit selectors (SAP_FIELD_ANY_AESA_REST) take higher precedence than those sockets that are bound to a wildcarded selector (SAP_FIELD_ANY_AESA_SEL). Those that are bound to explicit selectors (SAP_FIELD_ANY_AESA_REST) or explicit interfaces (ATM_NSAP and ATM_E164) will get first choice at connections. (That is, if a connection comes in on the endpoint and the selector that a socket is explicitly listening on, that socket gets the connection.) Only when no explicitly bound socket is available will a wildcarded selector socket get the connection.

Finally, a Windows utility named ATMADM allows you to retrieve all ATM address and virtual connection information on an endpoint. This utility can be useful when you are developing an ATM application and need to know which interfaces are available on an endpoint. The command line options listed in Table 4-3 are available.

 

Table 4-3 ATMADM Program Options

 

Parameter

Description

-c

Lists all connections (VC). Lists the remote address and the local interface.

-a

Lists all registered addresses (such as all local ATM interfaces and their addresses).

-s

Prints statistics (such as current number of calls, number of signaling and ILMI packets sent/received).

 

The Asynchronous Transfer Mode (ATM) network: The Windows atmadm utility tool

 

Name Resolution

 

Currently, there are no name providers available for ATM under Winsock. Unfortunately, this requires applications to specify the 20-byte ATM address to establish socket communication over an ATM network. Chapter 8 discusses the Windows 2000 and Windows XP domain name space that can be generically used to register ATM addresses with user-friendly service names. Some info on Windows ATM support can be found at NDIS 5.0 and ATM Support in Windows. More info on Windows support for ATM can be found in Windows ATM Services, Asynchronous Transfer Mode and ATM article. The following program example tries to demonstrate the ATM protocol use in Winsock.

 

ATM and Winsock Program Example

 

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

 

ATM and Winsock Program Example: Creating a new empty Win32 console mode application and adding the project/solution name.

 

Add the following source code.

 

// Description:

//    This is a simple Winsock ATM client/server echo program.

//    The server side requires a local interface to bind to.

//    This can be accomplished with the -l:interface option.

//    For the client side, simply specify the sever address

//    to connect to. The server handles client connections in

//    the same thread as the listening socket. This sample

//    is meant to illustrate how to use the ATM address family

//    and is not how an actual client/server should be implemented

//

// Command Line Parameters/Options

//    -a          Print out local ATM address

//    -s          Act as the server

//    -l <if >    Interface to bind to. Either the index of the

//                interface or an NSAP ATM address

//    -r <addr>   Specify the server's NSAP ATM address (another version is ATM E.164 address)

//    -p <port>   The 2 digit selector byte (hexadecimal port number)

//

#include "support.h"

#include <stdio.h>

 

#define MAX_ATM_ADDR_LEN        64

#define MAX_BUFFER              1024

#define NSAP_ADDR_LEN           38

#define SELECTOR_BYTE_LEN       2

 

WSAPROTOCOL_INFO  *lpSocketProtocol=NULL;

 

char szServerAddr[39],        // Server's ATM NSAP address

             szPort[3];               // Port number

BOOL bServer = FALSE;

DWORD dwInterface=-1;         // Which interface to bind to?

 

// Function: usage()

// Description: The usage information

int usage(char *progname)

{

    printf("Usage: %s -a -s -l interface -r server-addr -p port\n", progname);

    printf("       -a          Print a list of ATM interface addresses\n");

    printf("       -s          Act as server\n");

    printf("       -l <if >    Interface to bind to:\n");

    printf("                    Interface number (e.g. 0, 1, etc.)\n");

    printf("                    NSAP ATM address (38 character address)\n");

    printf("       -r <addr>   NSAP ATM address of server\n");

    printf("       -p <port>   Selector byte (2 digit hexadecimal port number)\n");

    printf("Server example: -s -l 2 -p 12\n");

    printf("Sender example: -l 3 -r 4700918100000000613E5BFE010020480811F300 -p 12\n");

    printf("                                     -l 1 -r 11.111122223333444455556666.112233445566.00 -p 12\n");

    return 0;

}

 

// Function: EnumerateATMAddresses()

// Description: Enumerate all ATM interfaces and print their addresses

void EnumerateATMAddresses(WSAPROTOCOL_INFO *lpProtocol)

{

    SOCKET             s;

    SOCKADDR_ATM       atm_addr;

    char               szAddress[MAX_ATM_ADDR_LEN];

    DWORD              dwNumInterfaces, dwAddrLen=MAX_ATM_ADDR_LEN, i;

 

    s = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, lpProtocol, 0, WSA_FLAG_OVERLAPPED);

    if (s == INVALID_SOCKET)

    {

        printf("WSASocket() failed with error code %d\n", WSAGetLastError());

        return;

    }

    else

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

 

    dwNumInterfaces = GetNumATMInterfaces(s);

 

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

            {

                        ZeroMemory((PVOID)&atm_addr, sizeof(SOCKADDR_ATM));

                        ZeroMemory((PVOID)szAddress, MAX_ATM_ADDR_LEN);

 

                        if (GetATMAddress(s, i, &atm_addr.satm_number) == FALSE)

                        {

                                    printf("GetATMAddress() failed!\n");

                                    break;

                        }

 

                        atm_addr.satm_family                 = AF_ATM;

                        atm_addr.satm_number.AddressType     = ATM_NSAP;

                        atm_addr.satm_number.NumofDigits     = ATM_ADDR_SIZE;

                        atm_addr.satm_blli.Layer2Protocol    = SAP_FIELD_ANY;

                        atm_addr.satm_blli.Layer3Protocol    = SAP_FIELD_ABSENT;

                        atm_addr.satm_bhli.HighLayerInfoType = SAP_FIELD_ABSENT;

                        if (WSAAddressToString((LPSOCKADDR)&atm_addr, sizeof(atm_addr),lpProtocol, (LPWSTR)szAddress, &dwAddrLen))

                        {

                                    printf("WSAAddressToString() failed with error code %d\n", WSAGetLastError());

                                    break;

                        }

                        printf("ATM ADDRESS <%d>: '%s'\n", i, szAddress);

            }

            closesocket(s);

            return;

}

 

// Function: ValidateArgs()

// Description:  Parse command line arguments and set global variables accordingly

void ValidateArgs(int argc, char **argv)

{

   int i;

 

   if (argc > 1)

    {

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

       {

           if ( (argv[i][0] == '-') || (argv[i][0] == '/')  )

           {

              switch (tolower(argv[i][1]) )

               {

               case '?':

                   usage(argv[0]);

                   break;                 

               case 'a':   // Get my ATM address

                   EnumerateATMAddresses(lpSocketProtocol);

                   ExitProcess(1);

                   break

               case 's':   // Act as server

                   bServer = TRUE;

                   break

              case 'l':   // Use this local interface

                   if(i+1 < argc)

                   {

                      if(strlen(argv[i+1]) == NSAP_ADDR_LEN)

                          strncpy_s(szServerAddr, sizeof(szServerAddr),argv[i+1],NSAP_ADDR_LEN);

                       else if(strlen(argv[i+1]) == 1)

                           dwInterface = atoi(argv[i+1]);

                      else

                          usage(argv[0]); 

                      ++i;

                  }

                  break;

              case 'r':   // server's address

                   if(i+1 < argc)

                   {

                      if(strlen(argv[i+1]) == NSAP_ADDR_LEN)

                          strncpy_s(szServerAddr, sizeof(szServerAddr),argv[i+1],NSAP_ADDR_LEN);

                      else

                          usage(argv[0]);

                       ++i;

                   }

                  break;

                case 'p':   // server's selector byte (port)

                   if(i+1 < argc)

                   {

                       if(strlen(argv[i+1]) == SELECTOR_BYTE_LEN)

                          strncpy_s(szPort,sizeof(szPort),argv[i+1],SELECTOR_BYTE_LEN);

                       else

                           usage(argv[0]);

                       ++i;

                   }

                  break;

               default:

                   usage(argv[0]);

                  break;

              }

           }

       }

   }

    return;

}

 

// Function: main()

// Description:

//    This function parses arguments and starts either the client or server

//    depending on the arguments. The server will enumerate local ATM

//    interfaces if necessary and bind to a local address and wait for

//    client connections. The server handles the client connection in the

//    same thread as the listening socket. The client only handles one

//    connection and then exits. If running the client, create a socket

//    and connect to the server. Once connected, send a message and read it back

int main(int argc, char **argv)

{

    WSADATA      wsd;

    SOCKET       s;

    DWORD        dwAddrLen = sizeof(SOCKADDR_ATM);

    SOCKADDR_ATM atm_addr;

    int          ret, i;

    char         szAddress[41];

 

   // Initialize Winsock and parse command line arguments

   if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)

   {

               printf("WSAStartup() failed with error code %d\n", WSAGetLastError());

               return -1;

   }

   else

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

 

   // Find the protocol entry supporting ATM and create a socket

   lpSocketProtocol = FindProtocol();

   if (lpSocketProtocol == NULL)

   {

               printf("FindProtocol() returned NULL!\n");

               return -1;

   }

   else

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

 

   s = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,

                  lpSocketProtocol, 0, WSA_FLAG_OVERLAPPED);

    if (s == INVALID_SOCKET)

    {

        printf("WSASocket() failed with error code %d\n", WSAGetLastError());

        return -1;

    }

    else

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

 

            ValidateArgs(argc, argv);

 

            ZeroMemory((PVOID)&atm_addr, sizeof(atm_addr));

            atm_addr.satm_family                 = AF_ATM;

            atm_addr.satm_number.AddressType     = ATM_NSAP;

            atm_addr.satm_number.NumofDigits     = 20;

            atm_addr.satm_blli.Layer2Protocol    = SAP_FIELD_ABSENT;

            atm_addr.satm_blli.Layer3Protocol    = SAP_FIELD_ABSENT;

            atm_addr.satm_bhli.HighLayerInfoType = SAP_FIELD_ABSENT;

            // If an interface number was not supplied (i.e. a 38 character NSAP ATM address was supplied)

            if ((!bServer) || (dwInterface == -1))

            {

                        strncpy_s(&szAddress[0], sizeof(szAddress[0]),szServerAddr, 38);

                        strncpy_s(&szAddress[38], sizeof(szAddress[38]),szPort, 2);

                        szAddress[40] = 0;

                        AtoH((char *) &atm_addr.satm_number.Addr[0], szAddress, 20);

            }

            else

            {

                        // An index was supplied, look it up and get its address

                        if (GetATMAddress(s, dwInterface, &atm_addr.satm_number) == FALSE)

                        {

                                    printf("Unable to get ATM interface!\n");

                        }

                        AtoH((char *) &atm_addr.satm_number.Addr[19], szPort, 1);

            }

           

            if (bServer)

            {

                        SOCKET        sclient;

                        SOCKADDR_ATM  atm_client;

                        int           atmaddrsz = sizeof(SOCKADDR_ATM);

                        DWORD         dwClientAddrLen=MAX_ATM_ADDR_LEN;

                        struct fd_set fdaccept;

                        char          recvbuf[MAX_BUFFER], szClientAddr[MAX_ATM_ADDR_LEN], szAddr[MAX_BUFFER];

                        dwAddrLen = MAX_BUFFER;

 

                        // Print out the address we're binding to

                        if (WSAAddressToString((LPSOCKADDR)&atm_addr, sizeof(atm_addr), lpSocketProtocol, (LPWSTR)szAddr, &dwAddrLen))

                        {

                                    printf("WSAAddressToString() failed with error code %d\n", WSAGetLastError());

                        }

                        else

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

 

                        printf("Binding to: <%s>\n", szAddr);

 

                        if (bind(s, (SOCKADDR *)&atm_addr, sizeof(atm_addr)) == SOCKET_ERROR)

                        {

                                    printf("bind() failed with error code %d\n", WSAGetLastError());

                                    return -1;

                        }

                        else

                                    printf("bind() should be fine!\n");

 

                        if(listen(s, 7) == SOCKET_ERROR)

                                    printf("listen() failed with error code %d\n", WSAGetLastError());

                        else

                                    printf("listen() is OK! I am listening...\n");

 

                        FD_ZERO(&fdaccept);

                        FD_SET(s, &fdaccept);

 

                        if (select(0, &fdaccept, NULL, NULL, NULL) == SOCKET_ERROR)

                                    printf("Something wrong with select() with error code %d\n", WSAGetLastError());

                        else if (select(0, &fdaccept, NULL, NULL, NULL) == 0)

                                    printf("select() - the time limit expired!\n");

                        else

                                    printf("select() should be OK!\n");

 

                        sclient = WSAAccept(s, (SOCKADDR *)&atm_client, &atmaddrsz, NULL, 0);

 

                        if (sclient == INVALID_SOCKET)

                        {

                                    printf("WSAAccept() failed with error code %d\n", WSAGetLastError());

                                    return -1;

                        }

                        else

                                    printf("WSAAccept() should be OK!\n");

 

                        ZeroMemory((PVOID)szClientAddr, MAX_ATM_ADDR_LEN);

                        if (WSAAddressToString((LPSOCKADDR)&atm_client, sizeof(atm_client), lpSocketProtocol, (LPWSTR)szClientAddr, &dwClientAddrLen))

                        {

                                    printf("WSAAddressToString() failed with herror code %d\n", WSAGetLastError());

                        }

                        else

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

 

                        printf("Client's ATM ADDRESS: <%s>\n", szClientAddr);

 

                        // Handle the client connection until it closes

                        while (1)

                        {

                                    ret = recv(sclient, recvbuf, MAX_BUFFER, 0);

                                    if (ret == SOCKET_ERROR)

                                    {

                                                if(WSAEDISCON == WSAGetLastError())

                                                            printf("recv() - a connection closed by peer...\n");

                                                else

                                                            printf("recv() failed with error code %d\n", WSAGetLastError());

                                                return -1;

                                    }

                                    else if (ret == 0)

                                    {

                                                printf("recv() - a graceful close!\n");

                                                break;

                                    }

                                    else

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

 

                                    recvbuf[ret] = '\0';

                                    printf("Read: '%s'\n", recvbuf);

 

                                    ret = send(sclient, recvbuf, ret, 0);

 

                                    if (ret == SOCKET_ERROR)

                                    {

                                                if(WSAEDISCON == WSAGetLastError())

                                                            printf("send() - a connection closed by peer!\n");

                                                else

                                                            printf("send() failed with error code %d\n", WSAGetLastError());

                                                return -1;

                                    }

                                    else

                                                printf("send() should be OK!\n");

 

                                    printf("wrote %d bytes...\n", ret);

                        }

                        closesocket(sclient);

            }

            else

            {

                        char     sendbuf[MAX_BUFFER], szAddr[MAX_BUFFER];

                        dwAddrLen = MAX_BUFFER;

 

                        // Connect and then send and recv data

                        if (WSAAddressToString((LPSOCKADDR)&atm_addr, sizeof(atm_addr), lpSocketProtocol, (LPWSTR)szAddr, &dwAddrLen))

                        {

                                    printf("WSAAddressToString() failed with error code %d\n", WSAGetLastError());

                        }

                        else

                                    printf("WSAAddressToString() is OK\n");

 

                        printf("Connect to: <%s>\n", szAddr);

                        if (connect(s, (SOCKADDR *)&atm_addr, sizeof(atm_addr)) == SOCKET_ERROR)

                        {

                                    printf("connect() failed with error code %d\n", WSAGetLastError());

                                    return -1;

                        }

                        else

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

 

                        memset(sendbuf, '$', 512);

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

                        {

                                    ret = send(s, sendbuf, 64, 0);

                                    if (ret == SOCKET_ERROR)

                                    {

                                                if(WSAEDISCON == WSAGetLastError())

                                                            printf("send() - connection closed by peer!\n");

                                                else

                                                            printf("send() failed with error code %d\n", WSAGetLastError());

                                                return -1;

                                    }

                                    else

                                                printf("send() should be OK!\n");

 

                                    printf("Sent %d bytes\n", ret);

 

                                    ret = recv(s, sendbuf, ret, 0);

                                    if (ret == SOCKET_ERROR)

                                    {

                                                if(WSAEDISCON == WSAGetLastError())

                                                            printf("recv() - connection closed by peer!\n");

                                                else

                                                            printf("recv() failed with error code %d\n", WSAGetLastError());

                                                return -1;

                                    }

                                    else if (ret == 0)

                                    {

                                                printf("recv() - a graceful close\n");

                                                break;

                                    }

                                    else

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

                                    sendbuf[ret] = '\0';

                                    printf("Read: '%s'\n", sendbuf);

                        }

  }

  closesocket(s);

  WSACleanup();

  return 0;

}

 

Next, add a new header file.

 

---------------------------------------------------------------

ATM and Winsock Program Example: Adding a new header file to the project

 

ATM and Winsock Program Example: Adding the support.h header file to the project

 

Then, add the source code.

 

// Description:

//    This file contains function prototypes for functions defined

//    in support.cpp

#include  <winsock2.h>

#include  <Ws2atm.h>

 

int  GetNumATMInterfaces(SOCKET s);

BOOL GetATMAddress(SOCKET s, int device, ATM_ADDRESS *atmaddr);

WSAPROTOCOL_INFO *FindProtocol();

void AtoH( CHAR *szDest, CHAR *szSource, INT iCount );

 

Next, add the definition file for support.h.

 

ATM and Winsock Program Example: Adding the support.cpp, the definition file to the project

 

Then, add the source code.

 

// Description:

//    This file contains various support routines used in the

//    wsockatm.c file. The functions in this file deal with

//    enumerating local ATM interfaces as well as encoding

//    a character string addresses into NSAP style ATM addresses

#include "support.h"

#include <stdio.h>

 

// Function prototype

UCHAR BtoH(CHAR ch);

 

// Function: GetNumATMInterfaces()

// Description: This function enumerates the number of ATM interfaces on the local machine

int  GetNumATMInterfaces(SOCKET s)

{

            DWORD  dwNum, nbytes=sizeof(DWORD);

 

            if (WSAIoctl(s, SIO_GET_NUMBER_OF_ATM_DEVICES, NULL, 0, (LPVOID)&dwNum, sizeof(DWORD),

                    &nbytes, NULL, NULL) == SOCKET_ERROR)

            {

                return -1;

            }

            else

                        printf("WSAIoctl(SIO_GET_NUMBER_OF_ATM_DEVICES) seems working...\n");

   return dwNum;

}

 

 

// Function: GetATMAddress()

// Description:

//    This function returns the ATM_ADDRESS corresponding to

//    the given interface number. The GetNumATMInterfaces function

//    returns the number of interfaces. These number can be

//    passed as the device number into this function (ATM devices begin with number 0)

BOOL GetATMAddress(SOCKET s,int device, ATM_ADDRESS *atmaddr)

{

   DWORD bytes;

 

   if (WSAIoctl(s, SIO_GET_ATM_ADDRESS, (LPVOID)&device, sizeof(DWORD),

       (LPVOID)atmaddr, sizeof(ATM_ADDRESS), &bytes, NULL, NULL) == SOCKET_ERROR)

   {

       return FALSE;

   }

         printf("WSAIoctl(SIO_GET_ATM_ADDRESS) seems working...\n");

 

   return TRUE;

}

 

// Function: FindProtocol()

// Description:

//    This function enumerates protocols installed on the system

//    with WSAEnumProtocols and searches for ATM transports

WSAPROTOCOL_INFO *FindProtocol()

{

   WSAPROTOCOL_INFO *lpProtocolBuf=NULL, *lpRet=NULL;

   DWORD             dwErr, dwRet, dwBufLen=0, i;

 

   if (WSAEnumProtocols(NULL, lpProtocolBuf, &dwBufLen) != SOCKET_ERROR)

   {

               // This should never happen as there is a NULL buffer

               printf("WSAEnumProtocols() failed with error code %d\n", WSAGetLastError());

               return FALSE;

   }

   else if ((dwErr = WSAGetLastError()) != WSAENOBUFS)

   {

               // We failed for some reason not relating to buffer size - also odd

               printf("WSAEnumProtocols() failed with error code %d\n", dwErr);

               return FALSE;

   }

   else

               printf("WSAEnumProtocols() should be fine!\n");

 

   // Allocate the correct buffer size for WSAEnumProtocols as

   // well as the buffer to return

   lpProtocolBuf = (WSAPROTOCOL_INFO *)GlobalAlloc(GMEM_FIXED, dwBufLen);

 

   if (lpProtocolBuf == NULL)

   {

               printf("GlobalAlloc() failed with error code %d\n", GetLastError());

               return FALSE;

   }

   else

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

 

   dwRet = WSAEnumProtocols(NULL, lpProtocolBuf, &dwBufLen);

   if (dwRet == SOCKET_ERROR)

   {

               printf("WSAEnumProtocols() failed with error code %d\n", WSAGetLastError());

               GlobalFree(lpProtocolBuf);

               return FALSE;

   }

   else

               printf("WSAEnumProtocols() should be fine!\n");

 

   // Loop through the returned protocol information looking for those

   // that are in the AF_ATM address family

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

   {

               if ( (lpProtocolBuf[i].iAddressFamily == AF_ATM) && (lpProtocolBuf[i].iSocketType == SOCK_RAW) &&

                           (lpProtocolBuf[i].iProtocol == ATMPROTO_AAL5))

              {

                          lpRet = GlobalAlloc(GMEM_FIXED, sizeof(WSAPROTOCOL_INFO));

                          memcpy(lpRet, &lpProtocolBuf[i], sizeof(WSAPROTOCOL_INFO));

                          break;

               }

   }

 

   GlobalFree(lpProtocolBuf);

   return lpRet;

}

 

// Function: AtoH()

// Description:

//    This function coverts the ATM address specified in the string

//    (ascii) format to the binary(hexadecimal) format

void AtoH(CHAR *szDest, CHAR *szSource, INT iCount)

{

            while (iCount--)

            {

               *szDest++ = ( BtoH ( *szSource++ ) << 4 ) + BtoH ( *szSource++ );

            }

            return;

}

 

// Function: BtoH

// Description:

//    This function returns the equivalent binary value for

//    an individual character specified in the ascii format

UCHAR BtoH(CHAR ch)

{

    if (ch >= '0' && ch <= '9')

    {

                        return (ch - '0');

    }

 

  if (ch >= 'A' && ch <= 'F')

  {

              return ( ch - 'A' + 0xA );

  }

 

  if (ch >= 'a' && ch <= 'f')

  {

              return ( ch - 'a' + 0xA );

  }

 

  // Illegal values in the address will not be excepted

  return -1;

}

 

Build and run the program.

 

ATM and Winsock Program Example: A sample output

 

In order to test the server and sender program, you need to have an ATM adapter card (NIC) installed on you machine. Unfortunately, we don’t have it!

 

 

 


< Another AppleTalk Example | Winsock2 Supported Protocols Main | Bluetooth >