< Reliable Multicasting | Multicasting Main | Winsock & Quality of Service >


 

 

Multicasting 9 Part 6

 

 

What do we have in this chapter 9 part 6?

  1. ATM Multipoint

  2. ATM Multipoint with WSAJoinLeaf()

  3. ATM Leaf Node

  4. ATM Root Node

  5. Useful References

 

ATM Multipoint

 

Native ATM through Winsock also supports multicasting, which offers significantly different capabilities than IP multicasting. Remember that ATM supports rooted control and data planes, so when a multicast server, or c_root, is established, it has control over who is allowed to join the group as well as how data is transmitted within the group.

One important distinction is that on an ATM network, IP over ATM can be enabled. This configuration allows the ATM network to emulate an IP network by mapping IP addresses to ATM native addresses. With IP over ATM enabled, you have a choice of using IP multicasting, which will be translated appropriately to the ATM layer, or of using the native ATM multicasting capabilities, which we present in this section. The behavior of IP multicasting on ATM when configured for IP over ATM should be the same because it appears that you are on an IP network. The only exception is that IGMP is not present because all multicast calls are translated into ATM native commands. In addition, it is possible to configure an ATM network with one or more LAN emulation (LANE) networks. The purpose of a LANE is to make the ATM appear as a “regular” network capable of multiple protocols such as IPX/SPX, NetBEUI, TCP/IP, IGMP, and ICMP. In this situation, IP multicasting does look every bit like IP multicasting on an Ethernet network, which means IGMP is present as well.

We mentioned that ATM supports rooted control planes and rooted data planes. Therefore, when you create a multicast group, you establish a root node that “invites” leaf nodes to join the multicast group. Currently, only root-initiated joins are supported, meaning that a leaf cannot request to be added to a group. In addition, the root node (as a rooted data plane) sends data in one direction only, from the root to the leaves.

One startling contrast between ATM and IP multicasting is that ATM needs no special addresses. All that is required is that the root has knowledge of the addresses of each leaf that it will invite. Also, only one root node can be in a multicast group. If another ATM endpoint starts inviting the same leaves, this association becomes a separate group.

 

ATM Multipoint with WSAJoinLeaf()

 

The WSAJoinLeaf() API is the only method of using ATM multicasting. In addition, the semantics of setting up an ATM multipoint session are client-server oriented but conceptually reversed. The server creates a socket and then initiates a multipoint join with WSAJoinLeaf() to each client it wishes to invite into the multicast group. Each client creates a socket, listens, and waits on an accept call. If the server invites the client, the accept call completes.

The next two sections describe the exact steps required for setting up an ATM leaf (client) node followed by the root (server) node however we begin with the an ATM multicast sample first.

 

ATM Multipoint with WSAJoinLeaf(): Creating a new empty Win32 console mode application project

 

Add the following source code.

 

// Description:

//    This sample illustrates multicasting on an ATM network.

//    ATM multicasting features rooted control and data planes.

//    This means our multicast server explicitly invites each

//    leaf not via a WSAJoinLeaf call. The leaf nodes simply

//    wait for on an accept for the invitation.

//

//    For the root node we specify the -s options along with

//    one or more -l:Address options.  The address is the ATM

//    address of the leaf to invite. All ATM addresses are only

//    the first 38 chars. The port (selector) which is the other

//    2 characters of the address are given in the -p:xx option.

//

//    For the client simply call the app with no parameters (the

//    -i:Addr can be used for both client and server).

//

// Command Line Options/Parameters:

//     atmmulticastexample -s -l ATM-Addr -i ATM-Addr -p XX -n int

//           -s       Act as root\n");

//           -l str   Leaf address to invite (38 chars)

//                     May be specified multiple times.

//           -i str   Local interface to bind to (38 chars)

//           -p xx    Port number (2 hex chars)

//           -n int   Number of packets to send

//

// Link to ws2_32.lib

// Already included in support.h

// #include <winsock2.h>

#include "support.h"

#include <stdio.h>

#include <stdlib.h>

 

#define BUFSIZE               1024

#define MAX_ATM_LEAF             4

#define ATM_PORT_OFFSET       ((ATM_ADDR_SIZE*2)-2)

#define MAX_ATM_STR_LEN       (ATM_ADDR_SIZE*2)

 

DWORD  dwAddrCount=0, dwDataCount=20;

BOOL   bServer=FALSE, bLocalAddress=FALSE;

char   szLeafAddresses[MAX_ATM_LEAF][MAX_ATM_STR_LEN+1], szLocalAddress[MAX_ATM_STR_LEN+1], szPort[3];

SOCKET sLeafSock[MAX_ATM_LEAF];

 

// Module: usage

// Description: Print usage information.

int usage(char *progname)

{

    printf("Usage: %s [-s]\n", progname);

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

    printf("     -l str   Leaf address to invite (38 chars)\n");

    printf("               May be specified multiple times\n");

    printf("     -i str   Local interface to bind to (38 chars)\n");

    printf("     -p xx    Port number (2 hex chars)\n");

    printf("     -n int   Number of packets to send\n");

    return 0;

}

 

// Module: ValidateArgs

// Description: Parse command line arguments.

void ValidateArgs(int argc, char **argv)

{

    int      i;

 

    memset(szLeafAddresses, 0, MAX_ATM_LEAF * (MAX_ATM_STR_LEN+1));

    memset(szPort, 0, sizeof(szPort));

 

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

    {

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

        {

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

            {

                case 's':     // server

                    bServer = TRUE;

                    break;

                case 'l':     // leaf address

                    if (i+1 >=argc)

                        usage(argv[0]);

                    strncpy_s(szLeafAddresses[dwAddrCount++], sizeof(szLeafAddresses), argv[++i], MAX_ATM_STR_LEN-2);

                    break;

                case 'i':     // local interface

                    if (i+1 >= argc)

                        usage(argv[0]);

                    strncpy_s(szLocalAddress, sizeof(szLocalAddress), argv[++i], MAX_ATM_STR_LEN-2);

                    bLocalAddress = TRUE;

                    break;

                case 'p':     // port address to use

                    if (i+1 >= argc)

                        usage(argv[0]);

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

                    break;

                case 'n':     // number of packets to send

                    if (i+1 >= argc)

                        usage(argv[0]);

                    dwDataCount = atoi(argv[++i]);

                    break;

                default:

                    usage(argv[0]);

                    break;

            }

        }

    }

    return;

}

 

// Function: Server

// Description:

//    Bind to the local interface and then invite each leaf

//    address which was specified on the command line.

//    Once each connection is made, send some data.

void Server(SOCKET s, WSAPROTOCOL_INFO *lpSocketProtocol)

{

    // Server routine

    SOCKADDR_ATM  atmleaf, atmroot;

    WSABUF        wsasend;

    char          sendbuf[BUFSIZE], szAddr[BUFSIZE];

    DWORD         dwBytesSent, dwAddrLen=BUFSIZE, dwNumInterfaces, i;

    int           ret;

 

    // If no specified local interface is given pick the first one

    memset(&atmroot, 0, sizeof(SOCKADDR_ATM));

    if (!bLocalAddress)

    {

        dwNumInterfaces = GetNumATMInterfaces(s);

        GetATMAddress(s, 0, &atmroot.satm_number);

    }

    else

        AtoH((char *)&atmroot.satm_number.Addr[0], szLocalAddress, ATM_ADDR_SIZE-1);

 

    // Set the port number in the address structure

    AtoH((char *)&atmroot.satm_number.Addr[ATM_ADDR_SIZE-1], szPort, 1);

 

    // Fill in the rest of the SOCKADDR_ATM structure

    atmroot.satm_family                 = AF_ATM;

    atmroot.satm_number.AddressType     = ATM_NSAP;

    atmroot.satm_number.NumofDigits     = ATM_ADDR_SIZE;

    atmroot.satm_blli.Layer2Protocol    = SAP_FIELD_ANY;

    atmroot.satm_blli.Layer3Protocol    = SAP_FIELD_ABSENT;

    atmroot.satm_bhli.HighLayerInfoType = SAP_FIELD_ABSENT;

 

    // Print out what we're binding to and bind()

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

    {

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

    }

    else

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

 

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

 

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

    {

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

        return;

    }

    else

        printf("bind() is oK!\n");

 

    // Invite each leaf

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

    {

        // Fill in the SOCKADR_ATM structure for each leaf

        memset(&atmleaf, 0, sizeof(SOCKADDR_ATM));

        AtoH((char *)&atmleaf.satm_number.Addr[0], szLeafAddresses[i], ATM_ADDR_SIZE-1);

        AtoH((char *)&atmleaf.satm_number.Addr[ATM_ADDR_SIZE-1], szPort, 1);

 

        atmleaf.satm_family                 = AF_ATM;

        atmleaf.satm_number.AddressType     = ATM_NSAP;

        atmleaf.satm_number.NumofDigits     = ATM_ADDR_SIZE;

        atmleaf.satm_blli.Layer2Protocol    = SAP_FIELD_ANY;

        atmleaf.satm_blli.Layer3Protocol    = SAP_FIELD_ABSENT;

        atmleaf.satm_bhli.HighLayerInfoType = SAP_FIELD_ABSENT;

 

        // Print out clients address and the invite it

        if (WSAAddressToString((LPSOCKADDR)&atmleaf,sizeof(atmleaf), lpSocketProtocol, (LPWSTR)szAddr,

            &dwAddrLen))

        {

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

        }

        else

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

 

        printf("[%02d] Inviting: <%s>\n", i, szAddr);

 

        if ((sLeafSock[i] = WSAJoinLeaf(s, (SOCKADDR *)&atmleaf, sizeof(SOCKADDR_ATM), NULL,

            NULL, NULL, NULL, JL_SENDER_ONLY)) == INVALID_SOCKET)

        {

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

            WSACleanup();

            return;

        }

        else

            printf("WSAJoinLeaf() is working!\n");

    }

 

    // Note that the ATM protocol is a bit different that TCP.

    // When the WSAJoinLeaf (or connect call) completes the

    // peer has not necessarily accepted the connection yet

    // so immediately sending data will result in an error which is why we wait a short bit.

    printf("Press a key to start sending.");

    getchar();

    printf("\n");

 

    // Now send some data to the group address which will

    // be replicated to all clients

    wsasend.buf = sendbuf;

    wsasend.len = 128;

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

    {

        memset(sendbuf, '$' + (i%26), 128);

        ret = WSASend(s, &wsasend, 1, &dwBytesSent, 0, NULL, NULL);

        if (ret == SOCKET_ERROR)

        {

            printf("WSASend() failed: %d\n", WSAGetLastError());

            break;

        }

        printf("[%02d] Wrote: %d bytes\n", i, dwBytesSent);

        Sleep(500);

    }

 

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

        closesocket(sLeafSock[i]);

    return;

}

 

 

 

 

// Function: Client

// Description:

//    The client binds to the local interface (either one specified

//    on the command line or the first local ATM address). It

//    then waits on an accept call for the root invitation.  It then waits to receive data.

void Client(SOCKET s, WSAPROTOCOL_INFO *lpSocketProtocol)

{

    SOCKET       sl;

    SOCKADDR_ATM atm_leaf, atm_root;

    DWORD        dwNumInterfaces, dwBytesRead, dwAddrLen=BUFSIZE, dwFlags, i;

    WSABUF       wsarecv;

    char         recvbuf[BUFSIZE], szAddr[BUFSIZE];

    int          iLen = sizeof(SOCKADDR_ATM),ret;

 

    // Setup the local interface

    memset(&atm_leaf, 0, sizeof(SOCKADDR_ATM));

    if (!bLocalAddress)

    {

        dwNumInterfaces = GetNumATMInterfaces(s);

        GetATMAddress(s, 0, &atm_leaf.satm_number);

    }

    else

        AtoH((char *)&atm_leaf.satm_number.Addr[0], szLocalAddress,ATM_ADDR_SIZE-1);

 

    AtoH((char *)&atm_leaf.satm_number.Addr[ATM_ADDR_SIZE-1],szPort, 1);

 

    // Fill in the SOCKADDR_ATM structure

    atm_leaf.satm_family                 = AF_ATM;

    atm_leaf.satm_number.AddressType     = ATM_NSAP;

    atm_leaf.satm_number.NumofDigits     = ATM_ADDR_SIZE;

    atm_leaf.satm_blli.Layer2Protocol    = SAP_FIELD_ANY;

    atm_leaf.satm_blli.Layer3Protocol    = SAP_FIELD_ABSENT;

    atm_leaf.satm_bhli.HighLayerInfoType = SAP_FIELD_ABSENT;

 

    // Print the address we're binding to and bind

    if (WSAAddressToString((LPSOCKADDR)&atm_leaf, sizeof(atm_leaf), 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_leaf, sizeof(SOCKADDR_ATM)) == SOCKET_ERROR)

    {

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

        return;

    }

    else

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

 

    if(listen(s, 1) == 0)

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

    else

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

 

    // Wait for the invitation

    memset(&atm_root, 0, sizeof(SOCKADDR_ATM));

    if ((sl = WSAAccept(s, (SOCKADDR *)&atm_root, &iLen, NULL, 0)) == INVALID_SOCKET)

    {

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

        return;

    }

    else

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

    printf("Received a connection!\n");

    // Receive some data

    wsarecv.buf = recvbuf;

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

    {

        dwFlags = 0;

        wsarecv.len = BUFSIZE;

        ret = WSARecv(sl, &wsarecv, 1, &dwBytesRead, &dwFlags,

            NULL, NULL);

        if (ret == SOCKET_ERROR)

        {

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

            break;

        }

        if (dwBytesRead == 0)

            break;

        recvbuf[dwBytesRead] = 0;

        printf("[%02d] Read %d bytes: '%s'\n", i, dwBytesRead, recvbuf);

    }

    if(closesocket(sl) == 0)

        printf("closesocket(sl) is OK!\n");

    else

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

    return;

}

 

// Function: main

// Description:

//    This function loads Winsock library, parses command line

//    arguments, creates the appropriate socket (with the right

//    root or leaf flags), and start the client or server

//    functions depending on the specified flags.

int main(int argc, char **argv)

{

    WSADATA             wsd;

    SOCKET              s;

    WSAPROTOCOL_INFO    lpSocketProtocol;

    DWORD               dwFlags;

 

    if(argc < 2)

    {

       usage(argv[0]);

       exit(1);

    }

 

    ValidateArgs(argc, argv);

 

    // Load the Winsock library

    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 an ATM capable protocol

    if (FindProtocol(&lpSocketProtocol) == FALSE)

    {

        printf("Unable to find ATM protocol entry!\n");

        return -1;

    }

    else

         printf("ATM protocol entry found!\n");

 

    // Create the socket using the appropriate root or leaf flags

    if (bServer)

        dwFlags = WSA_FLAG_OVERLAPPED | WSA_FLAG_MULTIPOINT_C_ROOT | WSA_FLAG_MULTIPOINT_D_ROOT;

    else

        dwFlags = WSA_FLAG_OVERLAPPED | WSA_FLAG_MULTIPOINT_C_LEAF | WSA_FLAG_MULTIPOINT_D_LEAF;

 

    if ((s = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,

            FROM_PROTOCOL_INFO, &lpSocketProtocol, 0, dwFlags)) == INVALID_SOCKET)

    {

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

        WSACleanup();

        return -1;

    }

    else

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

 

    // Start the correct driver depending on what flags were supplied on the command line.

    if (bServer)

    {

        Server(s, &lpSocketProtocol);

    }

    else

    {

        Client(s, &lpSocketProtocol);

    }

 

    if(closesocket(s) == 0)

        printf("closesocket(s) is OK!\n");

    else

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

 

    if(WSACleanup() == 0)

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

    else

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

    return 0;

}

 

Add the support.h header file.

 

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

ATM Multipoint with WSAJoinLeaf(): Adding the support.h header file

 

Add the source code.

 

// Module: support.h

//

// Description:

//    This file contains function prototypes for the support routines found in support.cpp.

#include <winsock2.h>

#include <ws2atm.h>

 

int  GetNumATMInterfaces(SOCKET s);

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

BOOL FindProtocol(WSAPROTOCOL_INFO *lpProto);

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

 

Add the definition file, support.cpp for support.h header file.

 

ATM Multipoint with WSAJoinLeaf(): Adding the support.cpp definition file

 

Add the source code.

 

// Module: support.cpp

//

// Description:

//    This file contains support routines necessary for the

//    mcastatm.c sample. These function return the number of

//    ATM interfaces as well as their corresponding ATM

//    addresses.

//

//    The BtoH and AtoH functions are provided which manually

//    perform the string conversion to an ATM address. These

//    are provided since some older platforms do not support

//    the ATM address family in WSAStringToAddress and WSAAddressToString.

#include "support.h"

#include <stdio.h>

 

UCHAR BtoH( CHAR ch );

 

// Function: GetNumATMInterfaces

// Description: This function returns 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;

    }

    return dwNum;

}

 

// Function: GetATMAddress

// Description:

//    This function returns the ATM address for a given interface.

//    Use the previous function to return how many interfaces there

//    are and then call this function with the device parameter

//    from 0 to the number of interfaces - 1.

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;

    }

    return TRUE;

}

 

// Function: FindProtocol

// Description: This function enumerates all installed protocol providers and returns the first ATM provider.

BOOL FindProtocol(WSAPROTOCOL_INFO *lpProto)

{

    WSAPROTOCOL_INFO *lpProtocolBuf=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;

    }

 

    // 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() for protocol buffer failed with error code %d\n", GetLastError());

        return FALSE;

    }

 

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

    if (dwRet == SOCKET_ERROR)

    {

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

        GlobalFree(lpProtocolBuf);

        return FALSE;

    }

 

    // Loop through the returned protocol information looking for those

    // that are in the AF_NETBIOS address family.

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

    {

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

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

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

        {

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

            GlobalFree(lpProtocolBuf);

            return TRUE;

        }

    }

    GlobalFree(lpProtocolBuf);

    return FALSE;

}

 

// 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 project.

 

ATM Multipoint with WSAJoinLeaf(): Running the program example without any argument

 

Unfortunately we don’t have ATM adapter to test this program.

 

ATM Multipoint with WSAJoinLeaf(): Running the program example with some argument

 

ATM Leaf Node

 

Creating a leaf node in a multicast group is straightforward. On an ATM network, the leaf must listen for an invitation from a root to join a group. Here are the four steps needed to do this:

  1. Using the WSASocket() function, create a socket of address family AF_ATM including the flags WSA_FLAG_MULTIPOINT_C_LEAF and WSA_FLAG_MULTIPOINT_D_LEAF.

  2. Bind the socket to the local ATM address and port with the bind() function.

  3. Call listen().

  4. Wait for an invitation by using accept(), WSAAccept(), or AcceptEx(). Depending on the I/O model you use, this will differ.

Once the connection is established, the leaf node can receive data sent from the root. Remember that with ATM multicasting, the data flow is one way: from the root to the leaves. Windows 98, Windows Me, Windows 2000, and Windows XP currently support only a single ATM leaf node on the system at any given time. Only a single process on the entire system can be a leaf member of any ATM point-to-multipoint session.

 

ATM Root Node

 

Creating a root node is even easier than creating an ATM leaf. The process includes two basic steps:

  1. Using the WSASocket() function, create a socket of address family AF_ATM including the flags WSA_FLAG_MULTIPOINT_C_ROOT and WSA_FLAG_MULTIPOINT_D_ROOT.

  2. Call WSAJoinLeaf() with the ATM address for each endpoint you want to invite.

A root node can invite as many endpoints as it wants, but it must issue a separate WSAJoinLeaf() call for each.

 

 

 

Useful References:

 

1.      IPv4 Multicasting Tools and Settings.

2.      Windows Server 2003 Resource Kit Tools.

3.      TCP/IP and NBT configuration parameters for Windows XP.

 


< Reliable Multicasting | Multicasting Main | Winsock & Quality of Service >