Click here to Skip to main content
15,897,518 members
Articles / Programming Languages / C++

How Proxy Server serves FTP clients?

Rate me:
Please Sign up or sign in to vote.
4.80/5 (23 votes)
10 Feb 2005CPOL7 min read 211.2K   5.4K   62  
This article describes how Proxy Server deals with PORT and PASV FTP commands
// LiteProxyServerView.cpp : implementation of the CLiteProxyServerView class
//

#include "stdafx.h"
#include "LiteProxyServer.h"

#include "LiteProxyServerDoc.h"
#include "LiteProxyServerView.h"
#include "request.h"
#include "Listener.h"
#include "Iphlpapi.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

CPtrList gptrArryTempListeners;

/////////////////////////////////////////////////////////////////////////////
// CLiteProxyServerView

IMPLEMENT_DYNCREATE(CLiteProxyServerView, CListView)

BEGIN_MESSAGE_MAP(CLiteProxyServerView, CListView)
	//{{AFX_MSG_MAP(CLiteProxyServerView)
	ON_WM_CREATE()
	ON_COMMAND(ID_FILE_NEW, OnFileNew)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CLiteProxyServerView construction/destruction

CLiteProxyServerView::CLiteProxyServerView()
{
	m_pListener = NULL;
}

CLiteProxyServerView::~CLiteProxyServerView()
{
	// shutdown all listeners
	delete m_pListener;

	for(POSITION pos = gptrArryTempListeners.GetHeadPosition(); pos;)
	{
		try
		{
			Listener* pListener = (Listener*)gptrArryTempListeners.GetNext(pos);
			delete pListener;
		}
		catch(...)
		{
		}
	}
}

BOOL CLiteProxyServerView::PreCreateWindow(CREATESTRUCT& cs)
{
	cs.style |= LVS_REPORT | LVS_SHOWSELALWAYS;

	return CListView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CLiteProxyServerView drawing

void CLiteProxyServerView::OnDraw(CDC* pDC)
{
	CLiteProxyServerDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here
}

void CLiteProxyServerView::OnInitialUpdate()
{
	CListView::OnInitialUpdate();
	
	GetNetworkParams();
}

/////////////////////////////////////////////////////////////////////////////
// CLiteProxyServerView diagnostics

#ifdef _DEBUG
void CLiteProxyServerView::AssertValid() const
{
	CListView::AssertValid();
}

void CLiteProxyServerView::Dump(CDumpContext& dc) const
{
	CListView::Dump(dc);
}

CLiteProxyServerDoc* CLiteProxyServerView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CLiteProxyServerDoc)));
	return (CLiteProxyServerDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CLiteProxyServerView message handlers

CLiteProxyServerView *gpView;

int CLiteProxyServerView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CListView::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	gpView = this;

	m_pList = &GetListCtrl();
	ListView_SetExtendedListViewStyle(m_pList->m_hWnd, LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
	m_pList->InsertColumn(0, "Serial", LVCFMT_LEFT, 60, -1);
	m_pList->InsertColumn(1, "Date", LVCFMT_CENTER, 105, -1);
	m_pList->InsertColumn(2, "Name", LVCFMT_LEFT, 100, -1);
	m_pList->InsertColumn(3, "Request", LVCFMT_LEFT, 160, -1);
	m_pList->InsertColumn(4, "Received", LVCFMT_RIGHT, 60, -1);
	m_pList->InsertColumn(5, "Sent", LVCFMT_RIGHT, 55, -1);
	m_pList->InsertColumn(6, "Content-Length", LVCFMT_RIGHT, 65, -1);
	m_pList->InsertColumn(7, "Status", LVCFMT_LEFT, 110, -1);
	m_pList->InsertColumn(8, "Time (ms)", LVCFMT_RIGHT, 60, -1);

	CBitmap bitmap;
	bitmap.LoadBitmap(IDB_LIST);
	m_imageList.Create(16, 15, ILC_COLOR24, 11, 0);
	m_imageList.Add(&bitmap, (CBitmap*)NULL);
	m_pList->SetImageList(&m_imageList, 1);

	return 0;
}

struct TwoWayStruct
{
	TwoWayStruct(SOCKET Server, SOCKET Client, bool bNormal, Request* p)
	{
		SockServer = Server;
		SockClient = Client;
		bSockNormal = bNormal;
		pRequest = p;
	}
	~TwoWayStruct()
	{
		if(bSockNormal)
		{
			shutdown(SockClient, 2);
			closesocket(SockClient);
			if(SockServer)
			{
				shutdown(SockServer, 2);
				closesocket(SockServer);
			}
		}
		if(--pRequest->nRefCount == 0)
		{
			gpView->UpdateLog(pRequest->nLogID, 8, Commas(::GetTickCount()-pRequest->nTime));
			delete pRequest;
		}
	}

	SOCKET SockServer;
	SOCKET SockClient;
	bool bSockNormal;
	Request* pRequest;
};

#define ERROR_INVALIDIP			0
#define ERROR_BLOCKEDIP			1
#define ERROR_BLOCKEDFUNCTION	2
#define ERROR_BLOCKEDSIZE		3
#define ERROR_BLOCKEDEXTENSION	4
#define ERROR_BLOCKEDURLWORD	5
#define ERROR_BLOCKEDSITE		6

void SendError(SOCKET sock, int nErrorCode, CString strInfo)
{
	CString str = "HTTP/1.0 200 OK\r\n\r\n<title>Proxy server alert</title><Body><br>";
	switch(nErrorCode)
	{
	case ERROR_INVALIDIP:
		str += "None registered IP ("+strInfo+")";
		break;
	case ERROR_BLOCKEDIP:
		str += "You ("+strInfo+") are blocked.";
		break;
	case ERROR_BLOCKEDFUNCTION:
		str += "The function ("+strInfo+") is not authorized to you.";
		break;
	case ERROR_BLOCKEDSIZE:
		str += "Your request exceeded maximum allowed size ("+strInfo+").";
		break;
	case ERROR_BLOCKEDEXTENSION:
		str += "Request extension ("+strInfo+") is not authorized to you.";
		break;
	case ERROR_BLOCKEDURLWORD:
		str += "Request url includes restricted words ("+strInfo+"), if u want to view it any way,";
		break;
	case ERROR_BLOCKEDSITE:
		str += strInfo+"<br>If you want to view it any way,";
		break;
	}
	str += "<br>Please, Contact the network administrator.</Body>";
	send(sock, str, str.GetLength(), 0);
}

CCriticalSection cs;

CString Time2String(CTime &time)
{
	CString str = "If-Modified-Since: "+time.FormatGmt("%A").Left(3)+time.FormatGmt(", %d ")+time.FormatGmt("%B").Left(3)+time.Format(" %Y %H:%M:%S")+" GMT";
	return str;
}

CString strMonthes = "janfebmaraprmayjunjulaugsepoctnovdec";
CTime String2Time(CString str)
{
	if(str.GetLength() != 29)
		return CTime(0);
	str.MakeLower();

	return CTime(atoi(str.Mid(12)), (strMonthes.Find(str.Mid(8,3))+1)/3+1, atoi(str.Mid(5)), atoi(str.Mid(17)), atoi(str.Mid(20)), atoi(str.Mid(23)));
}

int RequestSend(Request* pRequest, SOCKET s, char* buf, int len)
{
	return send(s, buf, len, 0);
}

int RequestRecv(Request* pRequest, SOCKET s, char* buf, int len)
{
	int nBytes = recv(s, buf, len, 0);
	if(nBytes > 0)
		buf[nBytes] = 0;
	else
		buf[0] = 0;
	return nBytes;
}

UINT TwoWayThread(void* lpv)
{
	TwoWayStruct* pTWS = (TwoWayStruct*)lpv;
	try
	{
		int nLogID = pTWS->pRequest->nLogID;
		if(pTWS->bSockNormal)
			theApp.m_nInProgress++;
		int nBytes = 0, nTotal = 0;
		char by[10240] = "";
		bool bUpdateLog = true;

		while(true)
		{
			nBytes = 10240;
			// retrieve from server
			if(pTWS->SockServer)
				// normal proxy step
				nBytes = recv(pTWS->SockServer, by, 10240, 0);
			if(nBytes <= 0)
				break;

			gpView->UpdateLog(nLogID, pTWS->bSockNormal ? 4 : 5, nTotal += nBytes);	
		
			if(pTWS->pRequest->nAppProtocol == Listener::ApplicationProtocol::TYPE_FTP)
			{
				bool bPasv = false, bPort = false;
				if(pTWS->bSockNormal)
				{
					// some clients don't send "anonymous" for anonymous connections
					if(memicmp(by, "USER ", 5) == 0 && nBytes == 7)
						memcpy(by+5, "anonymous\r\n", 11), nBytes+= 9;
					// check for PASV mode
					bPasv = memcmp(by, "227 ", 4) == 0;
				}
				else
					// check for PORT mode
					bPort = memicmp(by, "PORT ", 5) == 0;
				if(bPasv || bPort)
				{
					CString str = CString(by, nBytes), strSend;
					int n[7] = { str.Find(bPasv?'(':' '), str.Find(',', n[0]), str.Find(',', n[1]+1), str.Find(',', n[2]+1), str.Find(',', n[3]+1), str.Find(',', n[4]+1), str.Find(bPasv?')':'\r', n[5]) };
					CString strNewIP = gpView->m_strArrayIP[bPasv?gpView->m_strArrayIP.GetSize()-1:0];
					strNewIP.Replace('.', ',');
					// PASV: replace the server listener IP with LAN IP
					// PORT: replace the client listener IP with WAN IP
					strSend.Format("%s%s%s", str.Left(n[0]+1), strNewIP, str.Mid(n[4]));
					// copy command to its packet after replacment
					memcpy(by, strSend, nBytes = strSend.GetLength());

					Listener* pListener = new Listener;
					gptrArryTempListeners.AddTail(pListener);
					pListener->nPort = atoi(str.Mid(n[4]+1, n[5]-n[4]-1))*256+atoi(str.Mid(n[5]+1, n[6]-n[5]-1));
					pListener->nNextServerPort = pListener->nPort;
					// adjust the listener next proxy to the command listener
					pListener->strNextServerIP = str.Mid(n[0]+1, n[4]-n[0]-1);
					pListener->strNextServerIP.Replace(',', '.');
					pListener->nAppProtocol = Listener::ApplicationProtocol::TYPE_FTP_PASV+bPort;
					pListener->StartListen();
				}
			}
			// normal proxy step
			if(pTWS->SockClient && send(pTWS->SockClient, by, nBytes, 0) == SOCKET_ERROR)
			{
				if(pTWS->bSockNormal)
				{
					gpView->UpdateLog(nLogID, 7, CString(pTWS->pRequest->pFileCache?(pTWS->pRequest->bRequestServer ? "Online Proxy Cache " : "Offline Proxy Cache "):"")+"Canceled");
					bUpdateLog = false;
				}
				break;
			}
		}
		if(pTWS->bSockNormal)
		{
			theApp.m_nReceivedBytes += nTotal;
			pTWS->pRequest->nReceived += nTotal;
		}
		else
		{
			theApp.m_nSentBytes += nTotal;
			pTWS->pRequest->nSent += nTotal;
		}
		if(pTWS->bSockNormal && bUpdateLog == true)		
		{
			if(nTotal == SOCKET_ERROR)
				gpView->UpdateLog(nLogID, 7, "Failed");
			else
				gpView->UpdateLog(nLogID, 7, "Success");
		}
	}
	catch(...)
	{
	}
	if(pTWS->bSockNormal)
		theApp.m_nInProgress--;
	delete pTWS;		

	return 0;
}

bool ConnectHost(SOCKET &s, Request* pRequest)
{
	if(pRequest->nLogID == -1)
	{
		CString str;
		str.Format("%s %s:%d", sAppProtocolTypes[pRequest->nAppProtocol], pRequest->strHost, pRequest->nPort);
		pRequest->nLogID = gpView->Log(pRequest, str);
	}

	sockaddr_in host;
	host.sin_family = AF_INET;
	host.sin_port = htons(pRequest->nPort);
	if(inet_addr(pRequest->strHost) == INADDR_NONE )  // connect to the appropriate server
	{
		hostent* hp = gethostbyname(pRequest->strHost); // server address is a DNS name
		if(hp == NULL)
		{			
			gpView->UpdateLog(pRequest->nLogID, 7, "Failed to resolve "+pRequest->strHost);
			return false;
		}		
		host.sin_addr.s_addr = *((unsigned long *) hp->h_addr);
	}
	else
		host.sin_addr.s_addr = inet_addr(pRequest->strHost); // directly use the IP address

	gpView->UpdateLog(pRequest->nLogID, 7, "Connecting "+pRequest->strHost);
	if(connect(s, (sockaddr*)&host, sizeof(host)) == SOCKET_ERROR)
	{
		gpView->UpdateLog(pRequest->nLogID, 7, "Failed to Connect " + pRequest->strHost);
		return false;
	}
	return true;
}

void HostPort(CString &strHost, INTERNET_PORT &nPort)
{
	int nIndex;
	if((nIndex = strHost.Find(':')) != -1)
	{
		nPort = atoi(strHost.Mid(nIndex+1));
		strHost = strHost.Left(nIndex);
	}
}

UINT StartRequest(void* lpv)
{
	Request *pRequest = (Request *)lpv;
	pRequest->nTime = ::GetTickCount();
	SOCKET SocketClient = pRequest->socket;
	try
	{
		SOCKET SocketHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		pRequest->strIP = inet_ntoa(pRequest->address.sin_addr);
		bool bFtpPortCmd = pRequest->pListener->nAppProtocol == Listener::ApplicationProtocol::TYPE_FTP_PORT;
		int nIndex;
		CString str;

		if(pRequest->pListener->strNextServerIP.IsEmpty() == false)
		{
			pRequest->strHost = pRequest->pListener->strNextServerIP;
			pRequest->nPort = pRequest->pListener->nNextServerPort;
			if(ConnectHost(SocketHost, pRequest) == false)
				goto END_REQUEST;
		}
		else	if(pRequest->nAppProtocol == Listener::ApplicationProtocol::TYPE_HTTP)
		{
		}
		else	if(pRequest->nAppProtocol == Listener::ApplicationProtocol::TYPE_FTP)
		{
			send(SocketClient, "220 FTP Virtual Server\r\n", 24, 0);
			pRequest->nPort = 21;
			CString strPass;
			while(true)
			{
				pRequest->nLength = recv(SocketClient, str.GetBuffer(1024), 1024, 0);
				str.ReleaseBuffer(pRequest->nLength);
				if(memicmp(str, "USER", 4) == 0)
				{
					if((nIndex = str.Find("@")) != -1)
					{
						pRequest->strHost = str.Mid(nIndex+1);
						pRequest->strHost.TrimRight();
						HostPort(pRequest->strHost, pRequest->nPort);
						pRequest->strRequest = str.Left(nIndex)+"\r\n";
						break;
					}
					else
					{
						pRequest->strRequest = str;
						str.TrimRight();
						if(str.GetLength() == 4)
							pRequest->strRequest.Insert(5, "anonymous");
						// if host still not found then ask for login password
						send(SocketClient, "331 send password.\r\n", 20, 0);
					}
				}
				else	if(memicmp(str, "SITE", 4) == 0 || memicmp(str, "OPEN", 4) == 0)
				{
					if((nIndex = str.Find(" ")) == -1)
						goto END_REQUEST;
					pRequest->strHost = str.Mid(nIndex+1);
					pRequest->strHost.TrimRight();
					HostPort(pRequest->strHost, pRequest->nPort);
					break;
				}
				else	if(memicmp(str, "PASS", 4) == 0)
				{
					strPass = str;
					send(SocketClient, "230 Login OK. Proceed.\r\n", 24, 0);
				}
				else
					break;
			}

			// connect to ftp server
			if(ConnectHost(SocketHost, pRequest) == false)
				goto END_REQUEST;
			if(pRequest->strRequest.IsEmpty() == false)
			{
				// Receive ready command
				RequestRecv(pRequest, SocketHost, str.GetBuffer(1024), 1024);
				// send USER command
				RequestSend(pRequest, SocketHost, pRequest->strRequest.GetBuffer(0), pRequest->strRequest.GetLength());
				if(strPass.IsEmpty() == false)
				{
					// Receive reply of USER command
					nIndex = RequestRecv(pRequest, SocketHost, str.GetBuffer(1024), 1024);
					str.ReleaseBuffer(nIndex);
					// send password
					RequestSend(pRequest, SocketHost, strPass.GetBuffer(0), strPass.GetLength());
				}
			}
		}
		else	if(pRequest->nAppProtocol == Listener::ApplicationProtocol::TYPE_NNTP)
		{
		}
		else	if(pRequest->nAppProtocol == Listener::ApplicationProtocol::TYPE_DNS)
		{
		}
		else	if(pRequest->nAppProtocol == Listener::ApplicationProtocol::TYPE_SMTP_SERVER)
		{
		}
		else	if(pRequest->nAppProtocol == Listener::ApplicationProtocol::TYPE_SOCKS4)
		{
		}
		else	if(pRequest->nAppProtocol == Listener::ApplicationProtocol::TYPE_SOCKS5)
		{
		}
		
		gpView->UpdateLog(pRequest->nLogID, 7, "In progress...");
		// gets ready to relay traffic on both directions
		AfxBeginThread(TwoWayThread, new TwoWayStruct(SocketHost, SocketClient, !bFtpPortCmd, pRequest));
		AfxBeginThread(TwoWayThread, new TwoWayStruct(SocketClient, SocketHost, bFtpPortCmd, pRequest));

		return 0;
	}
	catch(...)
	{
	}

END_REQUEST:
	shutdown(SocketClient, 2);
	closesocket(SocketClient);
	gpView->UpdateLog(pRequest->nLogID, 8, Commas(::GetTickCount()-pRequest->nTime));
	delete pRequest;

	return 1;
}

UINT StartListenThread(void* lpv)
{
	CString str;
	Listener* pListener = (Listener*)lpv;
	int nType;
	if(pListener->nTransProtocol == Listener::TransportProtocol::TYPE_TCP)
		nType = SOCK_STREAM;
	else	if(pListener->nTransProtocol == Listener::TransportProtocol::TYPE_UDP)
		nType = SOCK_DGRAM;
	pListener->socketServer = socket(AF_INET, nType, 0);
	if(pListener->socketServer == INVALID_SOCKET)
	{
		pListener->pThread = NULL;
		if(pListener->IsTemp() == false)
			AfxMessageBox("Fail to create listener socket");
		return 1;
	}
	sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = INADDR_ANY;
	addr.sin_port = htons((u_short)pListener->nPort); // listen this port
	if(bind(pListener->socketServer, (sockaddr *)&addr, sizeof(addr)) != 0)
	{
		pListener->pThread = NULL;
		str.Format("Socket bind failed: port %d", pListener->nPort);
		if(pListener->IsTemp() == false)
			AfxMessageBox(str);
		return 1;
	}
	if(pListener->nTransProtocol == Listener::TransportProtocol::TYPE_TCP)
		if(listen(pListener->socketServer, SOMAXCONN) != 0)
		{
			pListener->pThread = NULL;
			str.Format("Fail to start listening: port %d", pListener->nPort);
			if(pListener->IsTemp() == false)
				AfxMessageBox(str);
			return 1;
		}

	int nLength;
	do
	{
		Request *pRequest = new Request;
		pRequest->pListener = pListener;
		pRequest->nAppProtocol = pListener->nAppProtocol;
		pRequest->nTransProtocol = pListener->nTransProtocol;
		nLength = sizeof(pRequest->address);
		if(pListener->nTransProtocol == Listener::TransportProtocol::TYPE_TCP)
		{
			if((pRequest->socket = accept(pListener->socketServer, (sockaddr*)&pRequest->address, &nLength)) != INVALID_SOCKET && pListener->pThread)
				AfxBeginThread(StartRequest, (LPVOID)pRequest);
		}
		else	if(pListener->nTransProtocol == Listener::TransportProtocol::TYPE_UDP)
		{
		}
		else
			break;
	}
	while(pListener->pThread && pListener->IsTemp() == false);
	pListener->pThread = NULL;

	return 0; 
}

void Listener::StartListen()
{
	if(pThread)
		return;
	pThread = AfxBeginThread(StartListenThread, this);
}

void Listener::StopListen()
{
	if(pThread == NULL)
		return;
	shutdown(socketServer, 2);
	closesocket(socketServer);
	if(pThread)
	{
		::TerminateThread(pThread, 0);
		pThread = NULL;
	}
}

int CLiteProxyServerView::Log(Request* pRequest, LPCSTR lpcsLog)
{
	int nItemCount = m_pList->GetItemCount();
	try
	{
		CString str;
		str.Format("%s", Commas(nItemCount+1));
		m_pList->InsertItem(nItemCount, str, pRequest->nAppProtocol ? pRequest->nAppProtocol : -1);
		m_pList->SetItemText(nItemCount, 1, CTime::GetCurrentTime().Format("%c"));
		m_pList->SetItemText(nItemCount, 2, pRequest->strIP);
		m_pList->SetItemText(nItemCount, 3, lpcsLog);
		if(m_bEnsureVisible)
			m_pList->EnsureVisible(nItemCount, FALSE);
	}
	catch(...)
	{
	}

	return nItemCount;
}

void CLiteProxyServerView::UpdateLog(int nLogID, int nCol, int nLength)
{
	if(nLogID < 0 || nLogID >= m_pList->GetItemCount())
		return;

	m_pList->SetItemText(nLogID, nCol, Commas(nLength));
}

void CLiteProxyServerView::UpdateLog(int nLogID, int nCol, LPCSTR lpcs)
{
	if(nLogID < 0 || nLogID >= m_pList->GetItemCount())
		return;

	m_pList->SetItemText(nLogID, nCol, lpcs);
}

void CLiteProxyServerView::OnFileNew()
{
	theApp.m_nInProgress = 0;
	m_pList->DeleteAllItems();
}

void CLiteProxyServerView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) 
{
	if(lHint == 0)
	{
		if(m_pListener != NULL)
			delete m_pListener;
		m_pListener = new Listener;
		m_pListener->nAppProtocol = Listener::ApplicationProtocol::TYPE_FTP;
		m_pListener->nTransProtocol = Listener::TransportProtocol::TYPE_TCP;
		m_pListener->nPort = 21;
		m_pListener->StartListen();
	}
	else	if(lHint == 1)
	{
		delete m_pListener;
		m_pListener = NULL;
	}
}

void CLiteProxyServerView::GetNetworkParams()
{
	try
	{
		m_strArrayDNS.RemoveAll();
		ULONG pOutBufLen = 0;
		::GetNetworkParams(NULL, &pOutBufLen);
		FIXED_INFO* pInfo = new FIXED_INFO[pOutBufLen/sizeof(FIXED_INFO)+1];
		if(ERROR_SUCCESS == ::GetNetworkParams(pInfo, &pOutBufLen))
		{
			IP_ADDR_STRING* pNext = &pInfo[0].DnsServerList;	
			do	m_strArrayDNS.Add(pNext->IpAddress.String);
			while(pNext = pNext->Next);
		}
		delete []pInfo;

		m_strArrayIP.RemoveAll();
		DWORD dwError;
		ULONG pdwSize = 0;
		GetIpAddrTable(NULL, &pdwSize, TRUE); 
		PMIB_IPADDRTABLE pIpAddrTable = new MIB_IPADDRTABLE[pdwSize/sizeof(MIB_IPADDRTABLE)+1];
		if((dwError = GetIpAddrTable(pIpAddrTable, &pdwSize, TRUE)) == NO_ERROR)
			for(int nIndex = 0; nIndex < (int)pIpAddrTable[0].dwNumEntries; nIndex++)
			{
				CString strIP = inet_ntoa((in_addr&)pIpAddrTable[0].table[nIndex].dwAddr);
				if(strIP != "127.0.0.1" && strIP != "0.0.0.0")
					m_strArrayIP.Add(strIP);
			}
		delete []pIpAddrTable;
	}
	catch(...)
	{
		AfxMessageBox("Failed in GetNetworkParams()");
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Egypt Egypt

Comments and Discussions