Programming QOS

Central to QOS is the initiation of an RSVP session. It's not until the RSVP PATH and RESV messages have been sent and processed that bandwidth is reserved for the process. Knowing when RSVP messages are generated is important to applications. For senders, three parameters must be known before a PATH message is generated:

  • Sending FLOWSPEC member
  • Source IP address and port
  • Destination IP address, port, and protocol

The FLOWSPEC member is known whenever a QOS-enabled function is called, such as WSAConnect, WSAJoinLeaf, WSAIoctl (with the SIO_SET_QOS option), and so on. The source IP address and port will not be known until the socket is bound locally, either implicitly (such as by connecting) or explicitly by bind. Finally, the application needs the data's destination. This information is gathered upon either a connect call or, in the case of connectionless UDP, the setting of the QOS_DESTADDR object in the provider-specific data passed using the SIO_SET_QOS ioctl command.

Similarly, for an RSVP RESV message to be generated, three things must be known:

  • Receiving FLOWSPEC member
  • Address and port of each sender
  • Local address and port of the receiving socket

The receiving FLOWSPEC member is obtained from any of the QOS-enabled Winsock functions. The address and port of each sender depend on the filter style, which can be set manually via the RSVP_RESERVE_INFO provider-specific structure, discussed earlier. Otherwise, this information is obtained from a PATH message. Of course, depending on the socket type, it is not always necessary to have already received a PATH statement to obtain the sender's address to generate RESV messages. The wildcard filter style used in multicasting is an example of this. The RESV message sent applies to all senders in the session. The local address and port are self-explanatory for unicast and UDP receivers but not for multicast receivers. In the case of multicast receivers, the local address and port are the multicast address and its corresponding port number.

In this section, we'll first cover the different socket types and their interaction with the QOS service provider and RSVP messages. Then we'll take a look at how the QOS service provider notifies applications of certain events. Understanding these concepts is central to writing successful QOS-enabled applications. Programming such applications is a matter of knowing how to obtain QOS guarantees as well as knowing when those guarantees are put into effect and when and how they can change.

RSVP and Socket Types

We now have a basic understanding of how PATH and RESV RSVP messages are generated. In the following sections, we'll look at the different types of sockets—UDP, TCP, and multicast UDP—and how they interact with the QOS service provider to generate PATH and RESV messages.

Unicast UDP

Because you have the option of using either connected or unconnected UDP sockets, setting QOS on unicast UDP sockets presents quite a few options. In the case of the UDP sender, the sending FLOWSPEC is obtained from one of the QOS-invoking functions. The local address and port are obtained either from an explicit bind call or from an implicit bind done by WSAConnect. The last piece is the address and port of the receiving application, which can be specified either in WSAConnect or via the QOS_DESTADDR provider-specific structure passed through the SIO_SET_QOS option. Be aware that if SIO_SET_QOS is used to set QOS, the socket must be bound beforehand.

For the UDP receiver, WSAConnect can be called to limit the receiving application to a single sender. Additionally, applications can specify a QOS_DESTADDR structure with the SIO_SET_QOS ioctl command. Otherwise, the SIO_SET_QOS can be called without providing any kind of destination address. In this case, a RESV message will be generated with the wildcard filter style. In fact, specifying the destination address via WSAConnect or via the QOS_DESTADDR structure should be done only if you want the application to receive data from only one sender that uses the fixed filter style.

The UDP receiver can actually call both WSAConnect and the SIO_SET_QOS ioctl command in any order. If SIO_SET_QOS is called before WSAConnect, a RESV message is created with the wildcard filter first. Once the connect call is made, the previous RESV session is torn down and a new one is generated with the fixed filter style. Alternatively, calling SIO_SET_QOS after WSAConnect and a fixed filter RESV message does not negate the RSVP session and generate a wildcard filter style. Instead it simply updates the QOS parameters associated with the existing RSVP session.

Unicast TCP

TCP sessions have two possibilities. First, the sender can be the client who connects to the server and sends data. The second possibility is that the server that the client connects to might be the sender. In the case of the client, QOS parameters can be specified directly in the WSAConnect call, which will result in PATH messages being sent. The ioctl command SIO_SET_QOS can also be called before calling connect, but until one of the connect calls knows the destination address, no PATH messages will be generated.

In the case in which the sender is the server, the server calls WSAAccept to accept the client connection. This function does not provide a means of setting QOS on the accepted socket. If QOS is set before a call to WSAAccept by using SIO_SET_QOS, any accepted socket inherits the QOS levels set on the listening socket. Note that if the sender uses the conditional function in WSAAccept, the function should pass QOS values set on the connecting client. However, this is not the case. The QOS service provider passes junk, which is the behavior on both Windows 98 and Windows 2000. The exception is that if the lpSQOS parameter is non-null under Windows 98, some kind of QOS values must be set via the SIO_SET_QOS ioctl command within the conditional function; otherwise, the WSAAccept call fails even if CF_ACCEPT is returned. QOS can also be set on the client socket after it has been accepted.

Let's look at receiving TCP applications. The first case is calling WSAConnect with a receiving FLOWSPEC. When this occurs, the QOS service provider creates a RESV request. If QOS parameters are not supplied to WSAConnect, the SIO_SET_QOS ioctl command can be set at a later time (resulting in a RESV message). The last combination is the server being the receiver, which is similar to the sending case. QOS can be set on the listening socket before a WSAAccept call, in which case the client socket inherits the same QOS levels. Otherwise, QOS can be set in the conditional function or after the socket has been accepted. In either case, the QOS service provider generates a RESV message as soon as a PATH message arrives.

Multicast

Multicast senders behave the same way as UDP senders except that WSAJoinLeaf is used to become a member of the multicast group, as opposed to calling WSAConnect with the destination address. QOS can be set with WSAJoinLeaf or separately through an SIO_SET_QOS call. The multicast session address is used to compose the RSVP session object included in the RSVP PATH message.

In the case of the multicast receiver, no RESV messages will be generated until the multicast address is specified via the WSAJoinLeaf function. Because the multicast receiver doesn't specify a peer address, the QOS provider generates RESV messages with the wildcard filter style. The QOS service provider does not prohibit a socket from joining multiple multicast groups. In this case, the service provider sends RESV messages for all groups that have a matching PATH message. The QOS parameters supplied to each WSAJoinLeaf will be used in each RESV message, but if SIO_SET_QOS is called on the socket after joining multiple groups, the new QOS parameters will be applied to all multicast groups joined.

When a sender sends data to a multicast group, only data sent to the multicast group that the sender joined results in QOS being applied to that data. In other words, if you join one multicast group and use sendto/WSASendTo with any other multicast group as the destination, QOS is not applied to that data. Additionally, if a socket joins a multicast group specifying a particular direction (for example, using JL_SENDER_ONLY or JL_RECEIVER_ONLY in the dwFlags parameter to WSAJoinLeaf), QOS is applied accordingly. A socket set as a receiver only will not gain any QOS benefits for sent data.

QOS Notifications

Thus far, you have learned how to invoke QOS for TCP, UDP, and multicast UDP sockets and the corresponding RSVP events that occur depending on whether you're sending or receiving. However, the completion of these RSVP messages is not strictly tied to the API calls that invoke them. That is, issuing a WSAConnect call for a TCP receiving socket generates a RESV message, but the RESV message is independent of the actual API call in that the call returns without any assurances that the reservation is approved and network resources are allocated. Because of this, a new asynchronous event has been added, FD_QOS, which is posted to a socket. Typically, an FD_QOS event notification will be posted in the following events.

  • Notification of the acceptance or rejection of the application's QOS request
  • Significant changes in the QOS provided by the network (as opposed to previously negotiated values)
  • Status regarding whether a QOS peer is ready to send or receive data for a particular flow

Registering for FD_QOS notifications

To take advantage of these notifications, an application must register to be notified when an FD_QOS event occurs. There are a couple ways to do this. First you can use either WSAEventSelect or WSAAsyncSelect and include the FD_QOS flag in the bitwise ORing of event flags. However, an application is eligible to receive the FD_QOS event only if a call has already been made to one of the QOS invoking functions. Note that in some cases an application might want to receive the FD_QOS event without having to set QOS levels on a socket. This can be accomplished by setting up a QOS structure whose sending and receiving FLOWSPEC members contain either the QOS_NOT_SPECIFIED or the SERVICETYPE_NOTRAFFIC flag. The only catch is that the SERVICE_NO_QOS_SIGNALING flag must be ORed with the SERVICETYPE_NOTRAFFIC flag for the direction of QOS in which you want to receive event notification.

If you need exact information on how to call the two asynchronous select functions, consult Chapter 8, which covers them in great detail. If you use WSAEventSelect once the event has been triggered, call the WSAEnumNetworkEvents function to obtain additional status codes that might be available. This function is also covered in Chapter 8, but we'll review it here since it's short, simple, and important to QOS applications. Pass the socket handle, the event handle, and a WSANETWORKEVENTS object into the call, which will return and set event information into the supplied structure. This structure is defined as

 typedef struct _WSANETWORKEVENTS { long lNetworkEvents; int iErrorCode[FD_MAX_EVENTS]; } WSANETWORKEVENTS, FAR * LPWSANETWORKEVENTS; 

The lNetworkEvents field will be set to a bitwise ORing of all the event flags triggered. To detect the occurrence of a particular event, simply AND (with the & operator) this field with the event flag. If the result is nonzero, that event was triggered. The iErrorCode array is used to indicate errors or, in the case of QOS, status information. If an event is triggered, a flag corresponding to that event is used to index into this array. If the value of the array index is 0, no error occurred; otherwise, the value is an index to the array element that contains the error code. For example, if the FD_QOS event was triggered, use the FD_QOS_BIT flag to index into the iErrorCode array to check for any errors or status information. All other Winsock asynchronous events (FD_READ_BIT, FD_WRITE_BIT, and so on) have similarly defined index flags.

RSVP notifications

We mentioned earlier that there are a couple of ways to receive QOS notifications. This information actually ties into this section: obtaining the results of a QOS event. If you have registered to receive FD_QOS notifications with either WSAAsyncSelect or WSAEventSelect and you actually receive an FD_QOS event notification, you must perform a call to WSAIoctl with the SIO_GET_QOS ioctl option to find out what triggered the event. You don't actually have to register for FD_QOS events—you can simply call WSAIoctl with the SIO_GET_QOS command using overlapped I/O. This also requires that you specify a completion routine, which is invoked once the QOS service provider detects a change in QOS. Once the callback occurs, a QOS structure will be available in the output buffer.

In either case, once a change in QOS has occurred, your application can be notified of this change by registering for FD_QOS or by using overlapped I/O and SIO_GET_QOS. If you register for FD_QOS, you also want to call WSAIoctl with the SIO_GET_QOS ioctl command upon event notification. For both methods, the QOS structure returned contains QOS information for only a single direction. That is, the FLOWSPEC structure for the invalid direction has its ServiceType field set to SERVICETYPE_NOCHANGE. Additionally, more than one QOS event might have occurred, in which case you should call WSAIoctl and SIO_GET_QOS in a loop until SOCKET_ERROR is returned and WSAGetLastError returns WSAEWOULDBLOCK. The final concern when calling SIO_GET_QOS is the buffer size. When an FD_QOS event has been triggered, it is possible that provider-specific objects will be returned. In fact, the RSVP_STATUS_INFO structure will most often be returned, provided the buffer is large enough. See the earlier entry on WSAIoctl for information on how to find the right-size buffer.

If your application uses one of the asynchronous event functions, a particularly important issue is that once an FD_QOS event occurs, you must always perform an SIO_GET_QOS operation to reenable FD_QOS notifications.

You now know how to receive QOS event notifications and obtain new QOS parameters as a result of these events, but what types of notifications will occur? The first and most obvious reason for a QOS event is a change in the FLOWSPEC parameters for a given flow. For example, if you set up a socket with best effort service, periodically the QOS service provider will send notification to your application indicating the current conditions on the network. Additionally, if you specify controlled load as well as other parameters, the QOS parameters for token bucket size and token rate might change slightly from what you requested once the reservation occurs. Your application should compare the FLOWSPEC returned once a QOS notification occurs to what you originally requested to ensure that it is sufficient for your application to continue. Also remember that throughout the life of a QOS-enabled socket, you can always perform a SIO_SET_QOS to change any of the parameters, which will result in a QOS notification for the peer or peers associated with your current RSVP session. A robust application should be able to handle these conditions.

In addition to updating QOS parameters, QOS event notification signals other occurrences, such as notification of senders or receivers. The possible events are listed in Table 12-6. There are two ways to obtain these status codes. The first is as a part of the RSVP_STATUS_INFO object. When a QOS event occurs and a call is made to SIO_GET_QOS, it is possible that a RSVP_STATUS_INFO object will be returned as part of the provider-specific buffer. Second, if you use WSAEventSelect to register for events, these codes can be returned in the WSANETWORKEVENTS structure returned from WSAEnumNetworkEvents. The codes defined in Table 12-6 can be found in the iErrorCode array, indexed by FD_QOS_BIT. The first five codes listed are not error codes. They return valuable information concerning the status of the QOS connection. The other status codes listed in the table are QOS errors of concern, but they won't prevent you from sending and receiving data—they merely indicate an error in the QOS session. Of course, data sent in this situation will not carry any of the requested QOS guarantees.

WSA_QOS_RECEIVERS and WSA_QOS_NO_RECEIVERS

In the case of unicast, after a sender starts up and receives the first RESV message, a WSA_QOS_RECEIVERS is passed up to the application. If the receiver performs any of the steps to disable QOS, the result is a RESV teardown message. Once the sender receives this, WSA_QOS_NO_RECEIVERS is passed up to the application. Of course, with unicast many receivers simply close the socket, generating both an FD_CLOSE event and the WSA_QOS_NO_RECEIVERS event. In most cases, an application's response is simply to close the sending socket.

In the case of multicast, the sending application receives WSA_QOS_RECEIVERS whenever the number of receivers changes and is nonzero. In other words, a single multicast sender receives WSA_QOS_RECEIVERS every time a QOS receiver joins the group, as well as every time a receiver drops out of a group—as long as at least one receiver remains.

WSA_QOS_SENDERS and WSA_QOS_NO_SENDERS

The senders notification is similar to the receivers event except that it deals with the receipt of the PATH message. For unicast receivers after startup, the receipt of the first PATH message generates WSA_QOS_SENDERS, while the PATH teardown message initiates a WSA_QOS_NO_SENDERS message.

Likewise, multicast receivers receive the WSA_QOS_SENDERS notification whenever the number of senders decrements or increments and is nonzero. Once the number of senders reaches 0, the WSA_QOS_NO_SENDERS message is passed to the application.

WSA_QOS_REQUEST_CONFIRMED

This last status message is issued to receiving QOS applications if they ask to be notified when a reservation request has been confirmed. Within the RSVP_STATUS_INFO structure is a field, ConfirmRequest, which if set to nonzero informs the QOS service provider to notify the application when the reservation request has been confirmed. This object is a provider-specific option that can be passed along with a QOS structure to the SIO_SET_QOS ioctl command.

QOS Templates

Winsock provides several predefined QOS structures, referred to as templates, that an application can query by name. These templates define the QOS parameters for some common audio and video codecs, such as G711 and H263QCIF. The function WSAGetQOSByName is defined as

 BOOL WSAGetQOSByName( SOCKET s, LPWSABUF lpQOSName, LPQOS lpQOS ); 

If you don't know the name of the installed templates, you can use this function to first enumerate all template names. This is accomplished by providing a sufficiently large buffer in lpQOSName with its first character set to the null character and passing a null pointer for lpQOS, as in the following code:

 WSABUF wbuf; char cbuf[1024]; cbuf[0] = '\0'; wbuf.buf = cbuf; wbuf.len = 1024; WSAGetQOSByName(s, &wbuf, NULL); 

Upon return, the character buffer is filled with an array of strings separated by a null character, and the entire list is terminated by another null character. This means the last string entry will have two consecutive null characters. From here you can get the names of all the installed templates and query for a specific one. The following code looks up the G711 template:

 QOS qos; WSABUF wbuf; wbuf.buf = "G711"; wbuf.len = 4; WSAGetQOSByName(s, &wbuf, &qos); 

In the event that the requested QOS template does not exist, the lookup returns FALSE and the error is WSAEINVAL. Upon success, the function returns TRUE. The example Qostemplate.c on the accompanying CD illustrates how to enumerate the installed QOS templates.

Additionally, you can install your own QOS template so that other applications can query for it by name. Two functions—WSCInstallQOSTemplate and WSCRemoteQOSTemplate—do this. The first function installs a QOS template, and the second removes it. The prototypes are

 BOOL WSCInstallQOSTemplate( const LPGUID lpProviderId, LPWSABUF lpQOSName, LPQOS lpQOS ); BOOL WSCRemoveQOSTemplate( const LPGUID lpProviderId, LPWSABUF lpQOSName ); 

These two functions are fairly self-explanatory. To install a template, call WSCInstallQOSTemplate with a GUID, the name of the template, and the QOS parameters. The GUID is a unique identifier for this template that can be generated by such utilities as Uuidgen.exe. To remove the template, simply supply the template name—along with the same GUID used in the installation process—to WSCRemoveQOSTemplate. Both functions return TRUE when successful.



Network Programming for Microsoft Windows
Linux Server Hacks, Volume Two: Tips & Tools for Connecting, Monitoring, and Troubleshooting
ISBN: 735615799
EAN: 2147483647
Year: 1998
Pages: 159

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