📄 qosmcast.c
字号:
// Module Name: qosmcast.c
//
// Description:
// This sample illustrates multicasting with QOS. QOS may be
// set before calling WSAJoinLeaf, during WSAJoinLeaf, after
// WSAJoinLeaf, or QOS may be set when an FD_QOS event has been
// received. This sample acts as wither a sender or receiver.
// In both cases, the multicast group is joined. Multiple
// groups may be joined by specifying one or more -m:IP
// options.
//
// Compile:
// cl qosmcast.c provider.c printqos.c ws2_32.lib
//
// Command Line Parameters/Options
// qosmcast.exe -q:x -s -r -m:IP-addr
// -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 sender
// -r:IP Act as receiver
// -w Wait to send until RESV has arrived
// -m:addr Multicast address to join
// -c Confirm reservation request
//
#include <winsock2.h>
#include <windows.h>
#include <qos.h>
#include <qossp.h>
#include "provider.h"
#include "printqos.h"
#include <stdio.h>
#include <stdlib.h>
#define QOS_BUFFER_SZ 32000 // Default buffer size for SIO_GET_QOS
#define DATA_BUFFER_SZ 2048 // Send/Recv buffer size
#define MAX_MULTICAST_GROUPS 32
#define MAX_RECEIVERS 32
#define SET_QOS_NONE 0 // No QOS
#define SET_QOS_BEFORE 1 // Set QOS on listening socket
#define SET_QOS_DURING 2 // Set QOS during conditional accept
#define SET_QOS_AFTER 3 // Set QOS after accept completed
#define SET_QOS_EVENT 4 // Wait for FD_QOS before setting
int iSetQos, // When to set qos
iNumGroups, // Number of groups to join
iNumSenders;
iFlowStyle=RSVP_DEFAULT_STYLE; // Style
char szMulticastAddrs[MAX_MULTICAST_GROUPS][64],
szSenderAddrs[MAX_RECEIVERS][64];
BOOL bSender, // Sending or receiving?
bWaitToSend, // Wait for confirmation before sending?
bConfirmResv;
QOS sendQos, // Sender's QOS values
recvQos; // Receiver's QOS values
RSVP_RESERVE_INFO qosreserve; // use to set filter style
FLOWDESCRIPTOR flow[MAX_RECEIVERS];
RSVP_FILTERSPEC filters[MAX_RECEIVERS];
//
// 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};
//
// Function: usage
//
// Description:
// Print out usage information.
//
void usage(char *progname)
{
printf("usage: %s -q:x -s -r[:IP] -m:IP-addr\n", progname);
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 sender\n");
printf(" -r[:IP] Act as receiver\n");
printf(" -w Wait to send until RESV has arrived\n");
printf(" -m:addr Multicast address to join\n");
printf(" -f:[se:ff] Filter style\n");
printf(" se Shared explicit style\n");
printf(" ff (Multiple) Fixed filter style\n");
printf(" -c Confirm reservation request\n");
ExitProcess(-1);
}
//
// Function: InitQos
//
// Description:
// Initalize the sending and receiving QOS structures for use in
// setting QOS on a socket. Also use the RSVP_RESERVE_INFO object
// to request confirmation of the reservation request (which is
// only valid for the receiver since it's the receiver who
// generates the RESV statement).
//
void InitQos()
{
sendQos.SendingFlowspec = flowspec_g711;
sendQos.ReceivingFlowspec = flowspec_notraffic;
sendQos.ProviderSpecific.buf = NULL;
sendQos.ProviderSpecific.len = 0;
recvQos.SendingFlowspec = flowspec_notraffic;
recvQos.ReceivingFlowspec = flowspec_g711;
recvQos.ProviderSpecific.buf = NULL;
recvQos.ProviderSpecific.len = 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)
{
char *ptr=NULL;
int i;
// Initialize globals to a default value
//
iSetQos = SET_QOS_NONE;
iNumGroups = 0;
iNumSenders = 0;
bSender = TRUE;
bWaitToSend = FALSE;
bConfirmResv = FALSE;
for(i=1; i < argc ;i++)
{
if ((argv[i][0] == '-') || (argv[i][0] == '/'))
{
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': // sender
bSender = TRUE;
break;
case 'r': // receiver
bSender = FALSE;
if (strlen(argv[i]) > 3)
strcpy(szSenderAddrs[iNumSenders++], &argv[i][3]);
break;
case 'm': // the multicast address to join
if (strlen(argv[i]) > 3)
strcpy(szMulticastAddrs[iNumGroups++], &argv[i][3]);
else
usage(argv[0]);
break;
case 'w': // wait to send data until
// RESV has arrived
bWaitToSend = TRUE;
break;
case 'f': // Filter style
ptr = &argv[i][3];
while (*ptr)
*ptr++ = tolower(*ptr);
if (!strncmp("ff", &argv[i][3], 2))
iFlowStyle = RSVP_FIXED_FILTER_STYLE;
else if (!strncmp("se", &argv[i][3], 2))
iFlowStyle = RSVP_SHARED_EXPLICIT_STYLE;
else
usage(argv[0]);
break;
case 'c': // Confirm reservation
bConfirmResv = TRUE;
break;
default:
usage(argv[0]);
break;
}
}
}
return;
}
//
// Function: SetQosReserveInfo
//
// Description:
// This function simply fills out the RSVP_RESERV_INFO object
// with the requested style and sets the RSVPFLOWDESCRIPTOR
// and RSVP_FILTERSPEC with the sender's addresses according
// to the selected filter style.
//
void SetQosReserveInfo(QOS *lpqos)
{
DWORD dwSize=0;
int i, j;
memset(&qosreserve, 0, sizeof(qosreserve));
//
// Initialize the RSVP_RESERVE_INFO structure
//
qosreserve.ObjectHdr.ObjectType = RSVP_OBJECT_RESERVE_INFO;
qosreserve.ObjectHdr.ObjectLength = sizeof(RSVP_RESERVE_INFO);
qosreserve.Style = iFlowStyle;
qosreserve.ConfirmRequest = bConfirmResv;
qosreserve.NumPolicyElement = 0;
qosreserve.PolicyElementList = NULL;
qosreserve.FlowDescList = flow;
if (iFlowStyle == RSVP_SHARED_EXPLICIT_STYLE)
{
// For shared explicit there is one FLOWSPEC for all
// senders.
//
qosreserve.NumFlowDesc = 1;
flow[0].FlowSpec = lpqos->ReceivingFlowspec;
flow[0].NumFilters = iNumSenders;
flow[0].FilterList = filters;
for(i=0; i < iNumSenders ;i++)
{
filters[i].Type = FILTERSPECV4;
filters[i].FilterSpecV4.Address.Addr = inet_addr(szSenderAddrs[i]);
filters[i].FilterSpecV4.Port = htons(5150);
}
}
else
{
// For multiple fixed filter there is one FLOWSPEC for
// each sender. This means that each RSVPFLOWDESCRIPTOR
// references a single FLOWSPEC and a single RSVP_FILTERSPEC.
//
qosreserve.NumFlowDesc = iNumSenders;
j=0;
for(i=0; i < iNumSenders ;i++)
{
flow[i].FlowSpec = lpqos->ReceivingFlowspec;
flow[i].NumFilters = 1;
flow[i].FilterList = &filters[j];
filters[j].Type = FILTERSPECV4;
filters[j].FilterSpecV4.Address.Addr = inet_addr(szSenderAddrs[j]);
filters[j].FilterSpecV4.Port = htons(5150);
j++;
}
}
lpqos->ProviderSpecific.buf = (char *)&qosreserve;
lpqos->ProviderSpecific.len = sizeof(RSVP_RESERVE_INFO);
return;
}
//
// Function: SetQosReceivers
//
// Description:
// This function sets the RSVP_RESERVE_INFO provider specific
// object if a different filter has been specified along with
// the sender's IP address. It then calls SIO_SET_QOS to set
// the supplied QOS parameters on the socket.
//
BOOL SetQosReceivers(SOCKET s, QOS *lpqos)
{
int ret;
DWORD dwBytes,
dwSize;
if (iNumSenders > 0)
{
SetQosReserveInfo(lpqos);
dwSize = sizeof(QOS) + sizeof(RSVP_RESERVE_INFO);
}
else
{
lpqos->ProviderSpecific.buf = NULL;
lpqos->ProviderSpecific.len = 0;
dwSize = sizeof(QOS);
}
PrintQos(lpqos);
ret = WSAIoctl(s, SIO_SET_QOS, lpqos, dwSize, NULL, 0,
&dwBytes, NULL, NULL);
if (ret == SOCKET_ERROR)
{
printf("WSAIoctl(SIO_SET_QOS) failed: %d\n",
WSAGetLastError());
return FALSE;
}
return TRUE;
}
//
// 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: MulticastDriver
//
// Description:
// Because the only difference between the sender and the
// receiver is calling WSARecvFrom or WSASendTo, we implement
// both sides in this one function.
//
void MulticastDriver(SOCKET s)
{
WSANETWORKEVENTS ne;
SOCKADDR_IN mcast,
from,
local;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -