// TCPIPTrcDlg.cpp : implementation file
//

#include "stdafx.h"
#include "TCPIPTrc.h"
#include "TCPIPTrcDlg.h"
#include "DlgProxy.h"
#include <atlconv.h>
#include <atlbase.h>
#include <stddef.h>
#include <winsock.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif




VOID ReaderThread(LPVOID lpvParam);

static char  ADI_TOOLS_TCPIP_RegistryKey[] = "Software\\Analog Devices\\VisualDSP++\\TCPIPTrace";
static char  ADI_TOOLS_TCPIPTraceFile[] = TEXT("TraceFile");

void SaveTraceFileIntoRegistry(char *in_filename)
{
	HKEY hTCPIPKey;
	DWORD dwResult;

	if(RegCreateKeyEx(HKEY_CURRENT_USER,ADI_TOOLS_TCPIP_RegistryKey,0,"REG_SZ",REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hTCPIPKey,&dwResult) != ERROR_SUCCESS)
	{
		// creating registry entry failed..returning.
		return;
	}
	
	if(in_filename != NULL)
		RegSetValueEx(hTCPIPKey,ADI_TOOLS_TCPIPTraceFile,0,REG_SZ,(unsigned char*)in_filename,strlen(in_filename));

	RegCloseKey(hTCPIPKey);
}
void SaveDWORDIntoRegistry(char *name, DWORD vl)
{
	HKEY hTCPIPKey;
	DWORD dwResult;

	if(RegCreateKeyEx(HKEY_CURRENT_USER,ADI_TOOLS_TCPIP_RegistryKey,0,"REG_SZ",REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hTCPIPKey,&dwResult) != ERROR_SUCCESS)
	{
		// creating registry entry failed..returning.
		return;
	}
	
	RegSetValueEx(hTCPIPKey,name,0,REG_DWORD,(unsigned char*)&vl,sizeof(vl));

	RegCloseKey(hTCPIPKey);
}

// Copies the last file form registry to the path supplied 
//
bool GetTraceFileFromRegistry(char *out_filename)
{
	BYTE  temp_filename[512];
	HKEY  hTCPIPKey;
	DWORD dwType;
	DWORD dwRead;

	if((RegOpenKeyEx(HKEY_CURRENT_USER,ADI_TOOLS_TCPIP_RegistryKey,0,KEY_ALL_ACCESS  | KEY_QUERY_VALUE
		,&hTCPIPKey) != ERROR_SUCCESS))
	{
		// nothing to load..copy null and return..
		*out_filename = '\0';
		return false;
	}
	
	if(out_filename != NULL)
	{
		dwRead = sizeof(temp_filename);
		if((RegQueryValueExA(hTCPIPKey,ADI_TOOLS_TCPIPTraceFile,NULL,&dwType,temp_filename,&dwRead) != ERROR_SUCCESS))
		{
			*out_filename = '\0';
			return false;
		}
		strcpy(out_filename,(char*)temp_filename);
	}

	RegCloseKey(hTCPIPKey);
	return true;
}

bool GetDWORDFromRegistry(char *name, DWORD *vl)
{
	HKEY  hTCPIPKey;
	DWORD dwType;
	DWORD dwRead,tvl;

	if((RegOpenKeyEx(HKEY_CURRENT_USER,ADI_TOOLS_TCPIP_RegistryKey,0,KEY_ALL_ACCESS  | KEY_QUERY_VALUE
		,&hTCPIPKey) != ERROR_SUCCESS))
	{
		// nothing to load..copy null and return..
		return false;
	} else {
	
		dwRead = sizeof(tvl);
		if((RegQueryValueExA(hTCPIPKey,name,NULL,&dwType,(unsigned char *)&tvl,&dwRead) != ERROR_SUCCESS))
		{
			return false;
		}
		if (dwType == REG_DWORD) *vl = tvl;
	}

	RegCloseKey(hTCPIPKey);
	return true;
}

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTCPIPTrcDlg dialog

IMPLEMENT_DYNAMIC(CTCPIPTrcDlg, CDialog);

CTCPIPTrcDlg::CTCPIPTrcDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CTCPIPTrcDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CTCPIPTrcDlg)
	m_FileName = _T("");
	m_SaveAll = FALSE;
	m_Channel = 0;
	m_NoEvents = 0;
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	m_pAutoProxy = NULL;
	m_Stopped = true;
	m_Listen = m_Client = INVALID_SOCKET;
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;

	wVersionRequested = MAKEWORD( 2, 2 );

	err =WSAStartup( wVersionRequested, &wsaData );
}

CTCPIPTrcDlg::~CTCPIPTrcDlg()
{
	// If there is an automation proxy for this dialog, set
	//  its back pointer to this dialog to NULL, so it knows
	//  the dialog has been deleted.
	if (m_pAutoProxy != NULL)
		m_pAutoProxy->m_pDialog = NULL;
}

void CTCPIPTrcDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CTCPIPTrcDlg)
	DDX_Control(pDX, IDC_REPORT, m_ReportCtrl);
	DDX_Control(pDX, IDC_LOCALIP, m_LocalIPCtrl);
	DDX_Control(pDX, IDC_CHANNEL, m_ChannelCtrl);
	DDX_Control(pDX, IDC_STOPACQ, m_StopAcqCtrl);
	DDX_Control(pDX, IDC_STARTACQ, m_StartAcqCtrl);
	DDX_Control(pDX, IDC_SAVECUR, m_SaveCurCtrl);
	DDX_Control(pDX, IDC_SAVEALL, m_SaveAllCtrl);
	DDX_Control(pDX, IDC_PAUSE, m_PauseCtrl);
	DDX_Control(pDX, IDC_NOEVENTS, m_NoEventsCtrl);
	DDX_Control(pDX, IDC_FILENAME, m_FileNameCtrl);
	DDX_Control(pDX, IDC_EVENTLIST, m_EventListCtrl);
	DDX_Text(pDX, IDC_FILENAME, m_FileName);
	DDX_Check(pDX, IDC_SAVEALL, m_SaveAll);
	DDX_Text(pDX, IDC_CHANNEL, m_Channel);
	DDX_Text(pDX, IDC_NOEVENTS, m_NoEvents);
	DDV_MinMaxLong(pDX, m_NoEvents, 0, 1000000000);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CTCPIPTrcDlg, CDialog)
	//{{AFX_MSG_MAP(CTCPIPTrcDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_DESTROY()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_WM_CLOSE()
	ON_BN_CLICKED(ID_HELP, OnHelp)
	ON_EN_CHANGE(IDC_FILENAME, OnChangeFilename)
	ON_EN_CHANGE(IDC_NOEVENTS, OnChangeNoevents)
	ON_BN_CLICKED(IDC_PAUSE, OnPause)
	ON_BN_CLICKED(IDC_SAVECUR, OnSavecur)
	ON_BN_CLICKED(IDC_SAVEFILE, OnSavefile)
	ON_BN_CLICKED(IDC_STARTACQ, OnStartacq)
	ON_BN_CLICKED(IDC_STOPACQ, OnStopacq)
	ON_BN_CLICKED(IDC_BROWSE, OnBrowse)
	ON_EN_CHANGE(IDC_CHANNEL, OnChangeChannel)
	ON_BN_CLICKED(IDC_SAVEALL, OnSaveall)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()







/*
 * This function converts the given 32 bit value to host byte order.
 */
static unsigned long dsp_ntohl(unsigned long value)
{
	unsigned long ret_value;

	ret_value = (((value & 0x000000FF) << 24) | ((value & 0x0000FF00) << 8) |
				((value & 0x00FF0000) >> 8) | ((value & 0xFF000000) >> 24));

	return(ret_value);}

/*
 * This function converts the given 16 bit value to host byte order.
 */
static short dsp_ntohs(short value)
{
	short ret_value;

	ret_value = ((value & 0x000000FF) << 8) | ((value & 0x0000FF00) >> 8);
	return(ret_value);
}



char *  CTCPIPTrcDlg::FindHostName(int IpAddrs, char *bf)
{
	int i;
	unsigned char *ic;
	
	for (i=0; i<m_NoHostNames; i++) {
		if (IpAddrs == m_HostMap[i].IpAddrs) {
			return (char *)m_HostMap[i].HostName;
		}
	}
	// generate 1.2.3.4
	ic = (unsigned char *)&IpAddrs;
	sprintf(bf,"%u.%u.%u.%u",ic[0],ic[1],ic[2],ic[3]);
	return bf;
}

static GetMac(unsigned char *mac, char *buf)
{
	sprintf(buf,"%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
			mac[0],mac[1],mac[2],
			mac[3],mac[4],mac[5]);
}
void  CTCPIPTrcDlg::DumpIPTraceEntry(
		unsigned char id, int nbytes, unsigned short clk,
		unsigned char *hdr)
{
	int rcvd = (id=='R'); 
	
	if (nbytes>0) {
		// we have to format the buffer
		char adr1[20],adr2[20],adr3[4];
		char *src,*dst,*prot;
		char line[128],codes[32];
		int cnext=0;
		datagram dd;
		datagram *d;
		udp uu;
		udp *u;
		tcp tt;
		tcp *t;
		icmp iicm;
		icmp *icm;
		int hdrlen = nbytes;
		int data=0;
		static char *ctext[] = {"FIN ","SYN ","RST ","PSH ","ACK ","URG ",0};
		int ic=0;
		int ndata;
		
		memcpy(&dd,hdr,sizeof(dd));
		d = &dd; // get fields aligned
		// format the IP header first
		src = FindHostName(d->Source,adr1);
		dst = FindHostName(d->Dest,adr2);
		switch(d->Protocol) {
		case ICMP_PROTOCOL:
			prot = "ICMP";
			break;
		case TCP_PROTOCOL:
			prot = "TCP";
			break;
		case UDP_PROTOCOL:
			prot = "UDP";
			break;
		default:
		    sprintf(adr3,"%d",d->Protocol);
			prot = adr3;
		    break;
		}
		sprintf(m_StrBuffer,"%4.4x %cX src=%s, dest=%s, prot=%s,frag=%u, length=%u",
				clk,(rcvd?'R':'T'),src,dst,prot,d->FlagsFragOffset&0x1fff,dsp_ntohs(d->TotalLnth));
		AppendLine();
		data = ((d->VersHlen&0x0f)*4); /* start of any data */
		switch (d->Protocol) {
		case ICMP_PROTOCOL:
			memcpy(&iicm,(icmp *)(hdr+(d->VersHlen&0x0f)*4),sizeof(iicm));
			icm = &iicm;
			sprintf(m_StrBuffer,"\t   icmp type=%u, qual=%u",
						icm->Type,icm->Qual);
			data += sizeof(iicm);
			AppendLine();
			break;
		case TCP_PROTOCOL:
			memcpy(&tt,(tcp *)(hdr+(d->VersHlen&0x0f)*4),sizeof(tt));
			t = &tt;
			for (ic=0;ic<6;ic++) {
				if ((t->Code>>ic)&1) {
					memcpy(codes+cnext,ctext[ic],4);
					cnext+=4;
				}
			}
			codes[cnext] = 0;
			sprintf(m_StrBuffer,"\t   sport=0x%x, dport=0x%4.4x, seq=%x, ack=0x%x, win=%u code=%s",
						dsp_ntohs(t->SrcPort),dsp_ntohs(t->DstPort),dsp_ntohl(t->SeqNo),dsp_ntohl(t->AckNo),dsp_ntohs(t->Window),codes);
			data += ((tt.Hlen>>4)*4);
			AppendLine();
			break;
		case UDP_PROTOCOL:
			memcpy(&uu,(udp *)(hdr+(d->VersHlen&0x0f)*4),sizeof(uu));
			u = &uu;
			sprintf(m_StrBuffer,"\t   sport=0x%x, dport=0x%4.4x, msg length=%u",
						dsp_ntohs(u->SrcPort),dsp_ntohs(u->DstPort),dsp_ntohs(u->MsgLnth));
			data += sizeof(uu);
			AppendLine();
			break;
		default:
			break;
		}
		ndata = hdrlen  - data;
		
		
		if (ndata>0) {
			int nxt=3;
			int mx=sizeof(line)-2;
			int inl=0;
			char *ch=line+53;

			strcpy(m_StrBuffer,"\t");
			memset(line,' ',72);
			while (ndata>0) {
				sprintf(line+nxt,"%2.2x ",hdr[data]);
				if ((33<=hdr[data]) && (hdr[data]<=126)) {
					*ch = hdr[data];
				} else {
					*ch = '.';
				}
				ch++;
				nxt += 3;
				data++;
				inl++;
				if (inl>15) {
					line[nxt] = ' ';
					*ch  = 0;
					strcat(m_StrBuffer,line);
					AppendLine();
					strcpy(m_StrBuffer,"\t");
					memset(line,' ',72);
					nxt = 3;
					inl = 0;
					ch=line+53;
				}
				ndata--;
			}
			if (nxt>3) {
				line[nxt] = ' ';
				*ch  = 0;
				strcat(m_StrBuffer,line);
				AppendLine();
			}
		}
	} else {
		sprintf(m_StrBuffer,"%4.4x %cX empty IP packet",
					clk,(rcvd?'R':'T'));
		AppendLine();
	}
}

void  CTCPIPTrcDlg::DumpArpTraceEntry(
		unsigned char id, int nbytes, unsigned short clk,
		unsigned char *hdr)
{
	int rcvd = (id=='R');  
	
	if (nbytes>0) {
		// we have to format the buffer
		unsigned short oper;
		char adr1[20],adr2[20],adr3[20],adr4[20];
		char *src,*dst,*prot;
		int ip;
		
		oper = dsp_ntohs(*((unsigned short *)(hdr+6)));
		switch (oper) {
		case 1:
			prot = "AREQ";
			break;
		case 2:
			prot = "ARSP";
			break;
		case 3:
			prot = "RREQ";
			break;
		case 4:
			prot = "RRSP";
			break;
		default:
		    sprintf(adr3,"%2.2x",oper);
			prot = adr3;
		    break;
		}
		
		// format the IP header first
		memcpy(&ip,hdr+14,4);
		src = FindHostName(ip,adr1);
		GetMac(hdr+8,adr3);
		memcpy(&ip,hdr+24,4);
		dst = FindHostName(ip,adr2);
		GetMac(hdr+18,adr4);
		sprintf(m_StrBuffer,"%4.4x %cX ARP OPER=%s Snd MAC=%s Snd IP=%s Tgt MAC=%s Tgt IP=%s",
					clk,(rcvd?'R':'T'),prot,adr3,src,adr4,dst);
	} else {
		sprintf(m_StrBuffer,"%4.4x %cX empty ARP packet",
					clk,(rcvd?'R':'T'));
	}
	AppendLine();
}

void  CTCPIPTrcDlg::DumpDefTraceEntry(
		unsigned char id, int nbytes, unsigned short clk,
		unsigned char *hdr)
{
	char pid[32];
	int i;

	if ((' '<=id) && (id<=126)) {
		pid[0] = id;
		pid[1] = 0;
	} else {
		sprintf(pid,"0x%2.2x",id);
	}
	
	sprintf(m_StrBuffer,"%4.4x ID=%s nbytes=%d ",clk,pid,nbytes);
	if (nbytes>0) {
		if (nbytes>8) nbytes = 8;
		for (i=0;i<nbytes;i++) {
			sprintf(pid,"%2.2x ",hdr[i]);
			strcat(m_StrBuffer,pid);
		}

	}
	AppendLine();
}

void  CTCPIPTrcDlg::DumpTraceEntry(
		unsigned char *hdr)
{
	unsigned short frame;
	int nbytes = hdr[1];
	unsigned short clk,frm;
	int def=0;
	
	m_TrcIndex++;
	if (!m_Paused) m_NoEntries++;
	InterlockedIncrement(&m_TraceListSize);

	if (m_TrcIndex>200) {
		int jj=5;
	}

	if ((hdr[0]=='T') || (hdr[0]=='R')) {
		
		m_LastNdx = -1;
		memcpy(&clk,hdr+2,2);
		memcpy(&frm,hdr+16,2);
		if (nbytes>13)  {
			frame = dsp_ntohs(frm);
			if (frame == 0x0800) {
				DumpIPTraceEntry(hdr[0],nbytes, clk,hdr+18);
			} else if (frame == 0x0806) {
				DumpArpTraceEntry(hdr[0],nbytes, clk,hdr+18);
			} else {
				// dump nothing
				def = 1;
			}
		} else {
			def = 1;
		}
		if (def) {
			DumpDefTraceEntry(hdr[0],nbytes,clk,hdr+4);
		}
		if (m_LastNdx>=0) {
			m_EventListCtrl.SetCurSel(m_LastNdx);
		}
	}
}


void CTCPIPTrcDlg::AppendLine(void)
{
	TraceLine *lin;

	if (m_Trc) {
		fprintf(m_Trc,"%s\n",m_StrBuffer);
	}
	lin = (TraceLine *)malloc(sizeof(TraceLine));
	if (lin!=NULL) {

		EnterCriticalSection(&m_Critical);
		lin->Next = NULL;
		lin->Mark = m_TrcIndex;
		lin->Data = (char *)malloc(strlen(m_StrBuffer)+1);
		if (lin->Data) {
			strcpy(lin->Data,m_StrBuffer);
		} else {
			free(lin);
			lin = NULL;
		}
		if (lin!=NULL) {
			// append it to the tail
			if (m_TraceTail) {
				m_TraceTail->Next = lin;
			} else {
				m_TraceHead = lin;
			}
			m_TraceTail = lin;
			if (m_TraceListSize > m_NoEvents) {
				// remove the first
				int mark = m_TraceHead->Mark;

				while ((m_TraceHead!=NULL) && (mark == m_TraceHead->Mark)) {
					// remove the line
					lin = m_TraceHead;
					// free up the memory
					m_TraceHead = m_TraceHead->Next;
					if (lin->Data) free(lin->Data);
					free(lin);
					if (m_TraceHead == NULL) m_TraceTail = NULL;
				}
				InterlockedDecrement(&m_TraceListSize);
			}
		}
		LeaveCriticalSection(&m_Critical);
	}

	if (!m_Paused) {
		int ndx = m_EventListCtrl.AddString(m_StrBuffer);

		if (ndx>=0) {
			m_EventListCtrl.SetItemData(ndx,m_TrcIndex);
			m_LastNdx = ndx;
		}
		while (m_NoEntries>m_NoEvents) {
			// remove oldest item
			DWORD mark;
			
			mark = m_EventListCtrl.GetItemData(0);
			while (mark == m_EventListCtrl.GetItemData(0)) {
				m_EventListCtrl.DeleteString(0);
				m_LastNdx--;
			}
			m_NoEntries--;
		}
	}
}

/******************************************************************************/
/*		GetHostNameFromRegistry                                               */
/******************************************************************************/
/*  Get the TCP/IP host name from the Registry  */
static BOOL GetHostNameFromRegistry(LPSTR HostName,DWORD dwSizeHostName) 
{
	HKEY hkTcpip;
	DWORD dwError;
	DWORD dwSize;
	char *p;

    dwError = RegOpenKeyEx(
                    HKEY_LOCAL_MACHINE,
                    "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
                    0,
                    KEY_READ,
                    &hkTcpip);
    if (dwError) {
        SetLastError(dwError);
        return FALSE;
    }
    /* Get the host name */
    dwSize = dwSizeHostName;
    dwError = RegQueryValueEx(
                    hkTcpip,
                    "Hostname",
                    NULL,
                    NULL,
                    (unsigned char *)HostName,
                    &dwSize);
    if (dwError) {
        RegCloseKey(hkTcpip);
        SetLastError(dwError);
        return FALSE;
    }
    /* Append a dot */
    strncat(HostName,".",dwSizeHostName);
    /* Append the domain name */
    dwSize = dwSizeHostName - strlen(HostName);
    p = HostName + strlen(HostName);
    dwError = RegQueryValueEx(
                    hkTcpip,
                    "Domain",
                    NULL,
                    NULL,
                    (unsigned char *)p,
                    &dwSize);
    if (dwError || strlen(p)==0) {
        //RegCloseKey(hkTcpip);
        //SetLastError(dwError);
        //return FALSE;
		// remove trailing .
		HostName[strlen(HostName)-1] = 0;
    }
    /* Terminate successfully */
    RegCloseKey(hkTcpip);
    return TRUE;
}


/******************************************************************************/
/*		GetLocalHostIPInfo                                                    */
/******************************************************************************/
/*  Get the local host IP addresses and names into the LocalHostIPInfo array.
    Return the number of addresses in the nAddresses variable.  */

#define MAX_INET_ADDRESSES 5


typedef struct _IPInfo {
    IN_ADDR IPAddr;
    char Name[256];
    char Address[64];
} tIPInfo;
static tIPInfo    LocalHostIPInfo[MAX_INET_ADDRESSES];

static void GetLocalHostIPInfo(char *localip) 
{
	char szBuff[256];
	DWORD dwSize;
	PHOSTENT phe;
	int i;
	int nAddresses;

    /* Error condition is indicated if this is 0 on exit */
    nAddresses = 0;

    /* Get host name */
    dwSize = sizeof(szBuff);
    if (gethostname(szBuff,dwSize)) {
        return;
    }
    /* Get host addresses */
    phe = gethostbyname(szBuff);
    if (phe == NULL) {
        return;
    }
    if (strchr(szBuff,'.')==NULL) {
        /* gethostname() did not return a FQDN.  Go get the FQDN from the Registry */
        if (!GetHostNameFromRegistry(szBuff,dwSize)) {
            return;
       }
    }
    /* Copy the IP addresses */
	strncpy(LocalHostIPInfo[0].Name,"",sizeof(LocalHostIPInfo[i].Name));

    i = 0;
    while (i<MAX_INET_ADDRESSES) {
        if (phe->h_addr_list[i]==0) break;
        memcpy(&LocalHostIPInfo[i].IPAddr,phe->h_addr_list[i],sizeof(struct in_addr));
        strncpy(LocalHostIPInfo[i].Address,
                inet_ntoa(LocalHostIPInfo[i].IPAddr),
                sizeof(LocalHostIPInfo[i].Address));
        strncpy(LocalHostIPInfo[i].Name,szBuff,sizeof(LocalHostIPInfo[i].Name));
        i++;
    }
    nAddresses = i;
	if (nAddresses>0) {
		strcpy(localip,LocalHostIPInfo[0].Address);
	} else {
		strcpy(localip,"?");
	}
#if 0
    /* Now look up the names corresponding to the addresses */
    for (i=0;i<nAddresses;i++) {
		time_t	tStartedTime, tFinishedTime;

		tStartedTime = time(&tStartedTime);
        phe = gethostbyaddr((const char *)&LocalHostIPInfo[i].IPAddr,sizeof(IN_ADDR),PF_INET);
		tFinishedTime = time(&tFinishedTime);

		//Did it take more than 20 seconds? If so, DNS does not active.
		if (tFinishedTime - tStartedTime > 20) {	
			MessageBox(NULL,
			"DNS(Domain Name Service) not operational.\nVerify DNS and your network.",
			"TCPIPTrc",
			MB_OK);
			return;
		}
        if (phe!=NULL) {
            /* We got something which claims to be a host name */
            if (strchr(phe->h_name,'.')!=0) {
                /* It has a dot, so it's probably a FQDN - replace the host name we got earlier. */
                strncpy(LocalHostIPInfo[i].Name,phe->h_name,sizeof(LocalHostIPInfo[i].Name));
            }
        }
    }
#endif
}

/////////////////////////////////////////////////////////////////////////////
// CTCPIPTrcDlg message handlers

BOOL CTCPIPTrcDlg::OnInitDialog()
{
	char filename[512];
	DWORD regvalue;

	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	m_Trc = NULL;
	m_NoHostNames = 0;
	m_TrcIndex = 0;
	m_NoEntries = 0;
	m_TraceHead = m_TraceTail = NULL;
	m_TraceListSize = 0;

	GetLocalHostIPInfo(filename);
	m_LocalIPCtrl.SetWindowText(filename);

	InitializeCriticalSection(&m_Critical);

	GetTraceFileFromRegistry(filename);
	m_FileNameCtrl.SetWindowText(filename);

	regvalue = 256;
	GetDWORDFromRegistry("NoEvents",&regvalue);
	ltoa(regvalue,filename,10);
	m_NoEventsCtrl.SetWindowText(filename);

	regvalue = 0;
	GetDWORDFromRegistry("ChannelNo",&regvalue);
	ltoa(regvalue,filename,10);
	m_ChannelCtrl.SetWindowText(filename);

	int tabstop = 12;
	m_EventListCtrl.SetTabStops(tabstop);
	m_PauseCtrl.EnableWindow(false);
	m_StartAcqCtrl.EnableWindow(true);
	m_StopAcqCtrl.EnableWindow(false);
	m_Paused = false;
	m_SaveAll = false;
	OnChangeFilename();
	OnChangeChannel();
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CTCPIPTrcDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

void CTCPIPTrcDlg::OnDestroy()
{
	WinHelp(0L, HELP_QUIT);
	CDialog::OnDestroy();
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CTCPIPTrcDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CTCPIPTrcDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

// Automation servers should not exit when a user closes the UI
//  if a controller still holds on to one of its objects.  These
//  message handlers make sure that if the proxy is still in use,
//  then the UI is hidden but the dialog remains around if it
//  is dismissed.

void CTCPIPTrcDlg::OnClose() 
{
	if (CanExit()) {
		if (!m_Stopped) {
			Stop();
			while (!m_Stopped) Sleep(100);
		}
		TidyUp();
		CDialog::OnClose();
	}
}

void CTCPIPTrcDlg::OnOK() 
{
	if (CanExit()) {

    if(!m_StopAcquiring)
		OnStopacq();
		/*if (!m_Stopped) {
			Stop();
			while (!m_Stopped) Sleep(100);
		}*/
		TidyUp();
		CDialog::OnOK();
	}
}

void CTCPIPTrcDlg::OnCancel() 
{
	if (CanExit()) {
		if (!m_Stopped) {
			Stop();
			while (!m_Stopped) Sleep(100);
		}
		TidyUp();
		CDialog::OnCancel();
	}
}

BOOL CTCPIPTrcDlg::CanExit()
{
	// If the proxy object is still around, then the automation
	//  controller is still holding on to this application.  Leave
	//  the dialog around, but hide its UI.
	if (m_pAutoProxy != NULL)
	{
		ShowWindow(SW_HIDE);
		return FALSE;
	}

	return TRUE;
}

void CTCPIPTrcDlg::OnHelp() 
{

}

void CTCPIPTrcDlg::OnChangeFilename() 
{
	// TODO: If this is a RICHEDIT control, the control will not
	// send this notification unless you override the CDialog::OnInitDialog()
	// function and call CRichEditCtrl().SetEventMask()
	// with the ENM_CHANGE flag ORed into the mask.
	CString fname;
	
	m_FileNameCtrl.GetWindowText(fname);
	m_SaveAllCtrl.EnableWindow(fname.GetLength()>0);
	m_SaveCurCtrl.EnableWindow(fname.GetLength()>0);


	
}

void CTCPIPTrcDlg::OnChangeNoevents() 
{
	// TODO: If this is a RICHEDIT control, the control will not
	// send this notification unless you override the CDialog::OnInitDialog()
	// function and call CRichEditCtrl().SetEventMask()
	// with the ENM_CHANGE flag ORed into the mask.
	
	// TODO: Add your control notification handler code here
	
}

void CTCPIPTrcDlg::OnPause() 
{
	if (m_Paused) {
		 m_Paused = false;
		m_PauseCtrl.SetWindowText("Pause display");
	} else {
		 m_Paused = true;
		m_PauseCtrl.SetWindowText("Start display");
	}
}

void CTCPIPTrcDlg::OnSavecur() 
{
	OPENFILENAME fn;
	char filename[512];

	m_FileNameCtrl.GetWindowText(filename,sizeof(filename));
	memset(&fn,0,sizeof(fn));
	fn.lStructSize = sizeof(fn);
	fn.lpstrFilter = "Trace dump files\x00*.trc\x00";
	fn.lpstrFile = filename;
	fn.nMaxFile = sizeof(filename);
	fn.lpstrTitle = "File the trace information is to be saved to";
	fn.Flags = OFN_CREATEPROMPT|OFN_LONGNAMES|OFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST;
	if (GetSaveFileName(&fn)) {
		FILE *trc = fopen(filename,"w");
		if (trc == NULL) {
			char err[1024];
			sprintf(err,"Unable to open %s for writing",filename);
			MessageBox(err,"TCP/IP Tracing");
		} else {
			TraceLine *lin;
			int nevents=0;
			int mark = -1;
			char emsg[512];

			SaveTraceFileIntoRegistry(filename);

			EnterCriticalSection(&m_Critical);

			lin = m_TraceHead;
			while (lin!=NULL) {
				fprintf(trc,"%s\n",lin->Data);
				if (lin->Mark != mark) {
					nevents++;
					mark = lin->Mark;
				}
				lin = lin->Next;
			}
			LeaveCriticalSection(&m_Critical);
			fclose(trc);
			sprintf(emsg,"%d events saved to %s",nevents,filename);
			MessageBox(emsg,"TCP/IP Tracing");
		}
	}
	
}

void CTCPIPTrcDlg::OnSavefile() 
{
	// TODO: Add your control notification handler code here
	
}

void CTCPIPTrcDlg::OnStartacq() 
{
	int ok=1;
	HANDLE hRead;
	DWORD dwThreadId;
	CString chn,noevs;
	char filename[512];

	TidyUp();

	m_NoEventsCtrl.GetWindowText(noevs);
	m_NoEvents = atoi(noevs);
	SaveDWORDIntoRegistry("NoEvents",m_NoEvents);

	m_ChannelCtrl.GetWindowText(chn);
	m_Channel = atoi(chn);
	SaveDWORDIntoRegistry("ChannelNo",m_Channel);

	m_PauseCtrl.SetWindowText("Pause display");
	m_Paused = false;
	m_PauseCtrl.EnableWindow(true);
	m_StopAcquiring = false;
	m_StopAcqCtrl.EnableWindow(true);
	m_StartAcqCtrl.EnableWindow(false);
	m_SaveAllCtrl.EnableWindow(false);

	if (m_SaveAll) {
		m_FileNameCtrl.GetWindowText(filename,sizeof(filename));
		if (filename[0]==0) {
			OPENFILENAME fn;

			memset(&fn,0,sizeof(fn));
			fn.lStructSize = sizeof(fn);
			fn.lpstrFilter = "Trace dump files\x00*.trc\x00";
			fn.lpstrFile = filename;
			fn.nMaxFile = sizeof(filename);
			fn.lpstrTitle = "File the trace information is to be saved to";
			fn.Flags = OFN_CREATEPROMPT|OFN_LONGNAMES|OFN_PATHMUSTEXIST|OFN_OVERWRITEPROMPT;
			if (GetSaveFileName(&fn)) {
				m_FileNameCtrl.SetWindowText(filename);
			}
		}
		m_FileNameCtrl.GetWindowText(filename,sizeof(filename));
		if (filename[0]!=0) {
			strcpy(m_SaveAlFileName,filename);
			m_Trc =  fopen(filename,"w");
			if (m_Trc == NULL) {
				char err[1024];
				sprintf(err,"Unable to open %s for writing",filename);
				MessageBox(err,"TCP/IP Tracing");
			} else {
				SaveTraceFileIntoRegistry(filename);
			}
		}
	}

	// create the threads
	hRead = CreateThread( 
		NULL,              // no security attribute 
		0,                 // default stack size 
		(LPTHREAD_START_ROUTINE) ReaderThread, 
		(LPVOID) this,    // thread parameter 
		0,                 // not suspended 
		&dwThreadId);      // returns thread ID 

	if (hRead == NULL) {
		// failed to create a thread to service the request
		MessageBox("Failed to create thread to acquire event data from DSP","TCP/IP Tracing");
		ok = 0;
	} else {
		CloseHandle(hRead); 
	}
	
}

void CTCPIPTrcDlg::Stop(void)
{
	m_StopAcquiring = true;
	if (m_Client != INVALID_SOCKET) {
		closesocket(m_Client);
		m_Client = INVALID_SOCKET;
	}
	if (m_Listen != INVALID_SOCKET) {
		closesocket(m_Listen);
		m_Listen = INVALID_SOCKET;
	}
	if (m_Trc!=NULL) {
		char em[512];

		fclose(m_Trc);
		m_Trc = NULL;
		sprintf(em,"Traced events have been saved in %s",m_SaveAlFileName);
		MessageBox(em,"TCP/IP Tracing");

	}
}

void CTCPIPTrcDlg::OnStopacq() 
{
	m_PauseCtrl.EnableWindow(false);
	m_StopAcquiring = true;
	m_StopAcqCtrl.EnableWindow(false);
	m_StartAcqCtrl.EnableWindow(true);
	m_SaveAllCtrl.EnableWindow(true);
	m_ReportCtrl.SetWindowText("");

	if (m_Trc!=NULL) {
		char em[512];

		fclose(m_Trc);
		m_Trc = NULL;
		sprintf(em,"Traced events have been saved in %s",m_SaveAlFileName);
		MessageBox(em,"TCP/IP Tracing");

	}
	Stop();
}

void CTCPIPTrcDlg::OnBrowse() 
{
	OPENFILENAME fn;
	char filename[512];

	m_FileNameCtrl.GetWindowText(filename,sizeof(filename));
	memset(&fn,0,sizeof(fn));
	fn.lStructSize = sizeof(fn);
	fn.lpstrFilter = "Trace dump files\x00*.trc\x00";
	fn.lpstrFile = filename;
	fn.nMaxFile = sizeof(filename);
	fn.lpstrTitle = "File the trace information is to be saved to";
	fn.Flags = OFN_CREATEPROMPT|OFN_LONGNAMES|OFN_PATHMUSTEXIST;
	if (GetSaveFileName(&fn)) {
		m_FileNameCtrl.SetWindowText(filename);
	}
}

void CTCPIPTrcDlg::OnChangeChannel() 
{
	CString fname;
	CString chn,noevs;

	
	
}

void CTCPIPTrcDlg::TidyUp(void)
{
	TraceLine *lin,*nxt;

	// free resources
	EnterCriticalSection(&m_Critical);
	m_EventListCtrl.ResetContent();
	lin = m_TraceHead;
	while (lin != NULL) {
		if (lin->Data) free(lin->Data);
		nxt = lin->Next;
		free(lin);
		lin = nxt;
	}
	m_TraceListSize = 0;
	m_TrcIndex = 0;
	m_NoEntries = 0;
	m_TraceHead = NULL;
	m_TraceTail = NULL;

	m_StopAcquiring = false;

	LeaveCriticalSection(&m_Critical);

}

void CTCPIPTrcDlg::Recv(void)
{
	USES_CONVERSION;

	typedef struct TraceData {
		unsigned int			Active;				// if non-zero some tracing is active
		unsigned int			ActClasses[8];		// Each bit represents one of 256 trace classes
		unsigned int			MaxTrcBytes;		// maximum number of trace bytes
		unsigned int			NoTrcBytes;			// the no of trace bytes to be read by the host
		unsigned char			TrcBytes[1];		// start of the trace buffer
						
	} TraceData;

	int ActPoint=0;

	m_Stopped = false;
	m_ReportCtrl.SetWindowText("Tracing from BTC");

	CoInitialize(NULL);
	try {

		SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_BELOW_NORMAL);

		IADspApplicationPtr pApp("VisualDSP.ADspApplication");
		IADspPluginPtr pBtcPlugin = pApp->PluginList->GetItem("BtcManager");
		IADspBtcManagerPtr pBtcManager = pBtcPlugin->Open();
		IADspProcessorPtr    pProc;
		IADspDebugSessionPtr pSession;
		DWORD adrs=0,lnth=0;
		int nfound = 1;
		unsigned int *rdbuf=NULL;
		int maxlnth,maxelem;
		int nbytes,nwords;
		long indx;
		int actionok;


		pSession = pApp->ActiveSession;
		//  get the first processor in the session
		pProc = pSession->ActiveProcessor;
		ActPoint=-2;
		// wait till the processor is running
		while ((!m_StopAcquiring) && (pProc->State != stateRunning)) {
			Sleep(10);
		}
		Sleep(1000);
		while ((!m_StopAcquiring) && (pProc->State != stateRunning)) {
			Sleep(10);
		}

		while ((!m_StopAcquiring) && (nfound || (lnth==0) || (adrs==0))) {
			ActPoint=-1;
			// wait till the processor is running
			while ((!m_StopAcquiring) && (pProc->State != stateRunning)) {
				Sleep(10);
			}
			if (m_StopAcquiring) break;
			IADspBtcChannelListPtr pBtcChannelList = pBtcManager->ChannelList((long)0);
			DWORD dwChanCount = pBtcChannelList->Count;

			for (DWORD i = 0; i < dwChanCount; ++i)	{
				ActPoint=0;
				// wait till the processor is running
				while ((!m_StopAcquiring) && (pProc->State != stateRunning)) {
					Sleep(10);
				}
				if (m_StopAcquiring) break;
				IADspBtcChannelPtr pBtcChannel = pBtcChannelList->GetItem((long)i);

				_bstr_t bstrSupportedWidths = "";
				DWORD dwSupportedWidths = pBtcChannel->SupportedWidths;
				if (dwSupportedWidths & btcWidth32) {
					if (strcmp("TRACE_DATA_STRUCT",OLE2A(pBtcChannel->Name))==0) {
						adrs = pBtcChannel->Address;
						lnth = pBtcChannel->Length;
						nfound = 0;
						break;
					}
				}

			}

		}
		if (m_StopAcquiring) lnth = 0;
		if (lnth>0) {

			rdbuf = (unsigned int *)malloc(((lnth+3)>>2)<<2);
		}
		if ((lnth>0) && (rdbuf!=NULL)) {
			{
				// set the acquiring data to be all ones
				LPSAFEARRAY psaWrite = SafeArrayCreateVector( VT_VARIANT, 0, 9 );

				int cj = -1;
				long i;
				for( i=0; i<9; i++ ) {
					CComVariant var = cj;
					SafeArrayPutElement( psaWrite, &i, &var );
				}

				CComVariant varWrArray;
				varWrArray.vt = VT_ARRAY|VT_VARIANT;
				varWrArray.parray = psaWrite;

				ActPoint=1;
				// wait till the processor is running
#if 0
				while ((!m_StopAcquiring) && (pProc->State != stateRunning)) {
					Sleep(10);
				}
				if (m_StopAcquiring) break;

				Sleep(1000);
#endif
				// wait till the processor is running
				while ((!m_StopAcquiring) && (pProc->State != stateRunning)) {
					Sleep(10);
				}
				if (!m_StopAcquiring) {
					pBtcManager->Write((long)0, (long)0, adrs, 9, btcWidth32, varWrArray);
				}
			}

			maxlnth = lnth - (sizeof(TraceData) -1  - offsetof(TraceData,MaxTrcBytes));
			maxlnth = (maxlnth+3)&(~0x3);
			maxelem = maxlnth >> 2;			// no. of integers

			while (!m_StopAcquiring) {
				// loop reading the thread data info
				CComVariant varRdArray;

				ActPoint=2;
				while ((!m_StopAcquiring) && (pProc->State != stateRunning)) {
					Sleep(10);
				}
				if (m_StopAcquiring) break;

				nwords = 0;
				actionok = 1;
				try {
					varRdArray = pBtcManager->Read((long)0, (long)0, adrs+9*sizeof(int), maxelem, btcWidth32);
				} catch ( _com_error err )
				{
					actionok = 0; 
				}
				if ((actionok) && (varRdArray.vt != VT_EMPTY))
				{
					CComVariant va;
					indx = 1;

					SafeArrayGetElement(varRdArray.parray,&indx,&va);
					nbytes = V_UI4(&va);
					nwords = (nbytes+3)>>2;
					if (nwords<=maxelem) {
						for (indx = 0; indx<nwords+2;indx++) {
							CComVariant va;

							SafeArrayGetElement(varRdArray.parray,&indx,&va);
							rdbuf[indx] = V_UI4(&va);
						}
					} else {
						nwords = 0;		// ignore if more than is valid
					}
				} else {
					nwords = 0;
				}
				if (nwords>0) {
					// we have got the data 
					unsigned int max,no;

					max = rdbuf[0];
					no = rdbuf[1];

					if ((no>0) && (no<=max) && 
						(no<=  (lnth-(sizeof(TraceData) - offsetof(TraceData,MaxTrcBytes))-2*sizeof(int)))
									) {
						unsigned char *buf = (unsigned char *)(rdbuf+2);
						unsigned int nxt,cnt=0;
						
						// process the data
						nxt = 0;
						while (nxt<no) {
							cnt++;
							if (cnt>80) {
								int gg=3;
							}
							// we have a complete trace to dump
							DumpTraceEntry(buf+nxt);
							nxt = nxt + buf[nxt+1]+4;
						}


						// tell the DSP the data has been processed
						{
							// set the acquiring data to zero
							LPSAFEARRAY psaWrite = SafeArrayCreateVector( VT_VARIANT, 0, 1 );

							int cj = 0x0;
							long i;
							for( i=0; i<1; i++ ) {
								CComVariant var = cj;
								SafeArrayPutElement( psaWrite, &i, &var );
							}

							CComVariant varWrArray;
							varWrArray.vt = VT_ARRAY|VT_VARIANT;
							varWrArray.parray = psaWrite;

							ActPoint=3;
							while ((pProc->State != stateRunning)) {
								Sleep(10);
							}
							pBtcManager->Write((long)0, (long)0, adrs+10*sizeof(int), 1, btcWidth32, varWrArray);
						}
					}

				}	// end of processing the read data

			}	// end of acquiring data 

			{
				// set the acquiring data control to zero
				LPSAFEARRAY psaWrite = SafeArrayCreateVector( VT_VARIANT, 0, 9 );

				int cj = 0x0;
				long i;
				for( i=0; i<9; i++ ) {
					CComVariant var = cj;
					SafeArrayPutElement( psaWrite, &i, &var );
				}

				CComVariant varWrArray;
				varWrArray.vt = VT_ARRAY|VT_VARIANT;
				varWrArray.parray = psaWrite;

				ActPoint =4;
				while (pProc->State != stateRunning) {
					Sleep(10);
				}

				try {
					pBtcManager->Write((long)0, (long)0, adrs, 9, btcWidth32, varWrArray);
				} catch ( _com_error err )
				{
					actionok = 0; 
				}
			}




		}

		pBtcPlugin->Close(pBtcManager);

		if (rdbuf) free(rdbuf);

	} catch ( _com_error err )
	{
		AfxMessageBox(err.ErrorMessage()); 
	}

	CoUninitialize();	
	
	m_Stopped = true;





}




int SetUpListen(int portno,SOCKET *sock)
{
	SOCKET WinSocket;
	char szError[512];
	SOCKADDR_IN local_sin;

	*sock = INVALID_SOCKET;

	WinSocket = socket(AF_INET, SOCK_STREAM, 0);

	if (WinSocket == INVALID_SOCKET) 
	{
	  wsprintf (szError, TEXT("Allocating socket failed. Error: %d"), 
				WSAGetLastError ());
	  MessageBox (NULL, szError, TEXT("Error"), MB_OK);
	  return FALSE;
	}
	// Fill out the local socket address data.
   	memset((char *)&local_sin,0,sizeof(local_sin));
	local_sin.sin_family = AF_INET;
	local_sin.sin_port = htons (portno);
	local_sin.sin_addr.s_addr = INADDR_ANY;

	// Associate the local address with WinSocket.
	if (bind (WinSocket, 
			  (struct sockaddr *) &local_sin, 
			  sizeof (local_sin)) == SOCKET_ERROR) 
	{
	  wsprintf (szError, TEXT("Binding socket failed. Error: %d"), 
				WSAGetLastError ());
	  MessageBox (NULL, szError, TEXT("Error"), MB_OK);
	  closesocket (WinSocket);
	  return FALSE;
	}
	if (listen (WinSocket, 5) == SOCKET_ERROR) 
	{
	  wsprintf (szError, 
				TEXT("Listening to the client failed. Error: %d"),
				WSAGetLastError ());
	  MessageBox (NULL, szError, TEXT("Error"), MB_OK);
	  closesocket (WinSocket);
	  return FALSE;
	}
	*sock = WinSocket;
	return 1;
}


void CTCPIPTrcDlg::TcpRecv(void)
{


	typedef struct TraceData {
		unsigned int			Active;				// if non-zero some tracing is active
		unsigned int			ActClasses[8];		// Each bit represents one of 256 trace classes
		unsigned int			MaxTrcBytes;		// maximum number of trace bytes
		unsigned int			NoTrcBytes;			// the no of trace bytes to be read by the host
		unsigned char			TrcBytes[1];		// start of the trace buffer
						
	} TraceData;
	SOCKET lstn,client;
	SOCKADDR_IN accept_sin;
	int accept_sin_len;
	//char szError[512];
#define BUFSIZE 0x10000
	unsigned char buffer[BUFSIZE];

	m_Stopped = false;

	if (SetUpListen(m_Channel,&lstn)) {
		m_Listen = lstn;

		m_ReportCtrl.SetWindowText("");
		while (!m_StopAcquiring) {
			accept_sin_len = sizeof (accept_sin);

			// Accept an incoming connection attempt on WinSocket.
			m_Client = client = accept (lstn, 
								 (struct sockaddr *) &accept_sin, 
								 (int *) &accept_sin_len);

			if (client == INVALID_SOCKET) 
			{
			  //wsprintf (szError, TEXT("Accepting connection with client failed.") TEXT(" Error: %d"), WSAGetLastError ());
			  //::MessageBox (NULL, szError, TEXT("Error"), MB_OK);
			  break;
			} else {
				int req[9];
				int lnth,nxt,nnxt;
				BOOL bOptVal = TRUE;
				int bOptLen = sizeof(BOOL);
				char cname[256];
				char rep[512];


				strcpy(cname,inet_ntoa(accept_sin.sin_addr));
				strcpy(rep,"Tracing is coming from ");
				strcat(rep,cname);
				m_ReportCtrl.SetWindowText(rep);

				// process the data
				setsockopt(client, SOL_SOCKET, SO_KEEPALIVE, (char*)&bOptVal, bOptLen); // detect when other end fails
				// send the start tracing request
				memset(req,0xff,sizeof(req));
				lnth = send(client,(const char *)req,sizeof(req),0);
				if (lnth==sizeof(req)) {
					// trace start sent
					nxt = 0;
					while (!m_StopAcquiring) {
						// process the data
						lnth = recv(client,(char *)(buffer+nxt),BUFSIZE-nxt,0);
						if (lnth<0) {
							m_Client = INVALID_SOCKET;
							closesocket(client);
							client = INVALID_SOCKET;
							break;
						} else {
							lnth += nxt;
							nxt = 0;
							while (nxt<lnth) {
								nnxt = nxt+buffer[nxt+1]+4;
								if (nnxt<=lnth) {
									// we have a complete trace to dump
									DumpTraceEntry(buffer+nxt);
									nxt = nxt + buffer[nxt+1]+4;
									if (nxt >= lnth) {
										nxt = 0;
										lnth = 0;
									}
								} else {
									// only a partial trace entry present
									memcpy(buffer,buffer+nxt,lnth-nxt);
									nxt = lnth-nxt;
									lnth =0;
								}
							}
						}

					}
					// send stop tracing
					if (client != INVALID_SOCKET) {
						memset(req,0,sizeof(req));
						lnth = send(client,(const char *)req,sizeof(req),0);
					}
				}
				if (m_Client != INVALID_SOCKET) {
					m_Client = INVALID_SOCKET;
					closesocket(client);
				}
				m_ReportCtrl.SetWindowText("");
			}
		}
		// Stop listening for connections from clients.
		closesocket (lstn);


	} else {
		// listen failed
	}
	m_Stopped = true;

}


VOID ReaderThread(LPVOID lpvParam)
{
	CTCPIPTrcDlg *dlg = (CTCPIPTrcDlg *)lpvParam;

	if (dlg->m_Channel == 0) {
		dlg->Recv();
	} else {
		dlg->TcpRecv();
	}

}




void CTCPIPTrcDlg::OnSaveall() 
{
	if (m_Trc!=NULL) {
		char em[512];

		fclose(m_Trc);
		m_Trc = NULL;
		sprintf("Traced events have been saved in %s",m_SaveAlFileName);
		MessageBox(em,"TCP/IP Tracing");

	} else {
		// we need to open the trace file
		char filename[512];

		m_FileNameCtrl.GetWindowText(filename,sizeof(filename));
		if (filename[0]==0) {
			OPENFILENAME fn;

			memset(&fn,0,sizeof(fn));
			fn.lStructSize = sizeof(fn);
			fn.lpstrFilter = "Trace dump files\x00*.trc\x00";
			fn.lpstrFile = filename;
			fn.nMaxFile = sizeof(filename);
			fn.lpstrTitle = "File the trace information is to be saved to";
			fn.Flags = OFN_CREATEPROMPT|OFN_LONGNAMES|OFN_PATHMUSTEXIST|OFN_OVERWRITEPROMPT;
			if (GetSaveFileName(&fn)) {
				m_FileNameCtrl.SetWindowText(filename);
			}
		}
		m_FileNameCtrl.GetWindowText(filename,sizeof(filename));
		if (filename[0]!=0) {
			strcpy(m_SaveAlFileName,filename);
			m_Trc =  fopen(filename,"w");
			if (m_Trc == NULL) {
				char err[1024];
				sprintf(err,"Unable to open %s for writing",filename);
				MessageBox(err,"TCP/IP Tracing");
			} else {
				SaveTraceFileIntoRegistry(filename);
			}
		}

	}
	
}
