blob: 850444e28fd143243d1d95e2ea3fe5e59d27e551 [file] [log] [blame]
/****************************************************************************
* (c) Copyright 2007 Wi-Fi Alliance. All Rights Reserved
*
*
* LICENSE
*
* License is granted only to Wi-Fi Alliance members and designated
* contractors ($B!H(BAuthorized Licensees$B!I(B)..AN Authorized Licensees are granted
* the non-exclusive, worldwide, limited right to use, copy, import, export
* and distribute this software:
* (i) solely for noncommercial applications and solely for testing Wi-Fi
* equipment; and
* (ii) solely for the purpose of embedding the software into Authorized
* Licensee$B!G(Bs proprietary equipment and software products for distribution to
* its customers under a license with at least the same restrictions as
* contained in this License, including, without limitation, the disclaimer of
* warranty and limitation of liability, below..AN The distribution rights
* granted in clause
* (ii), above, include distribution to third party companies who will
* redistribute the Authorized Licensee$B!G(Bs product to their customers with or
* without such third party$B!G(Bs private label. Other than expressly granted
* herein, this License is not transferable or sublicensable, and it does not
* extend to and may not be used with non-Wi-Fi applications..AN Wi-Fi Alliance
* reserves all rights not expressly granted herein..AN
*.AN
* Except as specifically set forth above, commercial derivative works of
* this software or applications that use the Wi-Fi scripts generated by this
* software are NOT AUTHORIZED without specific prior written permission from
* Wi-Fi Alliance.
*.AN
* Non-Commercial derivative works of this software for internal use are
* authorized and are limited by the same restrictions; provided, however,
* that the Authorized Licensee shall provide Wi-Fi Alliance with a copy of
* such derivative works under a perpetual, payment-free license to use,
* modify, and distribute such derivative works for purposes of testing Wi-Fi
* equipment.
*.AN
* Neither the name of the author nor "Wi-Fi Alliance" may be used to endorse
* or promote products that are derived from or that use this software without
* specific prior written permission from Wi-Fi Alliance.
*
* THIS SOFTWARE IS PROVIDED BY WI-FI ALLIANCE "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A.AN PARTICULAR PURPOSE,
* ARE DISCLAIMED. IN NO EVENT SHALL WI-FI ALLIANCE BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, THE COST OF PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************
*/
/*
* File: wfa_tg.c
* Library functions for traffic generator.
* They are shared with both TC and DUT agent.
*
* Revision History:
* 2006/03/10 -- initially created by qhu
* 2006/06/01 -- BETA release by qhu
* 2006/06/13 -- 00.02 release by qhu
* 2006/06/30 -- 00.10 Release by qhu
* 2006/07/10 -- 01.00 Release by qhu
* 2006/08/01 -- 01.03 fix ping result unreachable caused by random output
* timing. Add 2 seconds wait-time.
* change priority level to 40 max while traffic
* sending/receiving and 60 min for normal state.
* 2006/09/01 -- 01.05 Release by qhu
* 2006/10/26 -- 01.06 released by qhu
* 2006/10.20 -- bug fixes report by n. ojannen
* 2006/12/30 -- bug fix. a potential race condition for transaction test, * reported by c.benson.
* 2006/01/11 -- 01.10 released by qhu
* 2007/02/15 -- WMM Extension Beta released by qhu, mkaroshi
* 2007/03/15 -- develop a better rate control method for sendLong
* a major bug fix for File receive that opens socket with
* source port. It should be destination port. This was
* an early mistake because of interpretation.
* 2007/03/30 -- 01.40 WPA2 and Official WMM Beta Release by qhu
* 2007/04/20 -- 02.00 WPA2 and Official WMM Release by qhu
* 2007/08/15 -- 02.10 WMM-Power Save release by qhu
* 2007/10/10 -- 02.20 Voice SOHO beta -- qhu
* 2007/11/07 -- 02.30 Voice HSO -- qhu
* -- revise the code for traffic throttled control
* -- take care of EAGAIN error return by socket sendto() -- suggested
* by tterhaar
*/
#ifndef WIN32
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <signal.h>
#include <fcntl.h>
#include <netdb.h>
#include <pthread.h>
#include <semaphore.h>
#else
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#endif /* !WIN32 */
#include "wfa_debug.h"
#include "wfa_ver.h"
#include "wfa_main.h"
#include "wfa_tlv.h"
#include "wfa_tg.h"
#include "wfa_cmds.h"
#include "wfa_sock.h"
#include "wfa_rsp.h"
#include "wfa_wmmps.h"
#include "wfa_types.h"
#include "wfa_miscs.h"
int usedThread = 0;
BYTE Send_dutResp[WFA_BUFF_512];
extern void wfaSentStatsResp(BYTE*);
#ifndef WIN32
tgWMM_t wmm_thr[WFA_THREADS_NUM];
extern sem_t sem_wmm;
extern sem_t sem_wmm_resp;
extern sem_t sem_gtgrecv;
extern sem_t sem_iptv_gtgrecv[WFA_MAX_TRAFFIC_STREAMS];
int gnumStreams;
pthread_t thrid[WFA_MAX_TRAFFIC_STREAMS];
#else
extern HANDLE thr_flag_cond;
DWORD dwpingThread;
DWORD dwGenericThread;
HANDLE pinghThread = NULL;
HANDLE hTimerThread = NULL;
HANDLE hThread1 = NULL;
HANDLE hThread2 = NULL;
HANDLE g_hRecvEvent = NULL;
HANDLE send_event = NULL;
extern HANDLE g_RecvhThread;
extern HANDLE g_IPTVRecvhThread[WFA_MAX_TRAFFIC_STREAMS];
HANDLE g_recvEvent[WFA_MAX_TRAFFIC_STREAMS];
DWORD dwGenericThread2;
DWORD dwGenericThread1;
DWORD dwIPTVThread;
HANDLE g_TGSndThr[WFA_MAX_TRAFFIC_STREAMS];
extern ULONG exitcode;
extern HANDLE processHandle;
extern void SendIPTVFile(LPVOID);
#endif /* !WIN32 */
extern tgStream_t *gStreams;
extern BOOL gtgRecv;
extern BOOL gtgSend;
extern BOOL gtgTransac;
extern int btSockfd;
extern int btRecvSockfd;
extern int gTcpRecvSockfd;
extern int gTCPsock;
extern int gtimeOut;
extern int gRegSec;
extern int isExit;
extern int adj_latency;
extern tgStream_t *findStreamProfile(int);
extern int wfaTrafficSendTo(int, char *, int, struct sockaddr *);
extern int wfaTrafficRecv(int, char *, struct sockaddr *);
extern unsigned short wfa_defined_debug;
extern int tgSockfds[];
extern int wfaTGSetPrio(int sockfd, int tgClass);
extern double min_rttime;
extern tgSyncTime_t gtgFinishSyncTime;
extern BOOL gtgStartSync;
extern BOOL gtgFinishSync;
extern tgE2EStats_t *e2eStats;
extern int e2eCnt;
extern void wfaRecvThrCreate(void);
extern void wfaIPTVRecvThrCreate(int);
extern void SendFile(void);
extern int IPTVprof;
extern tgSyncTime_t gtgStartSyncTime;
#ifdef WFA_WMM_EXT
extern tgWMM_t wmm_thr[];
#ifdef WFA_WMM_PS_EXT
extern int gtgWmmPS;
extern wfaWmmPS_t wmmps_info;
extern int psSockfd;
extern unsigned long psTxMsg[];
extern unsigned long psRxMsg[];
extern int gtgPsPktRecvd;
dutCmdResponse_t gGenericResp;
extern void wfaSetDUTPwrMgmt(int mode);
void wmmps_wait_state_proc();
#endif /* WFA_WMM_PS_EXT */
#endif /* WFA_WMM_EXT */
static int runLoop = 0;
extern volatile int gTransactrunLoop;
static int streamId = 0;
static int totalTranPkts = 0, sentTranPkts = 0;
static int slotCnt = 0;
int clock_drift_ps = 0; // drift(usec) per second
char e2eResults[32];
extern dutCmdResponse_t gGenericResp;
#ifdef WIN32
unsigned int Timerid;
extern DWORD Win32_tmout_stop_send(LPVOID num ) ;
extern DWORD PingStart();
char PingStr[WFA_BUFF_512];
#ifndef MAX_UDP_LEN
#define MAX_UDP_LEN 2048
#endif /*MAX_UDP_LEN*/
#define HIGH_FRAME_RATE_VAL 500
#define SLEEP_DENOMINATOR 5
#endif /*WIN32*/
/* Some devices may only support UDP ECHO and do not have ICMP level ping */
// #define WFA_PING_UDP_ECHO_ONLY 1
/*
* Each packet will have the header in the data field
*/
void wfa_syncd_time(tgSyncTime_t *startTime, tgSyncTime_t *finishTime)
{
#ifdef WFA_WMM_EXT
#ifndef WIN32
DPRINT_INFO(WFA_OUT, "finish tm time %f start tm time %f\n", finishTime->tm_time, startTime->tm_time);
DPRINT_INFO(WFA_OUT, "finish dut time %f startTime dut time %f \n", finishTime->dut_time, startTime->dut_time);
if(startTime->dtime > finishTime->dtime)
startTime->dtime = finishTime->dtime;
DPRINT_INFO(WFA_OUT, "roundtrip delay time (usec): %i\n", (int) (1000000 * startTime->dtime));
clock_drift_ps = 1000000*( (finishTime->tm_time - startTime->tm_time)-(finishTime->dut_time - startTime->dut_time) ) /
(finishTime->dut_time - startTime->dut_time);
DPRINT_INFO(WFA_OUT, "drift per second %i\n", clock_drift_ps);
#endif /* !WIN32 */
#endif /* !WFA_WMM_EXT */
}
#ifndef WIN32
/* this is to stop sending packets by timer */
void tmout_stop_send(int num)
{
#ifdef WFA_WMM_EXT
int i;
#endif /* WFA_WMM_EXT */
DPRINT_INFO(WFA_OUT, "timer fired, stop sending traffic\n");
/*
* After runLoop reset, all sendLong will stop
*/
runLoop = 0;
gTransactrunLoop = 0;
#ifdef WFA_WMM_EXT
/*
* once usedThread is reset, WMM tests using multithread is ended
* the threads will be reused for the next test.
*/
usedThread--;
//if(usedThread == 0)
sem_post(&sem_wmm_resp);
#endif /* WFA_WMM_EXT */
/*
* once the stream table slot count is reset, it implies that the test
* is done. When the next set profile command comes in, it will reset/clean
* the stream table.
*/
slotCnt = 0;
/*
* The test is for DT3 transaction test.
* Timeout to stop it.
*/
if(gtgTransac != 0)
{
gtgSend = 0;
gtgRecv = 0;
gtgTransac = 0;
asd_closeSocket(btSockfd);
btSockfd = -1;
#ifdef WFA_WMM_EXT
/* Voice End 2 End Sync */
min_rttime = 0xFFFFFFFF;
if(gtgStartSync != 0)
{
gtgStartSync = 0;
DPRINT_INFO(WFA_OUT, "stopping StartSync\n");
}
if(gtgFinishSync != 0)
{
/* derive the clock drift */
wfa_syncd_time(&gtgStartSyncTime, &gtgFinishSyncTime);
gtgFinishSync = 0;
DPRINT_INFO(WFA_OUT, "stoping Finish Sync\n");
}
#endif /* WFA_WMM_EXT */
}
#ifdef WFA_WMM_EXT
/*
* all WMM streams also stop
*/
for(i=0; i<WFA_TRAFFIC_CLASS_NUM; i++)
{
wmm_thr[i].thr_flag = 0;
}
#endif /* WFA_WMM_EXT */
/* all alarms need to reset */
alarm(0);
}
#endif /* !WIN32 */
/*
* findStreamProfile(): search existing stream profile by stream id
* input: id - stream id;
* return: matched stream profile
*/
tgStream_t *findStreamProfile(int id)
{
int i;
tgStream_t *myStream = gStreams;
for(i = 0; i< WFA_MAX_TRAFFIC_STREAMS; i++)
{
if(myStream->id == id)
return myStream;
myStream++;
}
return NULL;
}
/*
* wfaTGSendPing(): Instruct Traffic Generator to send ping packets
*
*/
int wfaTGSendPing(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf)
{
int totalpkts;
char cmdStr[WFA_BUFF_128];
int streamid = ++streamId;
float interval; /* it could be subseconds/100s minisecond */
tgPingStart_t *staPing = (tgPingStart_t *)caCmdBuf;
dutCmdResponse_t *spresp = &gGenericResp;
#ifdef WFA_PING_UDP_ECHO_ONLY
tgStream_t *myStream = NULL;
#endif
DPRINT_INFO(WFA_OUT, "Entering wfaTSendPing ...\n");
if(staPing->frameSize == 0)
staPing->frameSize = 100;
if(staPing->frameRate == 0)
staPing->frameRate = 1;
interval = (float)1/staPing->frameRate;
if(staPing->duration == 0)
staPing->duration = 30;
switch(staPing->type)
{
case WFA_PING_ICMP_ECHO:
#ifndef WFA_PING_UDP_ECHO_ONLY
totalpkts = staPing->duration * staPing->frameRate;
#ifndef WIN32
sprintf(cmdStr, "echo streamid=%i > %s; %s -c %i -s %i -q %s >> %s 2>/dev/null&",
streamid, SPOUT_FILE_PATH, PING_PATH, totalpkts, staPing->frameSize, staPing->dipaddr, SPOUT_FILE_PATH);
system(cmdStr);
#endif
spresp->status = STATUS_COMPLETE;
spresp->streamId = streamid;
#else
DPRINT_INFO(WFA_OUT, "Only support UDP ECHO\n");
#endif
break;
case WFA_PING_UDP_ECHO:
{
#ifdef WFA_PING_UDP_ECHO_ONLY
/*
* Make this like a transaction testing
* Then make it a profile and run it
*/
myStream = &gStreams[slotCnt++];
memset(myStream, 0, sizeof(tgStream_t));
memcpy(&myStream->profile, caCmdBuf, len);
myStream->id = streamid; /* the id start from 1 */
myStream->tblidx = slotCnt-1;
btSockfd = wfaCreateUDPSock("127.0.0.1", WFA_UDP_ECHO_PORT);
if((btSockfd = wfaConnectUDPPeer(btSockfd, staPing->dipaddr, WFA_UDP_ECHO_PORT)) > 0)
{
gtgTransac = streamid;
gtgSend = streamid;
totalTranPkts = 512;
sentTranPkts = 0;
/*
* the framerate here is used to derive the timeout
* value for waiting transaction echo responses.
*/
gtimeOut = MINISECONDS/staPing->frameRate; /* in msec */
gRegSec = 0;
/* set to longest time */
if(staPing->duration == 0)
staPing->duration = 3600;
}
#else
DPRINT_INFO(WFA_OUT, "Doesn't support UDP Echo\n");
#endif
break;
}
default:
{
spresp->status = STATUS_INVALID;
spresp->streamId = streamid;
}
}
wfaEncodeTLV(WFA_TRAFFIC_SEND_PING_RESP_TLV, sizeof(dutCmdResponse_t), (BYTE *)spresp, respBuf);
*respLen = WFA_TLV_HDR_LEN + sizeof(dutCmdResponse_t);
return TRUE;
}
/*
* tgStopPing(): Instruct Traffic Generator to stop ping packets
*
*/
int wfaTGStopPing(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf)
{
int streamid = (int )(caCmdBuf+4);
dutCmdResponse_t *stpResp = &gGenericResp;
FILE *tmpfile = NULL;
tgStream_t *myStream;
#ifndef WIN32
char strout[WFA_BUFF_256];
#else
FILE *stptmpFile = NULL;
unsigned int position =0, recbfping =0, sentbfping =0, received =0, sent =0;
#endif
stpResp->status = STATUS_COMPLETE;
DPRINT_INFO(WFA_OUT, "Entering wfaTStopPing ...\n");
if(( gtgTransac == streamid) && (gtgSend == streamid))
{
gtgTransac =0;
gtgSend = 0;
gtimeOut = 0;
gtgRecv = 0;
#ifndef WIN32
alarm(0);
#endif
gRegSec = 1;
myStream = findStreamProfile(streamid);
if(myStream == NULL)
{
stpResp->status = STATUS_INVALID;
}
stpResp->cmdru.pingStp.sendCnt = myStream->stats.txFrames;
stpResp->cmdru.pingStp.repliedCnt = myStream->stats.rxFrames;
}
else
{
#ifndef WIN32
/* Ping will be stopped after the specified duration which will
* be specified by the user at the time send ping. For some reason popen with grep
* does not work well in Intel PXA with Linux
* Use system() call for such things and avoid using popen
*/
sprintf(strout, "cat %s |grep transmitted | awk '{print $1,$4}' >%s 2>&1",
SPOUT_FILE_PATH, TMP_FILE_PATH);
system(strout);
tmpfile = fopen(TMP_FILE_PATH, "rb");
if (tmpfile == NULL) {
DPRINT_ERR(WFA_ERR, "\nShell Cmd:File open error\n");
stpResp->status = STATUS_COMPLETE;
wfaEncodeTLV(WFA_TRAFFIC_STOP_PING_RESP_TLV, sizeof(dutCmdResponse_t), (BYTE *)stpResp, respBuf);
*respLen = WFA_TLV_HDR_LEN + sizeof(dutCmdResponse_t);
return TRUE;
}
DPRINT_INFO(WFA_OUT,"\nCmdStr is:%s\n", strout);
fgets(strout, sizeof(strout), tmpfile);
stpResp->cmdru.pingStp.sendCnt = atoi(strout);
fgets(strout, sizeof(strout), tmpfile);
stpResp->cmdru.pingStp.repliedCnt = atoi(strout);
fclose(tmpfile);
remove(TMP_FILE_PATH);
#else
if(exitcode ){
TerminateProcess(processHandle, exitcode);
}
tmpfile = fopen("temp\\RWL\\pingstats.txt", "r+");
if(tmpfile == NULL)
{
stpResp->status = STATUS_COMPLETE;
wfaEncodeTLV(WFA_TRAFFIC_STOP_PING_RESP_TLV, sizeof(dutCmdResponse_t), (BYTE *)stpResp, respBuf);
*respLen = WFA_TLV_HDR_LEN + sizeof(dutCmdResponse_t);
return FALSE;
}
GetStats(tmpfile, L"Sent =", &position, " ");
stpResp->cmdru.pingStp.sendCnt = position;
GetStats(tmpfile, L"Received =", &position, " ");
stpResp->cmdru.pingStp.repliedCnt = position;
fclose(tmpfile);
#endif
}
wfaEncodeTLV(WFA_TRAFFIC_STOP_PING_RESP_TLV, sizeof(dutCmdResponse_t), (BYTE *)stpResp, respBuf);
*respLen = WFA_TLV_HDR_LEN + sizeof(dutCmdResponse_t);
return TRUE;
}
/*
* wfaTGConfig: store the traffic profile setting that will be used to
* instruct traffic generation.
* input: cmd -- not used
* response: send success back to controller
* return: success or fail
* Note: the profile storage is a global space.
*/
int wfaTGConfig(int len, BYTE *caCmdBuf, int *respLen, BYTE *respBuf)
{
int ret = FALSE;
tgStream_t *myStream = NULL;
dutCmdResponse_t *confResp = &gGenericResp;
DPRINT_INFO(WFA_OUT, "slotCnt = %d\n", slotCnt);
/* if the stream table over maximum, reset it */
if(slotCnt == WFA_MAX_TRAFFIC_STREAMS)
slotCnt = 0;
if(slotCnt == 0)
{
memset(gStreams, 0, WFA_MAX_TRAFFIC_STREAMS*sizeof(tgStream_t));
}
DPRINT_INFO(WFA_OUT, "entering tcConfig ...\n");
myStream = &gStreams[slotCnt++];
memset(myStream, 0, sizeof(tgStream_t));
memcpy(&myStream->profile, caCmdBuf, len);
myStream->id = ++streamId; /* the id start from 1 */
myStream->tblidx = slotCnt-1;
DPRINT_INFO(WFA_OUT, "profile %i direction %i dest ip %s dport %i source %s sport %i rate %i duration %i size %i class %i delay %i\n", myStream->profile.profile, myStream->profile.direction, myStream->profile.dipaddr, myStream->profile.dport, myStream->profile.sipaddr, myStream->profile.sport, myStream->profile.rate, myStream->profile.duration, myStream->profile.pksize, myStream->profile.trafficClass, myStream->profile.startdelay);
confResp->status = STATUS_COMPLETE;
confResp->streamId = myStream->id;
wfaEncodeTLV(WFA_TRAFFIC_AGENT_CONFIG_RESP_TLV, sizeof(dutCmdResponse_t), (BYTE *)confResp, respBuf);
*respLen = WFA_TLV_HDR_LEN + sizeof(dutCmdResponse_t);
return ret;
}
/*
* wfaTGRecvStart: instruct traffic generator to start receiving
* based on a profile
* input: cmd -- not used
* response: inform controller for "running"
* return: success or failed
*
* In this function we create the UDP sockets for receiving the traffic and then
* set the global flag gtgRecv to indicate the receive thread to receive the incoming traffic.
* In the case of IPTV profile we multiple Create Events for multiple streams
*/
int wfaTGRecvStart(int len, BYTE *parms, int *respLen, BYTE *respBuf)
{
int status = STATUS_COMPLETE, i;
int numStreams = len/4;
int streamid, so;
tgProfile_t *theProfile;
tgStream_t *myStream;
DPRINT_INFO(WFA_OUT, "entering tgRecvStart %i\n", numStreams);
/*
* The function wfaSetProcPriority called here is to enhance the real-time
* performance for packet receiving. It is only for tuning and optional
* to implement
*/
//wfaSetProcPriority(60);
for(i=0; i<numStreams; i++) {
memcpy(&streamid, parms+(4*i), 4); /* changed from 2 to 4, bug reported by n.ojanen */
myStream = findStreamProfile(streamid);
if(myStream == NULL)
{
status = STATUS_INVALID;
return status;
}
theProfile = &myStream->profile;
if(theProfile == NULL)
{
status = STATUS_INVALID;
return status;
}
/* calculate the frame interval which is used to derive its jitter */
if(theProfile->rate != 0 && theProfile->rate < 5000)
myStream->fmInterval = 1000000/theProfile->rate; /* in ms */
else
myStream->fmInterval = 0;
if(theProfile->direction != DIRECT_RECV)
{
status = STATUS_INVALID;
return status;
}
memset(&myStream->stats, 0, sizeof(tgStats_t));
switch(theProfile->profile)
{
case PROF_FILE_TX:
status = STATUS_COMPLETE;
btRecvSockfd = wfaCreateUDPSock(theProfile->dipaddr, theProfile->dport);
if(btRecvSockfd > 0) {
gtgRecv = streamid;
#ifdef WIN32
/*Create receive event which is initially non-signalled and
* later reset the state of the signal when we call the command
* WfaRecvStop() */
if((g_hRecvEvent = CreateEvent(NULL, FALSE, TRUE, NULL)) == 0) {
DPRINT_INFO(WFA_OUT, "CreateEvent Failed = %d\r\n", GetLastError());
}
#endif
/*Creating a thread for receiving traffic in case of File_Transfer, Transac,Multicast */
wfaRecvThrCreate();
}
else
{
status = STATUS_ERROR;
wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_START_RESP_TLV, 4, (BYTE *)&status, respBuf);
*respLen = WFA_TLV_HDR_LEN + 4;
return TRUE;
}
break;
case PROF_FILE_TX_TCP:
gTCPsock = 1;
status = STATUS_COMPLETE;
gTcpRecvSockfd = wfaCreateTCPServSock(theProfile->dport);
if(gTcpRecvSockfd > 0) {
gtgRecv = streamid;
#ifdef WIN32
/*Create receive event which is initially non-signalled and
* later reset the state of the signal when we call the command
* WfaRecvStop() */
if((g_hRecvEvent = CreateEvent(NULL, FALSE, TRUE, NULL)) == 0) {
DPRINT_INFO(WFA_OUT, "CreateEvent Failed = %d\r\n", GetLastError());
}
#endif
/*Creating a thread for receiving traffic in case of File_Transfer, Transac,Multicast */
wfaRecvThrCreate();
}
else
{
status = STATUS_ERROR;
wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_START_RESP_TLV, 4, (BYTE *)&status, respBuf);
respLen = WFA_TLV_HDR_LEN + 4;
return TRUE;
}
break;
case PROF_MCAST:
status = STATUS_COMPLETE;
btRecvSockfd = wfaCreateUDPSock(theProfile->dipaddr, theProfile->dport);
DPRINT_INFO(WFA_OUT, "MCAST: RecvStart: btRecvSockfd = %d\r\n",btRecvSockfd);
if(btRecvSockfd > 0)
{
#ifdef WIN32
/*Create receive event which is initially non-signalled and
* later automatically reset the state of the signal
* when the receive thread exits. */
if((g_hRecvEvent = CreateEvent(NULL, FALSE, TRUE, NULL)) == 0){
DPRINT_INFO(WFA_OUT, "CreateEvent Failed = %d\r\n", GetLastError());
}
#endif
gtgRecv = streamid;
/*Creating a thread for receiving traffic in case of File_Transfer, Transac,Multicast */
wfaRecvThrCreate();
}
else
{
status = STATUS_ERROR;
wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_START_RESP_TLV, 4, (BYTE *)&status, respBuf);
*respLen = WFA_TLV_HDR_LEN + 4;
return TRUE;
}
DPRINT_INFO(WFA_OUT, "MCAST: RecvStart:before McastRecvOpt: btRecvSockfd = %d\r\n",btRecvSockfd);
/* set multicast socket option for receiver */
DPRINT_INFO(WFA_OUT, "MCAST: RecvStart: McastRecvOpt: theProfile->dipaddr = %s\r\n",theProfile->dipaddr);
so = wfaSetSockMcastRecvOpt(btRecvSockfd, theProfile->dipaddr);
if(so < 0)
{
DPRINT_INFO(WFA_OUT, "MCAST: RecvStart: McastRecvOpt: so<0: btRecvSockfd = %d\r\n",btRecvSockfd);
asd_closeSocket(btRecvSockfd);
gtgRecv = 0;
btRecvSockfd = -1;
status = STATUS_ERROR;
wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_START_RESP_TLV, 4, (BYTE *)&status, respBuf);
*respLen = WFA_TLV_HDR_LEN + 4;
return TRUE;
}
break;
case PROF_IPTV:
status = STATUS_COMPLETE;
/*Create multiple streams and get the socket values in the array*/
tgSockfds[myStream->tblidx] = wfaCreateUDPSock(theProfile->dipaddr, theProfile->dport);
DPRINT_INFO(WFA_OUT, "sock fd prof iptv = %d , streamid = %d\n", tgSockfds[myStream->tblidx], streamid);
if(tgSockfds[myStream->tblidx] > 0){
#ifdef WIN32
/* Create multiple event for different recv streams and get
* the values in the array of recv handles, Which will be later used in
* WfaRecvStop() to signal the recv thread to stop the recv process. */
if((g_recvEvent[myStream->tblidx] = CreateEvent(NULL, FALSE, TRUE, NULL)) == 0){
DPRINT_INFO(WFA_OUT, "CreateEvent Failed = %d\r\n", GetLastError());
}
DPRINT_INFO(WFA_OUT, "recvstart g_recvEvent[myStream->tblidx] = %i\r\n", g_recvEvent[myStream->tblidx]);
#endif
gtgRecv = streamid;
/*Create a thread to receive IPTV traffic. */
wfaIPTVRecvThrCreate(myStream->tblidx);
}
else
{
status = STATUS_ERROR;
wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_START_RESP_TLV, 4, (BYTE *)&status, respBuf);
*respLen = WFA_TLV_HDR_LEN + 4;
return TRUE;
}
break;
case PROF_TRANSC:
case PROF_START_SYNC:
case PROF_CALI_RTD: /* Calibrate roundtrip delay */
status = STATUS_COMPLETE;
btRecvSockfd = wfaCreateUDPSock(theProfile->sipaddr, theProfile->sport);
totalTranPkts = 0xFFFFFFF0;
sentTranPkts = 0;
if(btRecvSockfd > 0)
{
gtgTransac = streamid;
gtgRecv = streamid;
#ifdef WIN32
if((g_hRecvEvent = CreateEvent(NULL, FALSE, TRUE, NULL)) == 0){
DPRINT_INFO(WFA_OUT, "CreateEvent Failed = %d\r\n", GetLastError());
}
#endif
/*Creating a thread for receiving traffic in case of File_Transfer, Transac,Multicast */
wfaRecvThrCreate();
}
else
{
status = STATUS_ERROR;
wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_START_RESP_TLV, 4, (BYTE *)&status, respBuf);
*respLen = WFA_TLV_HDR_LEN + 4;
return TRUE;
}
break;
case PROF_TRANSC_TCP:
gTCPsock = 1;
status = STATUS_COMPLETE;
gTcpRecvSockfd = wfaCreateTCPServSock(theProfile->dport);
if(gTcpRecvSockfd > 0)
{
gtgTransac = streamid;
gtgRecv = streamid;
#ifdef WIN32
if((g_hRecvEvent = CreateEvent(NULL, FALSE, TRUE, NULL)) == 0){
DPRINT_INFO(WFA_OUT, "CreateEvent Failed = %d\r\n", GetLastError());
}
#endif
/*Creating a thread for receiving traffic in case of File_Transfer, Transac,Multicast */
wfaRecvThrCreate();
}
else
{
status = STATUS_ERROR;
wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_START_RESP_TLV, 4, (BYTE *)&status, respBuf);
*respLen = WFA_TLV_HDR_LEN + 4;
return TRUE;
}
break;
case PROF_UAPSD:
#ifdef WFA_WMM_EXT
#ifdef WFA_WMM_PS_EXT
status = STATUS_COMPLETE;
psSockfd = wfaCreateUDPSock(theProfile->dipaddr, WFA_WMMPS_UDP_PORT);
wmmps_info.sta_state = 0;
wmmps_info.wait_state = WFA_WAIT_STAUT_00;
#ifdef WIN32
init_wmmps_thr();
if((g_hRecvEvent = CreateEvent(NULL, FALSE, TRUE, NULL)) == 0){
DPRINT_INFO(WFA_OUT, "CreateEvent Failed = %d\r\n", GetLastError());
}
#endif
memset(&wmmps_info.psToAddr, 0, sizeof(wmmps_info.psToAddr));
wmmps_info.psToAddr.sin_family = AF_INET;
wmmps_info.psToAddr.sin_addr.s_addr = inet_addr(theProfile->sipaddr);
wmmps_info.psToAddr.sin_port = htons(theProfile->sport);
wmmps_info.reset = 0;
wmm_thr[usedThread].thr_flag = streamid;
wmmps_info.streamid = streamid;
#ifndef WIN32
pthread_mutex_lock(&wmm_thr[usedThread].thr_flag_mutex);
pthread_cond_signal(&wmm_thr[usedThread].thr_flag_cond);
gtgWmmPS = streamid;;
pthread_mutex_unlock(&wmm_thr[usedThread].thr_flag_mutex);
usedThread++;
#else
SetEvent(thr_flag_cond);
gtgWmmPS = streamid;
#endif /* WIN32 */
gtimeOut = MINISECONDS/10; /* in msec */
gRegSec = 0;
/* Create the receiver thread */
wfaRecvThrCreate();
#endif /* WFA_WMM_PS_EXT */
#endif /* WFA_WMM_EXT */
break;
}
}
/* encode a TLV for response for "complete/error ..." */
wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_START_RESP_TLV, 4,
(BYTE *)&status, respBuf);
*respLen = WFA_TLV_HDR_LEN + 4;
return TRUE;
}
/*
* tgRecvStop: instruct traffic generator to stop receiving based on a profile
* input: cmd -- not used
* response: inform controller for "complete"
* return: success or failed
*
* In this function we will reset the gtgRecv flag, close the UDP sockets opened in the
* receive start to stop receiving the traffic from TG. We also kill the thread that was created
* in receive start*/
int wfaTGRecvStop(int len, BYTE *parms, int *respLen, BYTE *respBuf)
{
int status = STATUS_COMPLETE, i, j;
int numStreams = len/4;
int streamid;
tgProfile_t *theProfile;
tgStream_t *myStream=NULL;
dutCmdResponse_t statResp;
BYTE dutRspBuf[WFA_BUFF_1K];
int id_cnt = 0;
FILE *e2eoutp = NULL;
#ifndef WIN32
struct timeval currtime;
#else
SYSTEMTIME currtime;
#endif
DPRINT_INFO(WFA_OUT, "entering tgRecvStop\n");
memset(dutRspBuf, 0, WFA_BUFF_1K);
for(i=0; i<numStreams; i++)
{
memcpy(&streamid, parms+(4*i), 4);
myStream = findStreamProfile(streamid);
if(myStream == NULL)
{
status = STATUS_INVALID;
wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_STOP_RESP_TLV, 4, (BYTE *)&status, respBuf);
*respLen = WFA_TLV_HDR_LEN + 4;
return TRUE;
}
theProfile = &myStream->profile;
if(theProfile == NULL)
{
status = STATUS_INVALID;
wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_STOP_RESP_TLV, 4, (BYTE *)&status, respBuf);
*respLen = WFA_TLV_HDR_LEN + 4;
return TRUE;
}
if(theProfile->direction != DIRECT_RECV)
{
status = STATUS_INVALID;
wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_STOP_RESP_TLV, 4, (BYTE *)&status, respBuf);
*respLen = WFA_TLV_HDR_LEN + 4;
return TRUE;
}
/* reset its flags , close sockets */
gtgRecv = 0;
switch(theProfile->profile)
{
case PROF_FILE_TX:
case PROF_FILE_TX_TCP:
#ifdef WIN32
/*Set the recv event and signal the recv thread function to stop
* Receiving the File transfer Traffic, also close the handle of the event*/
if(SetEvent(g_hRecvEvent) == 0) {
DPRINT_INFO(WFA_OUT, "ResetEvent failure %d \n", GetLastError());
}
while ((WaitForSingleObject(g_RecvhThread, INFINITE) != WAIT_OBJECT_0));
if(g_hRecvEvent != NULL)
CloseHandle(g_hRecvEvent);
#else
/* Waiting for signal from wfaRecvStart once the receive
* operation is complete in order to close the socket
*/
sem_wait(&sem_gtgrecv);
#endif
if(gTcpRecvSockfd != -1) {
gTCPsock = 0;
asd_closeSocket(gTcpRecvSockfd);
gTcpRecvSockfd = -1;
}
if(btRecvSockfd != -1) {
asd_closeSocket(btRecvSockfd);
btRecvSockfd = -1;
}
break;
case PROF_MCAST:
#ifdef WIN32
/* Set the recv event and signal the recv thread function to stop
* Receiving the Multicast Traffic, also close the handle of the event*/
if(SetEvent(g_hRecvEvent) == 0) {
DPRINT_INFO(WFA_OUT, "ResetEvent failure %d \n", GetLastError());
}
while ((WaitForSingleObject(g_RecvhThread, INFINITE) != WAIT_OBJECT_0));
if(g_hRecvEvent != NULL)
CloseHandle(g_hRecvEvent);
#else
/* Waiting for signal from wfaRecvStart once the receive
* operation is complete in order to close the socket
*/
sem_wait(&sem_gtgrecv);
#endif
if(btRecvSockfd != -1){
asd_closeSocket(btRecvSockfd);
btRecvSockfd = -1;
}
break;
case PROF_IPTV:
IPTVprof = 0;
#ifdef WIN32
/* Set the recv event and signal the recv thread function to stop
* Receiving the IPTV traffic in the case of multiple streams,
* also close the handles of the multiple events*/
if(SetEvent(g_recvEvent[myStream->tblidx]) == 0) {
DPRINT_INFO(WFA_OUT, "ResetEvent failure %d \n", GetLastError());
}
while ((WaitForSingleObject(g_IPTVRecvhThread[myStream->tblidx], INFINITE) != WAIT_OBJECT_0));
if(g_recvEvent[myStream->tblidx] != NULL)
CloseHandle(g_recvEvent[myStream->tblidx]);
#else
/* Waiting for signal from wfaIPTVRecvStart once the receive
* operation is complete in order to close the socket
*/
sem_wait(&sem_iptv_gtgrecv[myStream->tblidx]);
#endif
if(tgSockfds[myStream->tblidx] != -1){
asd_closeSocket(tgSockfds[myStream->tblidx]);
tgSockfds[myStream->tblidx] = -1;
}
/* the following to report the result. There will be a
* solution to send it back to TM
*/
//#endif
break;
case PROF_TRANSC:
case PROF_TRANSC_TCP:
case PROF_START_SYNC:
case PROF_CALI_RTD: /* Calibrate roundtrip delay */
gtgTransac = 0;
#ifdef WIN32
/* Set the recv event and signal the recv thread function to stop
* Receiving the Transaction Traffic, also close the handle of the event*/
if(SetEvent(g_hRecvEvent) == 0){
DPRINT_INFO(WFA_OUT, "ResetEvent failure %d \n", GetLastError());
}
while ((WaitForSingleObject(g_RecvhThread, INFINITE) != WAIT_OBJECT_0));
if(g_hRecvEvent != NULL)
CloseHandle(g_hRecvEvent);
#else
/* Waiting for signal from wfaRecvStart once the receive
* operation is complete in order to close the socket
*/
sem_wait(&sem_gtgrecv);
#endif
if(gTcpRecvSockfd != -1) {
gTCPsock = 0;
asd_closeSocket(gTcpRecvSockfd);
gTcpRecvSockfd = -1;
}
if(btRecvSockfd != -1){
asd_closeSocket(btRecvSockfd);
btRecvSockfd = -1;
}
break;
case PROF_UAPSD:
#ifdef WFA_WMM_EXT
#ifdef WFA_WMM_PS_EXT
gtgWmmPS = 0;
gtgPsPktRecvd = 0;
if(psSockfd != -1)
{
asd_closeSocket(psSockfd);
psSockfd = -1;
}
memset(&wmmps_info, 0, sizeof(wfaWmmPS_t));
wfaSetDUTPwrMgmt(PS_OFF);
#endif /* WFA_WMM_PS_EXT */
#endif /* WFA_WMM_EXT */
break;
}
/* encode a TLV for response for "complete/error ..." */
statResp.status = STATUS_COMPLETE;
statResp.streamId = streamid;
DPRINT_INFO(WFA_OUT, "stream Id %i rx %i total %i\n", streamid, myStream->stats.rxFrames, myStream->stats.rxPayloadBytes);
memcpy(&statResp.cmdru.stats, &myStream->stats, sizeof(tgStats_t));
memcpy((dutRspBuf + i * sizeof(dutCmdResponse_t)), (BYTE *)&statResp, sizeof(dutCmdResponse_t));
id_cnt++;
memset(myStream, 0, sizeof(tgStream_t));
}
wfaEncodeTLV(WFA_TRAFFIC_AGENT_RECV_STOP_RESP_TLV, (WORD)(id_cnt * sizeof(dutCmdResponse_t)), dutRspBuf, respBuf);
/* done here */
*respLen = WFA_TLV_HDR_LEN + numStreams * sizeof(dutCmdResponse_t);
return TRUE;
}
/*
* wfaTGSendStart: instruct traffic generator to start sending based on a profile
* input: cmd -- not used
* response: inform controller for "running"
* return: success or failed
*
* In this function we will create the UDP sockets to send the traffic
* and set the global flag gtgSend, increment usedThread for each stream
* also set the socket option and type ofservice bits (TOS) in
* the case of Multicast profiles . We also
* Call the thread Win32_tmout_stop_send() which sleeps for the duration specified in the profile
* and then stops the sending of the traffic by resetting the runloop, decrement usedThread .
*/
int wfaTGSendStart(int len, BYTE *parms, int *respLen, BYTE *respBuf)
{
int i=0, streamid=0, so;
int numStreams = len/4;
tgProfile_t *theProfile;
tgStream_t *myStream = NULL;
dutCmdResponse_t sendResp;
#ifdef WIN32
DWORD errnum;
#endif
#ifdef WFA_DUT_SYNC
#ifndef WIN32
pthread_attr_t ptAttr;
int ptPolicy;
struct sched_param ptSchedParam;
struct timeval btime;
#else
SYSTEMTIME btime;
#endif
#endif
dutCmdResponse_t staSendResp;
#ifdef WIN32
/*Create an event which will wait for the traffic streams to complete the send operation */
if((send_event = CreateEvent(NULL, FALSE, TRUE, NULL)) == 0){
DPRINT_INFO(WFA_OUT, "CreateEvent Failed = %d\r\n", GetLastError());
}
#else
gnumStreams = numStreams;
#endif
DPRINT_INFO(WFA_OUT, "Entering tgSendStart for %i streams ...\n", numStreams);
for(i=0; i<numStreams; i++)
{
memcpy(&streamid, parms+(4*i), 4);
myStream = findStreamProfile(streamid);
if(myStream == NULL)
{
staSendResp.status = STATUS_INVALID;
wfaEncodeTLV(WFA_TRAFFIC_AGENT_SEND_RESP_TLV, 4, (BYTE *)&staSendResp, respBuf);
*respLen = WFA_TLV_HDR_LEN + 4;
return TRUE;
}
theProfile = &myStream->profile;
if(theProfile == NULL)
{
staSendResp.status = STATUS_INVALID;
wfaEncodeTLV(WFA_TRAFFIC_AGENT_SEND_RESP_TLV, 4, (BYTE *)&staSendResp, respBuf);
*respLen = WFA_TLV_HDR_LEN + 4;
return TRUE;
}
if(theProfile->direction != DIRECT_SEND)
{
staSendResp.status = STATUS_INVALID;
wfaEncodeTLV(WFA_TRAFFIC_AGENT_SEND_RESP_TLV, 4, (BYTE *)&staSendResp, respBuf);
*respLen = WFA_TLV_HDR_LEN + 4;
return TRUE;
}
/*
* need to reset the stats
*/
memset(&myStream->stats, 0, sizeof(tgStats_t));
/* Here increment the usedThread for every time we wish to send a stream
* so as to maintain the count of streams that are running at the same time.
*/
switch(theProfile->profile)
{
case PROF_FILE_TX:
btSockfd = wfaCreateUDPSock(theProfile->sipaddr, theProfile->sport);
if((btSockfd=wfaConnectUDPPeer(btSockfd, theProfile->dipaddr, theProfile->dport)) > 0)
{
gtgSend = streamid;
usedThread++;
#ifndef WIN32
SendFile();
#else
g_TGSndThr[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SendFile, (LPVOID)streamid, 0, &dwIPTVThread);
if(g_TGSndThr[i] == NULL){
errnum = GetLastError();
DPRINT_INFO(WFA_OUT, "Could not create the thread1\n");
return TRUE;
}
#endif
}
else
{
gtgSend = 0;
staSendResp.status = STATUS_ERROR;
wfaEncodeTLV(WFA_TRAFFIC_AGENT_SEND_RESP_TLV, 4, (BYTE *)&staSendResp, respBuf);
*respLen = WFA_TLV_HDR_LEN + 4;
return TRUE;
}
break;
case PROF_FILE_TX_TCP:
if((btSockfd=wfaConnectTCPPeer(theProfile->sport, theProfile->dipaddr, theProfile->dport)) > 0)
{
gtgSend = streamid;
usedThread++;
#ifndef WIN32
SendFile();
#else
g_TGSndThr[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SendFile, (LPVOID)streamid, 0, &dwIPTVThread);
if(g_TGSndThr[i] == NULL){
errnum = GetLastError();
DPRINT_INFO(WFA_OUT, "Could not create the thread1\n");
return TRUE;
}
#endif
}
else
{
gtgSend = 0;
staSendResp.status = STATUS_ERROR;
wfaEncodeTLV(WFA_TRAFFIC_AGENT_SEND_RESP_TLV, 4, (BYTE *)&staSendResp, respBuf);
*respLen = WFA_TLV_HDR_LEN + 4;
return TRUE;
}
break;
case PROF_MCAST:
btSockfd = wfaCreateUDPSock(theProfile->sipaddr, theProfile->sport);
if(btSockfd > 0)
{
gtgSend = streamid;
usedThread ++;
}
else
{
staSendResp.status = STATUS_ERROR;
wfaEncodeTLV(WFA_TRAFFIC_AGENT_SEND_RESP_TLV, 4, (BYTE *)&staSendResp, respBuf);
*respLen = WFA_TLV_HDR_LEN + 4;
return TRUE;
}
so = wfaSetSockMcastSendOpt(btSockfd);
if (so < 0)
{
#ifdef WIN32
DPRINT_INFO(WFA_OUT, "setsockopt for mcast: %d\n",WSAGetLastError());
#endif
gtgSend = 0;
asd_closeSocket(btSockfd);
btSockfd = -1;
staSendResp.status = STATUS_ERROR;
wfaEncodeTLV(WFA_TRAFFIC_AGENT_SEND_RESP_TLV, 4, (BYTE *)&staSendResp, respBuf);
*respLen = WFA_TLV_HDR_LEN + 4;
return TRUE;
}
#ifndef WIN32
SendFile();
#else
g_TGSndThr[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SendFile, (LPVOID)gtgSend, 0, &dwIPTVThread);
if(g_TGSndThr[i] == NULL){
errnum = GetLastError();
DPRINT_INFO(WFA_OUT, "Could not create the thread1\n");
return TRUE;
}
#endif
break;
case PROF_IPTV:
IPTVprof = 1;
gtgSend = streamid;
usedThread++;
#ifndef WIN32
/*
* singal the thread to Sending WMM traffic
*/
wmm_thr[usedThread].thr_flag = streamid;
pthread_mutex_lock(&wmm_thr[usedThread].thr_flag_mutex);
pthread_cond_signal(&wmm_thr[usedThread].thr_flag_cond);
pthread_mutex_unlock(&wmm_thr[usedThread].thr_flag_mutex);
#else
/* Create thread to send the IPTV stream, and store the handle of the thread in the array of the handles.
* New thread is created everytime in the case of multiple streams, to send the traffic simultaneously.
*/
g_TGSndThr[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SendIPTVFile, (LPVOID)streamid, 0, &dwIPTVThread);
DPRINT_INFO(WFA_OUT, "Thread create Handle %x\n", g_TGSndThr[i]);
if(g_TGSndThr[i] == NULL){
errnum = GetLastError();
DPRINT_INFO(WFA_OUT, "Could not create the thread1\n");
return TRUE;
}
#endif
DPRINT_INFO(WFA_OUT, "wfa_wmm_thread: myProfile->startdelay %i\n", theProfile->startdelay);
/* if delay is too long, it must be something wrong */
DPRINT_INFO(WFA_OUT, "sleep for %d\n", theProfile->startdelay);
#ifdef WFA_DUT_SYNC
//reset clock by estimate drift
gettimeofday(&btime, NULL);
DPRINT_INFO(WFA_OUT, "btime.tv_sec %u, btime.tv_usec %u last sync time %f\n", (unsigned int) btime.tv_sec, (unsigned int) btime.tv_usec, gtgStartSyncTime.dut_time);
double bdftime = wfa_timeval2double(&btime) - (gtgStartSyncTime.dut_time);
traf_start_drift = clock_drift_ps * bdftime;
DPRINT_INFO(WFA_OUT, "time gap %lf traf_start_drift %i\n", bdftime, traf_start_drift);
if(abs(traf_start_drift) > 50)
{
DPRINT_INFO(WFA_OUT, "traf_start_drift %i\n", traf_start_drift);
btime.tv_usec += traf_start_drift;
if(btime.tv_usec < 0)
{
btime.tv_sec -= 1;
btime.tv_usec +=1000000;
}
else if(btime.tv_usec >=1000000)
{
btime.tv_sec +=1;
btime.tv_usec -= 1000000;
}
// clock get reset
settimeofday(&btime, NULL);
// ajust the sync time for the next run.
gtgStartSyncTime.dut_time = wfa_timeval2double(&btime);
clock_drift_ppk = (double) clock_drift_ps / (double) theProfile->rate;
}
#endif
break;
case PROF_TRANSC:
{
btSockfd = wfaCreateUDPSock(theProfile->sipaddr, theProfile->sport);
if((btSockfd = wfaConnectUDPPeer(btSockfd, theProfile->dipaddr, theProfile->dport)) > 0)
{
gtgTransac = streamid;
gtgSend = streamid;
totalTranPkts = theProfile->rate * theProfile->duration;
sentTranPkts = 0;
/*
* the framerate here is used to derive the timeout
* value for waiting transaction echo responses.
*/
if(theProfile->rate == 0){
gtimeOut = MINISECONDS; /* in msec */
} else {
gtimeOut = MINISECONDS/theProfile->rate; /* in msec */
}
gRegSec = 0;
usedThread++;
}
else
{
staSendResp.status = STATUS_ERROR;
wfaEncodeTLV(WFA_TRAFFIC_AGENT_SEND_RESP_TLV, 4, (BYTE *)&staSendResp, respBuf);
*respLen = WFA_TLV_HDR_LEN + 4;
return TRUE;
}
/* set duration for the test */
#ifndef WIN32
signal(SIGALRM, tmout_stop_send);
alarm(theProfile->duration);
#else
if(hThread1 != NULL){
CloseHandle(hThread1);
}
hThread1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) Win32_tmout_stop_send, (LPVOID)(theProfile->duration *1000), 0, &dwGenericThread1);
if(hThread1 == NULL){
errnum = GetLastError();
DPRINT_INFO(WFA_OUT, "Could not create the thread1\n");
return TRUE;
}
#endif
#ifndef WIN32
SendFile();
#else
g_TGSndThr[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SendFile, (LPVOID)gtgSend, 0, &dwIPTVThread);
if(g_TGSndThr[i] == NULL){
errnum = GetLastError();
DPRINT_INFO(WFA_OUT, "Could not create the thread1\n");
return TRUE;
}
#endif
}
break;
case PROF_TRANSC_TCP:
if((btSockfd=wfaConnectTCPPeer(theProfile->dport, theProfile->dipaddr, theProfile->dport)) > 0)
{
gtgTransac = streamid;
gtgSend = streamid;
totalTranPkts = theProfile->rate * theProfile->duration;
sentTranPkts = 0;
/*
* the framerate here is used to derive the timeout
* value for waiting transaction echo responses.
*/
if(theProfile->rate == 0){
gtimeOut = MINISECONDS; /* in msec */
} else {
gtimeOut = MINISECONDS/theProfile->rate; /* in msec */
}
gRegSec = 0;
usedThread++;
}
else
{
staSendResp.status = STATUS_ERROR;
wfaEncodeTLV(WFA_TRAFFIC_AGENT_SEND_RESP_TLV, 4, (BYTE *)&staSendResp, respBuf);
*respLen = WFA_TLV_HDR_LEN + 4;
return TRUE;
}
/* set duration for the test */
#ifndef WIN32
signal(SIGALRM, tmout_stop_send);
alarm(theProfile->duration);
#else
if(hThread1 != NULL){
CloseHandle(hThread1);
}
hThread1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) Win32_tmout_stop_send, (LPVOID)(theProfile->duration *1000), 0, &dwGenericThread1);
if(hThread1 == NULL){
errnum = GetLastError();
DPRINT_INFO(WFA_OUT, "Could not create the thread1\n");
return TRUE;
}
#endif
#ifndef WIN32
SendFile();
#else
g_TGSndThr[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) SendFile, (LPVOID)gtgSend, 0, &dwIPTVThread);
if(g_TGSndThr[i] == NULL){
errnum = GetLastError();
DPRINT_INFO(WFA_OUT, "Could not create the thread1\n");
return TRUE;
}
#endif
break;
#ifdef WFA_WMM_EXT
case PROF_START_SYNC:
case PROF_CALI_RTD:
{
DPRINT_INFO(WFA_OUT, "profile port %i\n", theProfile->sport);
btSockfd = wfaCreateUDPSock(theProfile->sipaddr, theProfile->sport);
if((btSockfd = wfaConnectUDPPeer(btSockfd, theProfile->dipaddr, theProfile->dport)) > 0)
{
gtgTransac = streamid;
gtgSend = streamid;
totalTranPkts = theProfile->rate * theProfile->duration;
sentTranPkts = 0;
if(theProfile->profile == PROF_START_SYNC)
gtgStartSync = streamid;
else if(theProfile->profile == PROF_CALI_RTD)
gtgFinishSync = streamid;
/*
* the framerate here is used to derive the timeout
* value for waiting transaction echo responses.
*/
gtimeOut = MINISECONDS/theProfile->rate; /* in msec */
}
else
{
DPRINT_INFO(WFA_OUT, "connection failed\n");
}
/* set duration for the test */
#ifndef WIN32
signal(SIGALRM, tmout_stop_send);
alarm(theProfile->duration+1);
#else
if(hThread2 != NULL){
CloseHandle(hThread2);
}
hThread2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) Win32_tmout_stop_send, (LPVOID)((theProfile->duration+1) *1000), 0, &dwGenericThread2);
if(hThread2 == NULL){
errnum = GetLastError();
DPRINT_INFO(WFA_OUT, "Could not create the thread1\n");
return TRUE;
}
#endif
}
break;
#endif
default :
DPRINT_INFO(WFA_OUT, "No profile match findStreams problem\n");
}
}
#ifdef WIN32
/* Wait fo the event to be signalled from the timeout function, after all
* the threads have finished sending the traffic.
*
*/
Sleep(theProfile->duration*1000);
if(SetEvent(send_event)== 0 ){
DPRINT_INFO(WFA_OUT, "SetEvent failure %d \n", GetLastError());
}
for(i = 0; i < numStreams; i++)
while ((WaitForSingleObject(g_TGSndThr[i], INFINITE) != WAIT_OBJECT_0));
if(IPTVprof == 1) {
memset(Send_dutResp, 0, WFA_BUFF_512);
wfaSentStatsResp(Send_dutResp);
}
if(send_event != NULL) {
CloseHandle(send_event);
send_event = NULL;
}
#else
sem_wait(&sem_wmm_resp);
if(IPTVprof) {
sem_wait(&sem_wmm);
memset(Send_dutResp, 0, WFA_BUFF_512);
wfaSentStatsResp(Send_dutResp);
}
#endif
/* update the response */
if(! IPTVprof) {
memset(Send_dutResp, 0, WFA_BUFF_512);
sendResp.status = STATUS_COMPLETE;
sendResp.streamId = myStream->id;
memcpy(&sendResp.cmdru.stats, &myStream->stats, sizeof(tgStats_t));
memcpy(Send_dutResp , (BYTE*)&sendResp, sizeof(dutCmdResponse_t));
}
wfaEncodeTLV(WFA_TRAFFIC_AGENT_SEND_RESP_TLV, (WORD)(numStreams* sizeof(dutCmdResponse_t)),Send_dutResp, (BYTE*)respBuf);
/* done here */
*respLen = WFA_TLV_HDR_LEN + numStreams * sizeof(dutCmdResponse_t);
DPRINT_INFO(WFA_OUT, "Leaving send start Check btsockfd = %d\n", btSockfd);
return TRUE;
}
int wfaTGReset(int len, BYTE *parms, int *respLen, BYTE *respBuf)
{
dutCmdResponse_t *resetResp = &gGenericResp;
gtgRecv = 0;
gtgSend = 0;
/* need to reset all traffic socket fds */
if(btSockfd != -1 ) {
asd_closeSocket(btSockfd);
btSockfd = -1;
}
if (btRecvSockfd != -1) {
asd_closeSocket(btRecvSockfd);
btRecvSockfd = -1;
}
/* reset the timer alarm if it was armed */
#ifndef WIN32
alarm(0);
#endif
/* just reset the flags for the command */
usedThread = 0;
gtgTransac = 0;
totalTranPkts = 0;
gtimeOut = 0;
gRegSec = 1; /* mewly added */
IPTVprof = 0;
runLoop = 0;
gTransactrunLoop = 0;
#ifdef WFA_WMM_EXT
e2eCnt = 0;
/* changed now */
memset(e2eStats, 0, 6000*sizeof(tgE2EStats_t));
/* Start : Modified as per BRCM 1.3 ASD */
#ifdef WFA_WMM_PS_EXT
gtgWmmPS = 0;
gtgPsPktRecvd = 0;
if(psSockfd != -1)
{
asd_closeSocket(psSockfd);
psSockfd = -1;
}
memset(&wmmps_info, 0, sizeof(wfaWmmPS_t));
wfaSetDUTPwrMgmt(PS_OFF);
#endif /* WFA_WMM_EXT */
/* End : Modified as per BRCM 1.3 ASD */
#endif
/* Also need to clean up WMM streams NOT DONE YET!*/
slotCnt = 0; /* reset stream profile container */
/* encode a TLV for response for "complete ..." */
resetResp->status = STATUS_COMPLETE;
wfaEncodeTLV(WFA_TRAFFIC_AGENT_RESET_RESP_TLV, 4,
(BYTE *)resetResp, respBuf);
*respLen = WFA_TLV_HDR_LEN + 4;
return TRUE;
}
/*
* calculate the sleep time for different frame rate
* It should be done according the device
* This is just one way to adjust the packet delivery speed. If you find
* you device does not meet the test requirements, you MUST re-adjust
* the method.
*/
/* The HZ value could be found in the build header file */
/* 100 -> 10ms, 1000 -> 1ms , etc */
#define WFA_KERNEL_MIN_TIMER_RES 100 /* HZ Value for 10 ms */
void wfaTxSleepTime(int profile, int rate, int *sleepTime, int *throttledRate)
{
*sleepTime=0; /* in microseconds */
/* calculate the sleep time based on frame rate */
/*
* Framerate is still required for Multicast traffic
* Sleep and hold for a timeout.
*
* For WMM traffic, the framerate must also need for VO and VI.
* the framerate 500, OS may not handle it precisely.
*/
switch(profile)
{
/*
* Vendor must find ways to better adjust the speed for their own device
*/
case PROF_MCAST:
case PROF_IPTV:
case PROF_FILE_TX:
case PROF_FILE_TX_TCP:
case PROF_TRANSC:
case PROF_TRANSC_TCP:
if(rate >=100 || rate == 0)
{
/*
* this sleepTime indeed is now being used for time period
* to send packets in the throttled Rate.
* The idea here is that in each fixed 50 minisecond period,
* The device will send rate/20 (rate = packets / second),
* then go sleep for rest of time.
*/
#ifndef WIN32
*sleepTime = 50000; /* fixed 50 miniseconds */
#else
*sleepTime = 50; /* CHANGED FROM 50000 TO 50 fixed 50 miniseconds */
#endif
*throttledRate = (rate?rate:3000)/20;
DPRINT_INFO(WFA_OUT, "Sleep time %i, throttledRate %i\n", *sleepTime, *throttledRate);
}
else if (rate > 0 && rate <= 50) /* typically for voice */
{
*throttledRate = 1;
#ifndef WIN32
*sleepTime = 1000*1000/rate;
#else
*sleepTime = 1000/rate;
#endif
}
break;
default:
DPRINT_ERR(WFA_ERR, "Incorrect profile\n");
}
}
#ifndef WIN32
#define WFA_TIME_DIFF(before, after, rtime, dtime) \
dtime = rtime + (after.tv_sec*1000000 + after.tv_usec) - (before.tv_sec*1000000 + before.tv_usec);
#else
#define WFA_TIME_DIFF(before, after, rtime, dtime) \
dtime = rtime + (after.wSecond +after.wMilliseconds ) - (before.wSecond + before.wMilliseconds );
#endif
void buzz_time(int delay)
{
#ifndef WIN32
struct timeval now, stop;
#else
SYSTEMTIME now, stop;
#endif
int diff;
int remain_time = 0;
#ifndef WIN32
gettimeofday(&stop, 0);
stop.tv_usec += delay;
if(stop.tv_usec > 1000000)
{
stop.tv_usec -=1000000;
stop.tv_sec +=1;
}
#else
GetSystemTime(&stop);
stop.wMilliseconds +=delay;
if(stop.wMilliseconds > 1000)
{
stop.wMilliseconds -=1000;
stop.wSecond+=1;
}
#endif
do
{
#ifndef WIN32
gettimeofday(&now, 0);
WFA_TIME_DIFF(now, stop, remain_time, diff);
#else
GetSystemTime(&now);
WFA_TIME_DIFF(stop, now, remain_time, diff);
#endif
} while(diff>0);
}
/**************************************************/
/* the actually functions to send/receive packets */
/**************************************************/
/* This is going to be a blocking SEND till it finishes */
int wfaSendLongFile(int mySockfd, int streamid, BYTE *aRespBuf, int *aRespLen)
{
tgProfile_t *theProf = NULL;
tgStream_t *myStream = NULL;
struct sockaddr_in toAddr;
char *packBuf;
int packLen;
int bytesSent;
dutCmdResponse_t sendResp;
int sleepTime = 0;
int throttledRate = 0;
int errsv;
#ifndef WIN32
struct timeval before, after, stime;
#else
SYSTEMTIME before, after, stime;
#endif
int difftime = 0;
int counter = 0;
int throttled_est_cost;
int act_sleep_time;
DPRINT_INFO(WFA_OUT, "Entering sendLongFile %i\n", streamid);
/* find the profile */
myStream = findStreamProfile(streamid);
if(myStream == NULL)
{
return FALSE;
}
theProf = &myStream->profile;
if(theProf == NULL)
{
return FALSE;
}
packLen = theProf->pksize;
/* allocate a buf */
packBuf = (char *)malloc(packLen);
memset(packBuf, 1, packLen);
/* fill in the header */
strncpy(packBuf, "1345678", sizeof(tgHeader_t));
/* initialize the destination address */
memset(&toAddr, 0, sizeof(toAddr));
toAddr.sin_family = AF_INET;
toAddr.sin_addr.s_addr = inet_addr(theProf->dipaddr);
toAddr.sin_port = htons(theProf->dport);
/* if a frame rate and duration are defined, then we know
* interval for each packet and how many packets it needs to
* send.
*/
if(theProf->duration != 0)
{
DPRINT_INFO(WFA_OUT, "duration %i\n", theProf->duration);
/*
* use this to decide periodical interval sleep time and frames to send
* int the each interval.
* Each device should adopt a own algorithm for better performance
*/
wfaTxSleepTime(theProf->profile, theProf->rate, &sleepTime, &throttledRate);
/*
* alright, we need to raise the priority level of the process
* to improve the real-time performance of packet sending.
* Since this is for tuning purpose, it is optional implementation.
*/
//wfaSetProcPriority(60);
//interval = 1*1000000/theProf->rate ; // in usec;
// Here assumes it takes 20 usec to send a packet
throttled_est_cost = throttledRate * 20; // MUST estimate the cost per ppk
act_sleep_time = sleepTime - adj_latency - throttled_est_cost;
if (act_sleep_time <= 0)
act_sleep_time = sleepTime;
DPRINT_INFO(WFA_OUT, "sleep time %i act_sleep_time %i\n", sleepTime, act_sleep_time);
runLoop=1;
#ifndef WIN32
while (runLoop)
#else
while ((WaitForSingleObject(send_event,0) != WAIT_OBJECT_0))
#endif
{
counter++;
/* fill in the counter */
int2BuffBigEndian(counter, &((tgHeader_t *)packBuf)->hdr[8]);
/*
* the following code is only used to slow down
* over fast traffic flooding the buffer and cause
* packet drop or the other end not able to receive due to
* some limitations, purely for experiment purpose.
* each implementation needs some fine tune to it.
*/
if(counter ==1)
{
#ifndef WIN32
gettimeofday(&before, NULL);
before.tv_usec += sleepTime;
if(before.tv_usec > 1000000)
{
before.tv_usec -= 1000000;
before.tv_sec +=1;
}
#else
GetSystemTime(&before);
before.wMilliseconds +=sleepTime;
if(before.wMilliseconds > 1000)
{
before.wMilliseconds -= 1000;
before.wMilliseconds += 1;
}
#endif
}
if(throttledRate != 0)
{
if(counter%throttledRate == 0)
{
// sleep that much time
#ifndef WIN32
usleep(act_sleep_time);
gettimeofday(&after, NULL);
difftime = wfa_itime_diff(&after, &before);
#else
/* In case of win32 for higher frame rate we are sleeping
* less to meet the required Tx frame rate efficiency.
*/
if (theProf->rate > HIGH_FRAME_RATE_VAL)
usleep(act_sleep_time / SLEEP_DENOMINATOR);
else
usleep(act_sleep_time);
GetSystemTime(&after);
difftime = wfa_Winitime_diff(&before,&after );
#endif
// burn the rest to absort latency
if(difftime >0)
buzz_time(difftime);
#ifndef WIN32
before.tv_usec += sleepTime;
if(before.tv_usec > 1000000)
{
before.tv_usec -= 1000000;
before.tv_sec +=1;
}
}
} // otherwise, it floods
#else
before.wMilliseconds += sleepTime;
if(before.wMilliseconds > 1000)
{
before.wMilliseconds -= 1000;
before.wSecond +=1;
}
}
} // otherwise, it floods
#endif
/*
* Fill the timestamp to the header.
*/
#ifndef WIN32
gettimeofday(&stime, NULL);
int2BuffBigEndian(stime.tv_sec, &((tgHeader_t *)packBuf)->hdr[12]);
int2BuffBigEndian(stime.tv_usec, &((tgHeader_t *)packBuf)->hdr[16]);
#else
GetSystemTime(&stime);
int2BuffBigEndian(stime.wSecond, &((tgHeader_t *)packBuf)->hdr[12]);
int2BuffBigEndian(stime.wMilliseconds , &((tgHeader_t *)packBuf)->hdr[16]);
#endif
if(theProf->profile == PROF_FILE_TX_TCP || theProf->profile == PROF_TRANSC_TCP)
bytesSent = wfaCtrlSend(mySockfd, (unsigned char*)packBuf, packLen);
else
bytesSent = wfaTrafficSendTo(mySockfd, packBuf, packLen, (struct sockaddr *)&toAddr);
if(bytesSent != -1)
{
myStream->stats.txPayloadBytes += bytesSent;
myStream->stats.txFrames++ ;
}
else
{
#ifndef WIN32
errsv = errno;
switch(errsv)
{
case EAGAIN:
case ENOBUFS:
//DPRINT_INFO(WFA_OUT, "send error\n");
usleep(50);
counter-- ;
//myStream->stats.txFrames--;
break;
case ECONNRESET:
runLoop = 0;
break;
case EPIPE:
runLoop = 0;
break;
default:
{
DPRINT_INFO(WFA_OUT, "Packet sent error\n");
}
}
#else
errsv = WSAGetLastError();
switch(errsv)
{
case WSATRY_AGAIN:
case WSAENOBUFS:
DPRINT_INFO(WFA_OUT, "send error\n");
usleep(1); /* hold for 1 ms */
counter-- ;
// myStream->stats.txFrames--;
break;
case WSAECONNRESET:
runLoop = 0;
break;
case WSAESHUTDOWN:
runLoop = 0;
break;
default:
DPRINT_INFO(WFA_OUT, "Packet sent error\n");
break;
}
#endif
}
}
/*
* lower back to an original level if the process is raised previously
* It is optional.
*/
//wfaSetProcPriority(30);
}
else /* invalid parameters */
{
/* encode a TLV for response for "invalid ..." */
sendResp.status = STATUS_INVALID;
memcpy(Send_dutResp , (BYTE*)&sendResp, sizeof(dutCmdResponse_t));
return DONE;
}
gtgSend = 0;
/* free the buffer */
free(packBuf);
/* Populate the statistics of the sent response in Send_dutResp . In the case of multiple streams
* Send_dutResp buffer will have all the response at the end of the send process of all the streams.
*/
sendResp.status = STATUS_COMPLETE;
sendResp.streamId = myStream->id;
memcpy(&sendResp.cmdru.stats, &myStream->stats, sizeof(tgStats_t));
memcpy(Send_dutResp , (BYTE*)&sendResp, sizeof(dutCmdResponse_t));
#ifndef WIN32
gnumStreams = gnumStreams -1;
if(IPTVprof == 1) {
if(gnumStreams == 0)
sem_post(&sem_wmm);
}
#endif
return DONE;
}
/* this only sends one packet a time */
int wfaSendShortFile(int mySockfd, int streamid, BYTE *sendBuf, int pksize, BYTE *aRespBuf, int *aRespLen)
{
BYTE *packBuf = sendBuf;
struct sockaddr_in toAddr;
tgProfile_t *theProf;
tgStream_t *myStream;
int packLen, bytesSent=-1;
dutCmdResponse_t sendResp;
int errsv;
DPRINT_INFO(WFA_OUT, "---------SendShortFile----------:%d\r\n", mySockfd);
if(mySockfd == -1)
{
/* stop */
gtgTransac = 0;
gtimeOut = 0;
gtgRecv = 0;
gtgSend = 0;
DPRINT_INFO(WFA_OUT, "stop short traffic\n");
myStream = findStreamProfile(streamid);
if(myStream != NULL)
{
sendResp.status = STATUS_COMPLETE;
sendResp.streamId = streamid;
memcpy(&sendResp.cmdru.stats, &myStream->stats, sizeof(tgStats_t));
memcpy(Send_dutResp , (BYTE*)&sendResp, sizeof(dutCmdResponse_t));
}
return DONE;
}
/* find the profile */
myStream = findStreamProfile(streamid);
theProf = &myStream->profile;
if(theProf == NULL) {
return FALSE;
}
if(pksize == 0)
packLen = theProf->pksize;
else
packLen = pksize;
memset(&toAddr, 0, sizeof(toAddr));
toAddr.sin_family = AF_INET;
toAddr.sin_addr.s_addr = inet_addr(theProf->sipaddr);
toAddr.sin_port = htons(theProf->sport);
if(gtgRecv && gtgTransac)
{
toAddr.sin_addr.s_addr = inet_addr(theProf->sipaddr);
toAddr.sin_port = htons(theProf->sport);
}
else if(gtgSend && gtgTransac)
{
toAddr.sin_addr.s_addr = inet_addr(theProf->dipaddr);
toAddr.sin_port = htons(theProf->dport);
}
int2BuffBigEndian(myStream->stats.txFrames, &((tgHeader_t *)packBuf)->hdr[8]);
if(mySockfd != -1)
{
if(theProf->profile == PROF_FILE_TX_TCP || theProf->profile == PROF_TRANSC_TCP)
bytesSent = wfaCtrlSend(mySockfd, (unsigned char*)packBuf, packLen);
else
bytesSent = wfaTrafficSendTo(mySockfd, (char *)packBuf, packLen, (struct sockaddr *)&toAddr);
}
if(bytesSent > 0)
{
myStream->stats.txFrames++;
myStream->stats.txPayloadBytes += bytesSent;
}
else if(bytesSent == -1)
{
#ifndef WIN32
errsv = errno;
switch(errsv)
{
case EAGAIN:
case ENOBUFS:
DPRINT_ERR(WFA_ERR, "send error\n");
usleep(1000); /* hold for 1 ms */
// myStream->stats.txFrames--;
break;
default:
break;
}
#else
errsv = WSAGetLastError();
switch(errsv)
{
case WSATRY_AGAIN:
case WSAENOBUFS:
usleep(1); /* hold for 1 ms */
// myStream->stats.txFrames--;
break;
default:
DPRINT_INFO(WFA_OUT, "sendto: ");
DPRINT_ERR(WFA_ERR, "send error\n");
break;
}
#endif
}
sentTranPkts++;
DPRINT_INFO(WFA_OUT, "SendShortFile: sentTranPkts = %d\r\n",sentTranPkts);
return DONE;
}
/* In this function we always receive from a specified IP address and Port. We change the receive
* socket from blocking to non-blocking */
int wfaRecvFile(int mySockfd, int streamid, char *recvBuf)
{
/* how many packets are received */
char *packBuf = recvBuf;
struct sockaddr_in fromAddr;
tgProfile_t *theProf;
tgStream_t *myStream;
int bytesRecvd;
#ifndef WIN32
int ioflags;
#endif
int lostPkts;
/* find the profile */
myStream = findStreamProfile(streamid);
theProf = &myStream->profile;
if(theProf == NULL)
{
return FALSE;
}
memset(packBuf, 0, MAX_UDP_LEN);
memset(&fromAddr, 0, sizeof(fromAddr));
fromAddr.sin_family = AF_INET;
fromAddr.sin_addr.s_addr = inet_addr(theProf->dipaddr);
fromAddr.sin_port = htons(theProf->dport);
if(gtgRecv && gtgTransac)
{
fromAddr.sin_addr.s_addr = inet_addr(theProf->sipaddr);
fromAddr.sin_port = htons(theProf->sport);
}
else if(gtgSend && gtgTransac)
{
fromAddr.sin_addr.s_addr = inet_addr(theProf->dipaddr);
fromAddr.sin_port = htons(theProf->dport);
}
/* get current flags setting */
#ifndef WIN32
ioflags = fcntl(mySockfd, F_GETFL, 0);
/* set only BLOCKING flag to non-blocking */
fcntl(mySockfd, F_SETFL, ioflags | O_NONBLOCK);
#endif
/* it is always to receive at least one packet, in case more in the
queue, just pick them up.
*/
if(theProf->profile == PROF_FILE_TX_TCP || theProf->profile == PROF_TRANSC_TCP)
bytesRecvd = wfaCtrlRecv(mySockfd, (unsigned char*)packBuf);
else
bytesRecvd = wfaTrafficRecv(mySockfd, packBuf, (struct sockaddr *)&fromAddr);
if(bytesRecvd > 0)
{
myStream->stats.rxFrames++;
myStream->stats.rxPayloadBytes +=bytesRecvd;
#ifdef WIN32
/*
* This sleep is added to avoid driver crash at Dut side when TG sends
* traffic at unlimited frame rate for longer duration
*/
if (myStream->stats.rxFrames % 20 == 0)
usleep(1);
#endif
/*
* Get the lost packet count
*/
lostPkts =bigEndianBuff2Int(&((tgHeader_t *)packBuf)->hdr[8]) - 1 - myStream->lastPktSN;
myStream->stats.lostPkts += lostPkts;
myStream->lastPktSN = bigEndianBuff2Int(&((tgHeader_t *)packBuf)->hdr[8]);
}
return (bytesRecvd);
}
/* This is going to be a blocking SEND till it finishes
* The code is optimized for to achieve higher through put
* by using hardcoded header buffers
*/
int wfaImprovePerfSendLongFile(int mySockfd, int streamid, BYTE *aRespBuf, int *aRespLen)
{
tgProfile_t *theProf = NULL;
tgStream_t *myStream = NULL;
struct sockaddr_in toAddr;
char *packBuf;
int packLen;
int bytesSent;
dutCmdResponse_t sendResp;
int errsv;
#ifdef WIN32
SYSTEMTIME stime;
#else
struct timeval stime;
#endif
int counter = 0;
/* find the profile */
myStream = findStreamProfile(streamid);
if(myStream == NULL)
{
return FALSE;
}
theProf = &myStream->profile;
if(theProf == NULL || theProf->duration == 0) /* invalid parameters */
{
/* encode a TLV for response for "invalid ..." */
sendResp.status = STATUS_INVALID;
memcpy(Send_dutResp , (BYTE*)&sendResp, sizeof(dutCmdResponse_t));
return DONE;
}
packLen = theProf->pksize;
/* allocate a buf */
packBuf = (char *)malloc(packLen);
memset(packBuf, 1, packLen);
/* fill in the header */
strncpy(packBuf, "1345678", sizeof(tgHeader_t));
/* initialize the destination address */
memset(&toAddr, 0, sizeof(toAddr));
toAddr.sin_family = AF_INET;
toAddr.sin_addr.s_addr = inet_addr(theProf->dipaddr);
toAddr.sin_port = htons(theProf->dport);
/* if a frame rate and duration are defined, then we know
* interval for each packet and how many packets it needs to
* send.
*/
runLoop=1;
/*
* Fill the hardcoded timestamp to the header.
*/
#ifndef WIN32
gettimeofday(&stime, NULL);
int2BuffBigEndian(stime.tv_sec, &((tgHeader_t *)packBuf)->hdr[12]);
int2BuffBigEndian(stime.tv_usec, &((tgHeader_t *)packBuf)->hdr[16]);
#else
GetSystemTime(&stime);
int2BuffBigEndian(stime.wSecond, &((tgHeader_t *)packBuf)->hdr[12]);
int2BuffBigEndian(stime.wMilliseconds , &((tgHeader_t *)packBuf)->hdr[16]);
#endif
#ifndef WIN32
while (runLoop)
#else
while ((WaitForSingleObject(send_event,0) != WAIT_OBJECT_0))
#endif
{
counter++;
/* fill in the counter */
int2BuffBigEndian(counter, &((tgHeader_t *)packBuf)->hdr[8]);
/*
* the following code is only used to slow down
* over fast traffic flooding the buffer and cause
* packet drop or the other end not able to receive due to
* some limitations, purely for experiment purpose.
* each implementation needs some fine tune to it.
*/
if(theProf->profile == PROF_FILE_TX_TCP || theProf->profile == PROF_TRANSC_TCP)
bytesSent = wfaCtrlSend(mySockfd, (unsigned char*)packBuf, packLen);
else
bytesSent = wfaTrafficSendTo(mySockfd, packBuf, packLen, (struct sockaddr *)&toAddr);
if(bytesSent > 0)
{
myStream->stats.txPayloadBytes += bytesSent;
myStream->stats.txFrames++ ;
}
else if(bytesSent == -1)
{
#ifndef WIN32
errsv = errno;
switch(errsv)
{
case EAGAIN:
case ENOBUFS:
//DPRINT_INFO(WFA_OUT, "send error\n");
usleep(50);
counter-- ;
//myStream->stats.txFrames--;
break;
case ECONNRESET:
runLoop = 0;
break;
case EPIPE:
runLoop = 0;
break;
default:
{
DPRINT_INFO(WFA_OUT, "Packet sent error\n");
}
}
#else
errsv = WSAGetLastError();
switch(errsv)
{
case WSATRY_AGAIN:
case WSAENOBUFS:
DPRINT_INFO(WFA_OUT, "send error\n");
usleep(1); /* hold for 1 ms */
counter-- ;
break;
case WSAECONNRESET:
runLoop = 0;
break;
case WSAESHUTDOWN:
runLoop = 0;
break;
default:
DPRINT_INFO(WFA_OUT, "Packet sent error\n");
break;
}
#endif
}
#ifdef WIN32
/* In case of win32 we are sleeping after every 20 frame sent.
* This is to avoid driver hang in case of windows mobile
*/
if (myStream->stats.txFrames % 20 == 0)
usleep(1);
#endif
}
gtgSend = 0;
/* free the buffer */
free(packBuf);
/* Populate the statistics of the sent response in Send_dutResp . In the case of multiple streams
* Send_dutResp buffer will have all the response at the end of the send process of all the streams.
*/
sendResp.status = STATUS_COMPLETE;
sendResp.streamId = myStream->id;
memcpy(&sendResp.cmdru.stats, &myStream->stats, sizeof(tgStats_t));
memcpy(Send_dutResp , (BYTE*)&sendResp, sizeof(dutCmdResponse_t));
#ifndef WIN32
gnumStreams = gnumStreams -1;
if(IPTVprof == 1) {
if(gnumStreams == 0)
sem_post(&sem_wmm);
}
#endif
return DONE;
}
#ifdef WIN32
DWORD Win32_tmout_stop_send(LPVOID num )
{
int i;
Sleep((DWORD)num);
DPRINT_INFO(WFA_OUT, "timer fired, stop sending traffic\n");
/*
* After runLoop reset, all sendLong will stop
*/
runLoop = 0;
/*Reset to stop sending the short file*/
gTransactrunLoop = 0;
/*
* Decrement the usedThread everytime the timeout function is called .
*/
--usedThread ;
if(usedThread ==0 && IPTVprof == 1) {
asd_sleep(1);
/* Set the event when there are no more streams to send the traffic */
if(SetEvent(send_event)== 0 ){
DPRINT_INFO(WFA_OUT, "SetEvent failure %d \n", GetLastError());
}
/*
* all WMM streams also stop
*/
for(i=0; i<WFA_TRAFFIC_CLASS_NUM; i++)
{
if(g_TGSndThr[i] != NULL){
CloseHandle(g_TGSndThr[i]);
g_TGSndThr[i] = NULL;
}
}
}
/*
* once the stream table slot count is reset, it implies that the test
* is done. When the next set profile command comes in, it will reset/clean
* the stream table.
*/
slotCnt = 0;
/*
* The test is for DT3 transaction test.
* Timeout to stop it.
*/
if(gtgTransac != 0)
{
gtgTransac = 0;
gtgSend = 0;
gtimeOut = 0;
gRegSec = 1;
gtgRecv = 0;
}
return 0;
}
#endif