< QOS Templates | QOS Programming Main | TCP, UDP, ATM & QOS Examples >


 

 

Generic Quality of Service (QOS) 10 Part 5

 

 

What do we have in this chapter 10 part 5?

  1. Program Examples

  2. TCP

 

Program Examples

 

In this section, we'll take a look at two programming examples of using QOS over TCP and UDP. The first example, which uses TCP, will demonstrate how to set up a FLOWSPEC and manage RSVP signaling on the Windows 98, Windows Me, and Windows 2000 platforms.

The second example describes UDP and is primarily designed for Windows XP, which demonstrates only how to set up a FLOWSPEC to invoke the IP packet scheduler.

The examples rely on a couple of support routines, PrintQos() and FindProtocolInfo(), which are defined in the files PRINTQOS.CPP and PROVIDER.CPP, respectively. The former routine simply prints out the contents of a QOS structure, while the latter finds a protocol from the provider catalog with the required attributes, such as QOS.

 

TCP

 

The following program example illustrates the TCP over QOS. Create a new empty Win32 console mode application and add the project/solution name.

 

Generic Quality of Service (QOS): Creating a new empty Win32 console mode application project for TCP QOS program

 

Add the following source code.

 

// Description:

//    This sample illustrates unicast TCP connections. This sample

//    may act as either a client or server. For both, QOS may be

//    set before connection or acceptance, during connection or

//    acceptance, after connection or acceptance, or once an

//    FD_QOS event has been received. The server may handle up to

//    MAX_CONN number of client connections.

//

// Command line options

//

//    tcpqosexample -q [b,d,a,e] -s -c <Server IP> -w -r

//       -q [b,d,a,e]        When to request QOS

//           b               Set QOS before bind or connect

//           d               Set QOS during accept cond func

//           a               Set QOS after session setup

//           e               Set QOS only upon receipt of FD_QOS

//       -s                  Act as server

//       -c <Server-IP>      Act as client

//       -w                  Wait to send until RESV has arrived

//       -r                  Confirm reservation request

//

// Link to ws2_32.lib

#include <winsock2.h>

#include <windows.h>

#include <qos.h>

#include <qossp.h>

#include "provider.h"

#include "printqos.h"

#include <stdio.h>

 

#define QOS_BUFFER_SZ       16000 // Default buffer size for SIO_GET_QOS

#define DATA_BUFFER_SZ       2048 // Send/Recv buffer size

#define SET_QOS_NONE          0   // No QOS

#define SET_QOS_BEFORE        1   // Set QOS on listening socket

#define SET_QOS_DURING        2   // Set QOS in conditional accept

#define SET_QOS_AFTER         3   // Set QOS after accept

#define SET_QOS_EVENT         4   // Wait for FD_QOS and then set

#define MAX_CONN              10

 

int  iSetQos,                  // When to set QOS?

     nConns;

BOOL bServer,            // Client or server?

     bWaitToSend,         // Wait to send data until RESV

     bConfirmResv;

char szServerAddr[64]; // Server's address

QOS  clientQos,            // QOS client structure

     serverQos;                // QOS server structure

RSVP_RESERVE_INFO  qosreserve;

 

// Setup some common FLOWSPECS

const FLOWSPEC flowspec_notraffic = {QOS_NOT_SPECIFIED,

                                     QOS_NOT_SPECIFIED,

                                     QOS_NOT_SPECIFIED,

                                     QOS_NOT_SPECIFIED,

                                     QOS_NOT_SPECIFIED,

                                     SERVICETYPE_NOTRAFFIC,

                                     QOS_NOT_SPECIFIED,

                                     QOS_NOT_SPECIFIED};

 

const FLOWSPEC flowspec_g711 = {8500,

                                680,

                                17000,

                                QOS_NOT_SPECIFIED,

                                QOS_NOT_SPECIFIED,

                                SERVICETYPE_CONTROLLEDLOAD,

                                340,

                                340};

 

const FLOWSPEC flowspec_guaranteed = {17000,

                                      1260,

                                      34000,

                                      QOS_NOT_SPECIFIED,

                                      QOS_NOT_SPECIFIED,

                                      SERVICETYPE_GUARANTEED,

                                      340,

                                      340};

 

// Function: SetReserveInfo

// Description:

//    For receivers, if a confirmation is requested this must be done with an RSVP_RESERVE_INFO structure

void SetQosReserveInfo(QOS *lpqos)

{

    qosreserve.ObjectHdr.ObjectType = RSVP_OBJECT_RESERVE_INFO;

    qosreserve.ObjectHdr.ObjectLength = sizeof(RSVP_RESERVE_INFO);

    qosreserve.Style = RSVP_DEFAULT_STYLE;

    qosreserve.ConfirmRequest = bConfirmResv;

    qosreserve.PolicyElementList = NULL;

    qosreserve.FlowDescList = NULL;

 

    lpqos->ProviderSpecific.buf = (char *)&qosreserve;

    lpqos->ProviderSpecific.len = sizeof(qosreserve);

 

    return;

}

 

// Function: InitQos

// Description:

//    Setup the client and server QOS structures. This is

//    broken out into a separate function so you can change

//    the requested QOS parameters to see how that affects the application.

void InitQos()

{

    clientQos.SendingFlowspec = flowspec_g711;

    clientQos.ReceivingFlowspec =  flowspec_notraffic;

    clientQos.ProviderSpecific.buf = NULL;

    clientQos.ProviderSpecific.len = 0;

 

    serverQos.SendingFlowspec = flowspec_notraffic;

    serverQos.ReceivingFlowspec = flowspec_g711;

    serverQos.ProviderSpecific.buf = NULL;

    serverQos.ProviderSpecific.len = 0;

 

    if (bConfirmResv)

        SetQosReserveInfo(&serverQos);

}

 

// Function: usage

// Description: Print out usage information.

int usage(char *progname)

{

    printf("Usage: %s -q [b,d,a,e] -s|-c <Server IP> -w -r\n", progname);

    printf("\n");

    printf("      -q [b,d,a,e] When to request QOS\n");

    printf("          b        Set QOS before bind or connect\n");

    printf("          d        Set QOS during accept cond func\n");

    printf("          a        Set QOS after session setup\n");

    printf("          e        Set QOS only upon receipt of FD_QOS\n");

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

    printf("      -c <Server IP> Act as client\n");

    printf("      -w           Wait to send until RESV has arrived\n");

    printf("      -r           Confirm reservation request\n");

    return 0;

}

 

// Function: ValidateArgs

// Description:

//    Parse command line arguments and set global variables to indicate how the application should act

void ValidateArgs(int argc, char **argv)

{

    int      i;

 

    // Initialize globals to a default value

    iSetQos = SET_QOS_NONE;

    bServer = TRUE;

    bWaitToSend = FALSE;

    bConfirmResv = FALSE;

 

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

    {

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

        {

                                    // printf(" i = %d\n", i);

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

            {

                case 'q':        // When to set QOS

                    if (tolower(argv[i][3]) == 'b')

                        iSetQos = SET_QOS_BEFORE;

                    else if (tolower(argv[i][3]) == 'd')

                        iSetQos = SET_QOS_DURING;

                    else if (tolower(argv[i][3]) == 'a')

                        iSetQos = SET_QOS_AFTER;

                    else if (tolower(argv[i][3]) == 'e')

                        iSetQos = SET_QOS_EVENT;

                    else

                        usage(argv[0]);

                    break;

                case 's':        // Server

                    printf("Server flag set!\n");

                    bServer = TRUE;

                    break;

                case 'c':        // Client

                    printf("Client flag set!\n");

                    bServer = FALSE;

                    //

                    printf("strlen(argv[%d]) = %d\n", i, strlen(argv[i]));

                    if (strlen(argv[i]) >= 2)

                    {

                           strcpy_s(szServerAddr, sizeof(szServerAddr), &argv[i][3]);

                           // Verify!

                           printf("\nThe server address is : %s\n", szServerAddr);

                    }

                    else

                    {

                        printf("strlen(argv[i]) < 3, i = %d\n", i);

                        usage(argv[0]);

                     }

                    break;

                case 'w':       // Wait to send data until RESV has arrived

                    bWaitToSend = TRUE;

                    break;

                case 'r':

                    bConfirmResv = TRUE;

                    break;

                default:

                    usage(argv[0]);

                    break;

            }

        }

    }

    return;

}

 

// Function: AbleToSend

// Description:

//    Checks to send whether data can be sent on the socket before

//    any RESV message have arrived. This checks to see if the

//    best effort level currently available on the network is

//    sufficient for the QOS levels that were set on the socket.

BOOL AbleToSend(SOCKET s)

{

    int     ret;

    DWORD   dwCode = ALLOWED_TO_SEND_DATA, dwValue, dwBytes;

 

    ret = WSAIoctl(s, SIO_CHK_QOS, &dwCode, sizeof(dwCode), &dwValue, sizeof(dwValue), &dwBytes, NULL, NULL);

    if (ret == SOCKET_ERROR)

    {

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

        return FALSE;

    }

    else

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

 

    return (BOOL)dwValue;

}

 

// Function: ChkForQosStatus

// Description:

//    Check for the presence of a RSVP_STATUS_INFO object and

//    determine if the supplied flags are present in that object

DWORD ChkForQosStatus(QOS *lpqos, DWORD dwFlags)

{

    QOS_OBJECT_HDR   *objhdr = NULL;

    RSVP_STATUS_INFO *status = NULL;

    char             *bufptr = NULL;

    BOOL              bDone = FALSE;

    DWORD             objcount = 0;

 

    if (lpqos->ProviderSpecific.len == 0)

        return 0;

 

    bufptr = lpqos->ProviderSpecific.buf;

    objhdr = (QOS_OBJECT_HDR *)bufptr;

 

    while (!bDone)

    {

        if (objhdr->ObjectType == RSVP_OBJECT_STATUS_INFO)

        {

            status = (RSVP_STATUS_INFO *)objhdr;

            if (status->StatusCode & dwFlags)

                return 1;

        }

        else if (objhdr->ObjectType == QOS_OBJECT_END_OF_LIST)

            bDone = TRUE;

 

        bufptr += objhdr->ObjectLength;

        objcount += objhdr->ObjectLength;

        objhdr = (QOS_OBJECT_HDR *)bufptr;

 

        if (objcount >= lpqos->ProviderSpecific.len)

            bDone = TRUE;

    }

    return 0;

}

 

// Function: HandleClientEvents

// Description:

//    This function is called by the Server function to handle

//    events which occurred on client SOCKET handles. The socket

//    array is passed in along with the event array and the index

//    of the client who received the signal. Within the function

//    the event is decoded and the appropriate action occurs.

void HandleClientEvents(SOCKET socks[], HANDLE events[], int index)

{

    WSANETWORKEVENTS  ne;

    char              databuf[4096];

    WSABUF            wbuf;

    DWORD             dwBytesRecv, dwFlags;

    int               ret, i;

 

    // Enumerate the network events that occurred

    ret = WSAEnumNetworkEvents(socks[index], events[index], &ne);

    if (ret == SOCKET_ERROR)

    {

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

        return;

    }

    else

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

 

    // Data to be read

    if ((ne.lNetworkEvents & FD_READ) == FD_READ)

    {

        wbuf.buf = databuf;

        wbuf.len = 4096;

 

        if (ne.iErrorCode[FD_READ_BIT])

            printf("FD_READ error: %d\n", ne.iErrorCode[FD_READ_BIT]);

        else

            printf("FD_READ...\n");

 

        dwFlags = 0;

        ret = WSARecv(socks[index], &wbuf, 1, &dwBytesRecv, &dwFlags, NULL, NULL);

        if (ret == SOCKET_ERROR)

        {

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

            return;

        }

        else

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

 

        wbuf.len = dwBytesRecv;

        printf("Read: %d bytes\n", dwBytesRecv);

    }

 

    // Able to write data, nothing to do here

    if ((ne.lNetworkEvents & FD_WRITE) == FD_WRITE)

    {

        if (ne.iErrorCode[FD_WRITE_BIT])

            printf("FD_WRITE error: %d\n", ne.iErrorCode[FD_WRITE_BIT]);

        else

            printf("FD_WRITE...\n");

    }

 

    // The client closed the connection. Close the socket on our end and clean up the data structures.

    if ((ne.lNetworkEvents & FD_CLOSE) == FD_CLOSE)

    {

        if (ne.iErrorCode[FD_CLOSE_BIT])

            printf("FD_CLOSE error: %d\n", ne.iErrorCode[FD_CLOSE_BIT]);

        else

            printf("FD_CLOSE...\n");

 

        closesocket(socks[index]);

        WSACloseEvent(events[index]);

        socks[index] = INVALID_SOCKET;

 

        // Remote the client socket entry from the array and compact the remaining clients to the beginning of the array

        for(i = index; i < MAX_CONN - 1; i++)

            socks[i] = socks[i + 1];

        nConns--;

    }

 

    // Received an FD_QOS event. This could mean several things.

    if ((ne.lNetworkEvents & FD_QOS) == FD_QOS)

    {

        char        buf[QOS_BUFFER_SZ];

        QOS        *lpqos = NULL;

        DWORD       dwBytes;

 

        if (ne.iErrorCode[FD_QOS_BIT])

            printf("FD_QOS error: %d\n", ne.iErrorCode[FD_QOS_BIT]);

        else

            printf("FD_QOS...\n");

 

        lpqos = (QOS *)buf;

        lpqos->ProviderSpecific.buf = &buf[sizeof(QOS)];

        lpqos->ProviderSpecific.len = sizeof(buf) - sizeof(QOS);

 

        ret = WSAIoctl(socks[index], SIO_GET_QOS, NULL, 0, buf, QOS_BUFFER_SZ, &dwBytes, NULL, NULL);

        if (ret == SOCKET_ERROR)

        {

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

            return;

        }

        else

            printf("WSAIoctl(SIO_GET_QOS) is OK!\n");

 

        PrintQos(lpqos);

 

        // See if we're set for receiving FD_QOS events only.

        // If so we need to actually invoke QOS on the connection

        // now otherwise client will never receive a RESV message.

        if (iSetQos == SET_QOS_EVENT)

        {

            lpqos->ReceivingFlowspec.ServiceType = serverQos.ReceivingFlowspec.ServiceType;

 

            ret = WSAIoctl(socks[index], SIO_SET_QOS, lpqos, dwBytes, NULL, 0, &dwBytes, NULL, NULL);

            if (ret == SOCKET_ERROR)

            {

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

                return;

            }

            else

                printf("WSAIoctl(SIO_SET_QOS) is OK!\n");

 

            // Change iSetQos so we don't set QOS again if we receive another FD_QOS event

            iSetQos = SET_QOS_BEFORE;

        }

    }

    return;

}

 

// Function: SrvCondAccept

// Description:

//    This is the conditional function for WSAAccept. There is a

//    limitation with the QOS service provider that the QOS values

//    passed into here are unreliable so the option SET_QOS_DURING

//    is rather useless unless we call SIO_SET_QOS with are own

//    values (as opposed to what the client is requesting since

//    that is what is supposed to be returned in lpSQOS). Note that

//    on Windows 98 if lpSQOS is not NULL you have to use set some

//    kind of QOS values (with SIO_SET_QOS) in the conditional function otherwise WSAAccept will fail.

int CALLBACK SrvCondAccept(LPWSABUF lpCallerId,

    LPWSABUF lpCallerdata, LPQOS lpSQOS, LPQOS lpGQOS,

    LPWSABUF lpCalleeId, LPWSABUF lpCalleeData, GROUP *g, DWORD dwCallbackData)

{

    DWORD       dwBytes = 0;

    SOCKET      s = (SOCKET)dwCallbackData;

    SOCKADDR_IN client;

    int         ret;

 

    if (nConns == MAX_CONN)

        return CF_REJECT;

 

    memcpy(&client, lpCallerId->buf, lpCallerId->len);

    printf("Client request: %s\n", inet_ntoa(client.sin_addr));

 

    if (iSetQos == SET_QOS_EVENT)

    {

        printf("Setting for event!\n");

        serverQos.SendingFlowspec.ServiceType |= SERVICE_NO_QOS_SIGNALING;

        serverQos.ReceivingFlowspec.ServiceType |= SERVICE_NO_QOS_SIGNALING;

 

        ret = WSAIoctl(s, SIO_SET_QOS, &serverQos, sizeof(serverQos), NULL, 0, &dwBytes, NULL, NULL);

        if (ret == SOCKET_ERROR)

        {

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

            return CF_REJECT;

        }

        else

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

    }

    return CF_ACCEPT;

}

 

// Function: Server

// Description:

//    This server routine handles incoming client connections.

//    First it sets up the listening socket, sets QOS when

//    appropriate, and wait for incoming clients and events.

void Server(SOCKET s)

{

    SOCKET        sc[MAX_CONN + 1];

    WSAEVENT      hAllEvents[MAX_CONN+1];

    SOCKADDR_IN   local, client;

    int           clientsz, ret, i;

    DWORD         dwBytesRet;

    WSANETWORKEVENTS ne;

 

    // Initialize the arrays to invalid values

    for(i = 0; i < MAX_CONN+1; i++)

    {

        hAllEvents[i] = WSA_INVALID_EVENT;

        sc[i] = INVALID_SOCKET;

    }

 

    // Array index 0 will be our listening socket

    hAllEvents[0] = WSACreateEvent();

    sc[0]         = s;

    nConns        = 0;

 

    local.sin_family = AF_INET;

    local.sin_port = htons(5150);

    local.sin_addr.s_addr = htonl(INADDR_ANY);

 

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

    {

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

        return;

    }

    else

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

 

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

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

    else

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

 

    if (iSetQos == SET_QOS_BEFORE)

    {

        ret = WSAIoctl(sc[0], SIO_SET_QOS, &serverQos, sizeof(serverQos), NULL, 0, &dwBytesRet, NULL, NULL);

        if (ret == SOCKET_ERROR)

        {

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

            return;

        }

        else

            printf("WSAIoctl(SIO_SET_QOS) is OK!\n");

 

        printf("Set QOS on listening socket:\n");

        PrintQos(&serverQos);

    }

 

    if (WSAEventSelect(sc[0], hAllEvents[0], FD_ACCEPT) == SOCKET_ERROR)

    {

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

        return;

    }

    else

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

 

    while (1)

    {

        ret = WSAWaitForMultipleEvents(nConns+1, hAllEvents, FALSE, WSA_INFINITE, FALSE);

        if (ret == WSA_WAIT_FAILED)

        {

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

            return;

        }

        else

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

 

        if ((i = ret - WSA_WAIT_EVENT_0) > 0)  // Client network event

            HandleClientEvents(sc, hAllEvents, i);

        else

        {

            ret = WSAEnumNetworkEvents(sc[0], hAllEvents[0], &ne);

            if (ret == SOCKET_ERROR)

            {

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

                return;

            }

            else

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

 

            if ((ne.lNetworkEvents & FD_ACCEPT) == FD_ACCEPT)

            {

                if (ne.iErrorCode[FD_ACCEPT_BIT])

                    printf("FD_ACCEPT error: %d\n", ne.iErrorCode[FD_ACCEPT_BIT]);

                else

                    printf("FD_ACCEPT...\n");

 

                clientsz = sizeof(client);

                sc[++nConns] = WSAAccept(s, (SOCKADDR *)&client, &clientsz, SrvCondAccept, sc[nConns]);

                if (sc[nConns] == SOCKET_ERROR)

                {

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

                    nConns--;

                    return;

                }

                else

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

 

                hAllEvents[nConns] = WSACreateEvent();

 

                Sleep(1000);

                if (iSetQos == SET_QOS_AFTER)

                {

                    ret = WSAIoctl(sc[nConns], SIO_SET_QOS, &serverQos, sizeof(serverQos), NULL, 0, &dwBytesRet, NULL, NULL);

                    if (ret == SOCKET_ERROR)

                    {

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

                        return;

                    }

                    else

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

                }

                ret = WSAEventSelect(sc[nConns], hAllEvents[nConns], FD_READ | FD_WRITE | FD_CLOSE | FD_QOS);

                if (ret == SOCKET_ERROR)

                {

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

                    return;

                }

                else

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

            }

 

            if (ne.lNetworkEvents & FD_CLOSE)

                printf("FD_CLOSE\n");

            if (ne.lNetworkEvents & FD_READ)

                printf("FD_READ\n");

            if (ne.lNetworkEvents & FD_WRITE)

                printf("FD_WRITE\n");

            if (ne.lNetworkEvents & FD_QOS)

                printf("FD_QOS\n");

        }

    }

    return;

}

// Function: Client

// Description:

//    The client routine initiates the connection, sets QOS when appropriate, and handle incoming events.

void Client(SOCKET s)

{

    SOCKADDR_IN  server, local;

    WSABUF       wbuf;

    DWORD        dwBytes, dwBytesSent, dwBytesRecv, dwFlags;

    HANDLE       hEvent;

    int          ret, i;

    char         databuf[DATA_BUFFER_SZ];

    QOS         *lpqos;

    WSANETWORKEVENTS ne;

 

    hEvent = WSACreateEvent();

    if (hEvent == NULL)

    {

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

        return;

    }

    else

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

 

    lpqos = NULL;

    if (iSetQos == SET_QOS_BEFORE)

    {

        local.sin_family = AF_INET;

        local.sin_port = htons(0);

        local.sin_addr.s_addr = htonl(INADDR_ANY);

 

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

        {

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

            return;

        }

        else

           printf("bind() to local is fine!\n");

 

        ret = WSAIoctl(s, SIO_SET_QOS, &clientQos,sizeof(clientQos), NULL, 0, &dwBytes, NULL, NULL);

 

        if (ret == SOCKET_ERROR)

        {

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

            return;

        }

        else

            printf("WSAIoclt(SIO_SET_QOS) is OK!\n");

    }

    else if (iSetQos == SET_QOS_DURING)

        lpqos = &clientQos;

    else if (iSetQos == SET_QOS_EVENT)

    {

        clientQos.SendingFlowspec.ServiceType |= SERVICE_NO_QOS_SIGNALING;

        clientQos.ReceivingFlowspec.ServiceType |= SERVICE_NO_QOS_SIGNALING;

 

        ret = WSAIoctl(s, SIO_SET_QOS, &clientQos, sizeof(clientQos), NULL, 0, &dwBytes, NULL, NULL);

        if (ret == SOCKET_ERROR)

        {

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

            return;

        }

        else

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

    }

 

    server.sin_family = AF_INET;

    server.sin_port = htons(5150);

    server.sin_addr.s_addr = inet_addr(szServerAddr);

 

    printf("Connecting to: %s\n", inet_ntoa(server.sin_addr));

 

    ret = WSAConnect(s, (SOCKADDR *)&server, sizeof(server), NULL, NULL, lpqos, NULL);

    if (ret == SOCKET_ERROR)

    {

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

        return;

    }

    else

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

 

    ret = WSAEventSelect(s, hEvent, FD_READ | FD_WRITE | FD_CLOSE | FD_QOS);

    if (ret == SOCKET_ERROR)

    {

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

        return;

    }

    else

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

 

    wbuf.buf = databuf;

    wbuf.len = DATA_BUFFER_SZ;

 

    memset(databuf, '$', DATA_BUFFER_SZ);

    databuf[DATA_BUFFER_SZ-1] = 0;

 

    while (1)

    {

        ret = WSAWaitForMultipleEvents(1, &hEvent, FALSE, WSA_INFINITE, FALSE);

        if (ret == WSA_WAIT_FAILED)

        {

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

            return;

        }

        else

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

 

        ret = WSAEnumNetworkEvents(s, hEvent, &ne);

        if (ret == SOCKET_ERROR)

        {

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

            return;

        }

        else

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

 

        if (ne.lNetworkEvents & FD_READ)

        {

            if (ne.iErrorCode[FD_READ_BIT])

                printf("FD_READ error: %d\n", ne.iErrorCode[FD_READ_BIT]);

            else

                printf("FD_READ\n");

 

            wbuf.len = 4096;

            dwFlags = 0;

            ret = WSARecv(s, &wbuf, 1, &dwBytesRecv, &dwFlags, NULL, NULL);

            if (ret == SOCKET_ERROR)

            {

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

                return;

            }

            else

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

 

            printf("Read: %d bytes\n", dwBytesRecv);

 

            wbuf.len = dwBytesRecv;

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

            if (ret == SOCKET_ERROR)

            {

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

                return;

            }

            else

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

 

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

        }

        if (ne.lNetworkEvents & FD_WRITE)

        {

            if (ne.iErrorCode[FD_WRITE_BIT])

                printf("FD_WRITE error: %d\n", ne.iErrorCode[FD_WRITE_BIT]);

            else

                printf("FD_WRITE...\n");

 

            if (!bWaitToSend)

            {

                wbuf.buf = databuf;

                wbuf.len = DATA_BUFFER_SZ;

 

                // If the network can't support the bandwidth don't send

                if (!AbleToSend(s))

                {

                    printf("Network is unable to provide sufficient best effort bandwidth\n");

                    printf("before the reservation request is approved\n");

                }

 

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

                {

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

                    if (ret == SOCKET_ERROR)

                    {

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

                        return;

                    }

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

                }

            }

        }

        if (ne.lNetworkEvents & FD_CLOSE)

        {

            if (ne.iErrorCode[FD_CLOSE_BIT])

                printf("FD_CLOSE error: %d\n", ne.iErrorCode[FD_CLOSE_BIT]);

            else

                printf("FD_CLOSE...\n");

 

            closesocket(s);

            WSACloseEvent(hEvent);

            return;

        }

        if (ne.lNetworkEvents & FD_QOS)

        {

            char        buf[QOS_BUFFER_SZ];

            QOS        *lpqos = NULL;

            DWORD       dwBytes;

            BOOL        bRecvRESV = FALSE;

 

            if (ne.iErrorCode[FD_QOS_BIT])

            {

                printf("FD_QOS error: %d\n", ne.iErrorCode[FD_QOS_BIT]);

                if (ne.iErrorCode[FD_QOS_BIT] == WSA_QOS_RECEIVERS)

                    bRecvRESV = TRUE;

            }

            else

                printf("FD_QOS\n");

 

            lpqos = (QOS *)buf;

            ret = WSAIoctl(s, SIO_GET_QOS, NULL, 0, buf, QOS_BUFFER_SZ, &dwBytes, NULL, NULL);

            if (ret == SOCKET_ERROR)

            {

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

                return;

            }

            else

                printf("WSAIoctl(SIO_GET_QOS) is OK!\n");

 

            PrintQos(lpqos);

 

            // Check to see if there is a status object returned

            // in the QOS structure which may also contain the WSA_QOS_RECEIVERS flag

            if (ChkForQosStatus(lpqos, WSA_QOS_RECEIVERS))

                bRecvRESV = TRUE;

 

            if (iSetQos == SET_QOS_EVENT)

            {

                lpqos->SendingFlowspec.ServiceType = clientQos.SendingFlowspec.ServiceType;

                ret = WSAIoctl(s, SIO_SET_QOS, lpqos, dwBytes, NULL, 0, &dwBytes, NULL, NULL);

                if (ret == SOCKET_ERROR)

                {

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

                    return;

                }

 

                // Change iSetQos so we don't set QOS again if we receive another FD_QOS event

                iSetQos = SET_QOS_BEFORE;

            }

 

            if (bWaitToSend && bRecvRESV)

            {

                wbuf.buf = databuf;

                wbuf.len = DATA_BUFFER_SZ;

 

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

                {

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

                    if (ret == SOCKET_ERROR)

                    {

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

                        return;

                    }

                    else

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

 

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

                }

            }

        }

    }

    return;

}

 

// Function: main

// Description:

//    Initialize Winsock, parse command line arguments, create

//    a QOS TCP socket, and call the appropriate handler routine depending on the arguments supplied

int main(int argc, char **argv)

{

    WSADATA           wsd;

    WSAPROTOCOL_INFO *pinfo = NULL;

    SOCKET            s;

 

    if(argc < 2)

    {

         usage(argv[0]);

         exit(1);

    }

 

    // Parse the command line

    ValidateArgs(argc, argv);

 

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

    {

        printf("Unable to load Winsock, error %d\n", GetLastError());

        return -1;

    }

    else

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

 

    pinfo = FindProtocolInfo(AF_INET, SOCK_STREAM, IPPROTO_TCP, XP1_QOS_SUPPORTED);

    if (!pinfo)

    {

        printf("unable to find suitable provider!\n");

        return -1;

    }

    else

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

 

    printf("Provider returned: %S\n", pinfo->szProtocol);

 

    s = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, pinfo, 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");

 

    InitQos();

 

    if (bServer)

        Server(s);

    else

        Client(s);

 

     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;

}

 

 

 

Related reference:

 

MSDN QOS reference.

 


< QOS Templates | QOS Programming Main | TCP, UDP, ATM & QOS Examples >