Click here to Skip to main content
15,897,187 members
Articles / High Performance Computing / Parallel Processing

Use of free SocketPro package for creating super client and server applications

Rate me:
Please Sign up or sign in to vote.
4.48/5 (19 votes)
23 Feb 200211 min read 181.3K   6.3K   59  
A set of socket libraries for writing distributed computing applications over the internet
// DNS.cpp : Implementation of CDNS
#include "stdafx.h"
#include "DResolver.h"
#include "DNS.h"
#include "ClientSocket_i.c"
#include "ClientInfo.h"
#include <stdio.h>

//hard coded, see the defines in the file ..\extending\server\hostdnssvs.h
//#define HOST_DNS_SVS_SOCKET		0xA00100DD
/*typedef enum tagDResolverID
	{
		idGetDNSByName=			1,
		idGetDNSByAddr=			2,
		idGetCountClients	=	3,
		idGetClients =			4,
	}DResolverID;*/
/////////////////////////////////////////////////////////////////////////////
// CDNS

HRESULT	CDNS::RecvChunk(void *pBuffer, long *plRecv)
{
	CComPtr<ISktClient> pISktClient;
	HRESULT	hr=S_OK;
	VARIANT	vtData;
	VariantInit(&vtData);
	do
	{
		void	*pData;
		hr=m_pIUnknown.QueryInterface(&pISktClient);
		if(FAILED(hr))
			break;
		hr=pISktClient->RecvChunk(plRecv, 0, &vtData);
		if(FAILED(hr))
			break;
		SAFEARRAY	*psa=vtData.parray;
		hr=SafeArrayAccessData(psa, &pData);
		if(FAILED(hr))
			break;
		memcpy(pBuffer, pData, *plRecv);
		SafeArrayUnaccessData(psa);
	}while(false);
	VariantClear(&vtData);
	if(!FAILED(hr))
		hr=S_OK;
	return hr;
}

HRESULT	CDNS::SendChunk(void *pBuffer, long nSize, long *plSent)
{
	CComPtr<ISktClient> pISktClient;
	HRESULT	hr=S_OK;
	VARIANT	vtData;
	VariantInit(&vtData);
	do
	{
		void	*pData;
		hr=m_pIUnknown.QueryInterface(&pISktClient);
		if(FAILED(hr))
			break;
		SAFEARRAYBOUND	bound;
		bound.cElements=nSize;
		bound.lLbound=0;
		vtData.vt=VT_ARRAY|VT_UI1;
		SAFEARRAY	*psa=SafeArrayCreate(VT_UI1, 1, &bound);
		hr=SafeArrayAccessData(psa, &pData);
		if(FAILED(hr))
			break;
		memcpy(pData, pBuffer, nSize);
		SafeArrayUnaccessData(psa);
		vtData.parray=psa;
		hr=pISktClient->SendChunk(vtData, 0, plSent);
	}while(false);
	VariantClear(&vtData);
	if(!FAILED(hr))
		hr=S_OK;
	return hr;
}

STDMETHODIMP CDNS::GetClients()
{
	CStreamHeader	StreamHeader;
	BYTE *pBuffer=NULL;
	StreamHeader.m_nValue=idGetClients;
	CComPtr<ISktClient> pISktClient;
	Lock();
	do
	{
		long	lSent=0;
		long	lEvents;
		m_hrDNS=SendChunk(&StreamHeader, sizeof(StreamHeader), &lSent);
		if(FAILED(m_hrDNS))
			break;
		m_hrDNS=m_pIUnknown.QueryInterface(&pISktClient);
		if(FAILED(m_hrDNS))
			break;
		pISktClient->get_Events(&lEvents);
		if((lEvents & FD_READ) != FD_READ)	//if blocking mode used
		{
			UINT nCount;
			long lRecv=sizeof(StreamHeader);
			m_hrDNS=RecvChunk(&StreamHeader, &lRecv);
			if(FAILED(m_hrDNS))
				break;
			if(FAILED(StreamHeader.m_nValue))
				break;
			pBuffer=new BYTE[StreamHeader.m_nLen];
			lRecv=StreamHeader.m_nLen;
			m_hrDNS=RecvChunk(pBuffer, &lRecv);
			if(FAILED(m_hrDNS))
				break;
			if(m_bstrClients)
			{
				::SysFreeString(m_bstrClients);
				m_bstrClients=NULL;
			}
			ATLASSERT((lRecv%sizeof(CClientInfo))==0);
			nCount=lRecv/sizeof(CClientInfo);
			if(nCount)
			{
				CComBSTR	bstrClients;
				for(UINT n=0; n<nCount; n++)
				{
					BYTE	*p=pBuffer+n*sizeof(CClientInfo);
					CClientInfo* pInfo=(CClientInfo*)p;
					{
						char	strTemp[50]={0};
						unsigned short nPort=pInfo->m_nPort;
						if(n)
							sprintf(strTemp, ",%s:%d", inet_ntoa(*((in_addr*)&(pInfo->m_nIPAddr))), nPort);
						else
							sprintf(strTemp, "%s:%d", inet_ntoa(*((in_addr*)&(pInfo->m_nIPAddr))), nPort);
						bstrClients +=CComBSTR(strTemp);
					}
				}
				m_bstrClients=bstrClients.m_str;
				bstrClients.m_str=NULL;
			}
		}
	}while(false);
	if(pBuffer)
		delete []pBuffer;
	Unlock();
	return m_hrDNS;
}

STDMETHODIMP CDNS::GetCountClients()
{
	CStreamHeader	StreamHeader;
	StreamHeader.m_nValue=idGetCountClients;
	CComPtr<ISktClient> pISktClient;
	Lock();
	do
	{
		long	lSent=0;
		long	lEvents=0;
		m_hrDNS=SendChunk(&StreamHeader, sizeof(StreamHeader), &lSent);
		if(FAILED(m_hrDNS))
			break;
		m_hrDNS=m_pIUnknown.QueryInterface(&pISktClient);
		if(FAILED(m_hrDNS))
			break;
		pISktClient->get_Events(&lEvents);
		if((lEvents & FD_READ) != FD_READ)	//if blocking mode used
		{
			USES_CONVERSION;
			long lRecv=sizeof(StreamHeader);
			m_hrDNS=RecvChunk(&StreamHeader, &lRecv);
			if(FAILED(m_hrDNS))
				break;
			if(FAILED(StreamHeader.m_nValue))
				break;
			ATLASSERT(StreamHeader.m_nLen==sizeof(m_lCount));
			lRecv=sizeof(m_lCount);
			m_hrDNS=RecvChunk(&m_lCount, &lRecv);
			if(FAILED(m_hrDNS))
				break;
		}
	}while(false);
	Unlock();
	return m_hrDNS;
}

STDMETHODIMP CDNS::GetDnsByName(BSTR bstrName)
{
	CStreamHeader	StreamHeader;
	StreamHeader.m_nValue=idGetDNSByName;
	CComPtr<ISktClient> pISktClient;
	Lock();
	m_hrDNS=S_OK;
	do
	{
		USES_CONVERSION;
		long nLen=0;
		long	lEvents=0;
		CPacking	Packing;
		if(!bstrName|| (nLen=::SysStringLen(bstrName))==0)
		{
			m_hrDNS=E_UNEXPECTED;
			break;
		}
		StreamHeader.m_nLen=nLen;

		Packing.Pack(&StreamHeader, sizeof(StreamHeader));
		Packing.Pack(OLE2A(bstrName), nLen);
		m_hrDNS=SendChunk(Packing.m_pBuffer, Packing.m_nLen, &nLen);
		if(FAILED(m_hrDNS))
			break;
		m_hrDNS=m_pIUnknown.QueryInterface(&pISktClient);
		if(FAILED(m_hrDNS))
			break;

		pISktClient->get_Events(&lEvents);
		if((lEvents & FD_READ) != FD_READ)	//if blocking mode used, we need to process it now
		{
			USES_CONVERSION;
			long lRecv=sizeof(StreamHeader);
			m_hrDNS=RecvChunk(&StreamHeader, &lRecv);
			if(FAILED(m_hrDNS))
				break;
			if(FAILED(StreamHeader.m_nValue))
			{
				m_hrDNS=StreamHeader.m_nValue;
				break;
			}
			if(m_bstrHostEnt)
			{
				::SysFreeString(m_bstrHostEnt);
				m_bstrHostEnt=NULL;
			}
			lRecv=StreamHeader.m_nLen;
			if(lRecv)
			{
				char *strBuffer=new char[lRecv+1];
				m_hrDNS=RecvChunk(strBuffer, &lRecv);
				if(FAILED(m_hrDNS))
				{
					delete []strBuffer;
					break;
				}
				strBuffer[lRecv]=0;
				m_bstrHostEnt=A2BSTR(strBuffer);
				delete []strBuffer;
			}
		}
	}while(false);
	Unlock();
	return m_hrDNS;
}

STDMETHODIMP CDNS::GetDnsByAddr(BSTR bstrAddr)
{
	CStreamHeader	StreamHeader;
	StreamHeader.m_nValue=idGetDNSByAddr;
	CComPtr<ISktClient> pISktClient;
	Lock();
	m_hrDNS=S_OK;
	do
	{
		USES_CONVERSION;
		long nLen=0;
		long	lEvents=0;
		CPacking	Packing;
		if(!bstrAddr|| (nLen=::SysStringLen(bstrAddr))==0)
		{
			m_hrDNS=E_UNEXPECTED;
			break;
		}
		StreamHeader.m_nLen=nLen;

		Packing.Pack(&StreamHeader, sizeof(StreamHeader));
		Packing.Pack(OLE2A(bstrAddr), nLen);
		m_hrDNS=SendChunk(Packing.m_pBuffer, Packing.m_nLen, &nLen);
		if(FAILED(m_hrDNS))
			break;
		m_hrDNS=m_pIUnknown.QueryInterface(&pISktClient);
		if(FAILED(m_hrDNS))
			break;

		pISktClient->get_Events(&lEvents);
		if((lEvents & FD_READ) != FD_READ)	//if blocking mode used, we need to process it now
		{
			USES_CONVERSION;
			long lRecv=sizeof(StreamHeader);
			m_hrDNS=RecvChunk(&StreamHeader, &lRecv);
			if(FAILED(m_hrDNS))
				break;
			if(FAILED(StreamHeader.m_nValue))
			{
				m_hrDNS=StreamHeader.m_nValue;
				break;
			}
			if(m_bstrHostEnt)
			{
				::SysFreeString(m_bstrHostEnt);
				m_bstrHostEnt=NULL;
			}
			lRecv=StreamHeader.m_nLen;
			if(lRecv)
			{
				char *strBuffer=new char[lRecv+1];
				m_hrDNS=RecvChunk(strBuffer, &lRecv);
				if(FAILED(m_hrDNS))
				{
					delete []strBuffer;
					break;
				}
				strBuffer[lRecv]=0;
				m_bstrHostEnt=A2BSTR(strBuffer);
				delete []strBuffer;
			}
		}
	}while(false);
	Unlock();
	return m_hrDNS;
}

STDMETHODIMP CDNS::GetHostEnt(BSTR *pbstrHostEnt)
{
	Lock();
	if(!pbstrHostEnt)
	{
		m_hrDNS=E_UNEXPECTED;
		Unlock();
		return m_hrDNS;
	}
	m_hrDNS=S_OK;
	if(m_bstrHostEnt)
		*pbstrHostEnt=::SysAllocString(m_bstrHostEnt);
	Unlock();
	return S_OK;
}

STDMETHODIMP CDNS::Clients(BSTR *pbstrClients)
{
	Lock();
	if(!pbstrClients)
	{
		m_hrDNS=E_UNEXPECTED;
		Unlock();
		return m_hrDNS;
	}
	m_hrDNS=S_OK;
	if(m_bstrClients)
		*pbstrClients=::SysAllocString(m_bstrClients);
	Unlock();
	return S_OK;
}

STDMETHODIMP CDNS::Count(long *plCount)
{
	Lock();
	if(!plCount)
	{
		m_hrDNS=E_UNEXPECTED;
		Unlock();
		return m_hrDNS;
	}
	m_hrDNS=S_OK;
	*plCount=m_lCount;
	Unlock();
	return S_OK;
}

STDMETHODIMP CDNS::AttachSocket(IUnknown *pIUnknown)
{
	CComPtr<ISktClient>		pISktClient;
	CComPtr<IDResolver>		pIDResolver;
	VARIANT_BOOL			bIsConnected;
	VARIANT_BOOL			bDNSClient;
	long	hSocket=INVALID_SOCKET;
	long	hWnd=NULL;
	Lock();
	if(!pIUnknown)
	{
		m_hrDNS=E_UNEXPECTED;
		Unlock();
		return E_UNEXPECTED;
	}
	pIUnknown->QueryInterface(__uuidof(ISktClient), (void**)&pISktClient);
	if(!pISktClient.p)
	{
		m_hrDNS=E_UNEXPECTED;
		Unlock();
		return E_UNEXPECTED;
	}
	m_hrDNS=pIUnknown->QueryInterface(&pIDResolver);
	if(!FAILED(m_hrDNS))
	{
		bDNSClient=VARIANT_TRUE;
		CComPtr<IUnknown> pIUnknown;
		QueryInterface(__uuidof(IUnknown), (void**)&pIUnknown);
		if(pIUnknown.p && pIUnknown.IsEqualObject(pIUnknown))
		{
			m_hrDNS=E_UNEXPECTED;
			Unlock();
			return E_UNEXPECTED;
		}
	}
	else
		bDNSClient=VARIANT_FALSE;
	m_hrDNS=m_ClientSocketEvent.DispEventUnadvise(m_pIUnknown.p);
	if(m_pIUnknown.p)
		m_pIUnknown.Release();
	m_pIUnknown.p=pIUnknown;
	pIUnknown->AddRef();
	m_pIUnknownClientSocket=m_pIUnknown.p;
	m_pIUnknownForPointContainer=m_pIUnknown.p;
	m_hrDNS=m_ClientSocketEvent.DispEventAdvise(m_pIUnknown.p);
	if(FAILED(m_hrDNS))
	{
		Unlock();
		return m_hrDNS;
	}
	pISktClient->get_WinHandle(&hWnd);
	m_hWnd=hWnd;
	pISktClient->get_SocketHandle(&m_hSocket);
	if(bDNSClient==VARIANT_FALSE)
	{
		if(pISktClient->get_IsConnected(&bIsConnected)==S_OK && bIsConnected)
		{
			//SwitchTo call is blocking one
			m_hrDNS=pISktClient->SwitchTo(CREATE_START_SOCK_CLIENT);
			m_hrDNS=pISktClient->SwitchTo(0xA00100DDL);
		}
	}
	Unlock();
	return m_hrDNS;
}

HRESULT __stdcall CDNS::OnGetHostByAddr(LONG nHandle, BSTR bstrHostName, BSTR bstrHostAlias, LONG lError)
{
	return Fire_OnGetHostByAddr(nHandle, bstrHostName, bstrHostAlias, lError);
}

HRESULT __stdcall CDNS::OnGetHostByName(LONG hHandle, BSTR bstrHostName, BSTR bstrAlias, BSTR bstrIPAddr, LONG lError)
{
	return Fire_OnGetHostByName(hHandle, bstrHostName, bstrAlias, bstrIPAddr, lError);
}

HRESULT __stdcall CDNS::OnDataAvailable(long hSocket, long lBytes, long lError)
{
	CStreamHeader	StreamHeader;
aa:	if(lBytes>=sizeof(StreamHeader))
	{
		Lock();
		do
		{
			long lRecv=sizeof(StreamHeader);
			m_hrDNS=RecvChunk(&StreamHeader, &lRecv);
			lBytes -=lRecv;
			m_hrDNS=lError=StreamHeader.m_nValue;
			if(FAILED(m_hrDNS))
				break;
			if(StreamHeader.m_nLen)
			{
				USES_CONVERSION;
				lRecv=StreamHeader.m_nLen;
				switch (lError)
				{
				case idGetDNSByAddr:
				case idGetDNSByName:
					{
						char *str=new char [lRecv+1];
						m_hrDNS=RecvChunk(str, &lRecv);
						ATLASSERT(lRecv);
						str[lRecv]=0;
						if(m_bstrHostEnt)
							::SysFreeString(m_bstrHostEnt);
						m_bstrHostEnt=A2BSTR(str);
						delete []str;
					}
					break;
				case idGetCountClients:
					ATLASSERT(StreamHeader.m_nLen=sizeof(m_lCount));
					m_hrDNS=RecvChunk(&m_lCount, &lRecv);
					break;
				case idGetClients:
					{
						UINT nCount;
						BYTE *pBuffer=new BYTE[lRecv];
						m_hrDNS=RecvChunk(pBuffer, &lRecv);
						if(FAILED(m_hrDNS))
							break;
						ATLASSERT((lRecv%sizeof(CClientInfo))==0);
						nCount=lRecv/sizeof(CClientInfo);
						if(nCount)
						{
							CComBSTR	bstrClients;
							for(UINT n=0; n<nCount; n++)
							{
								BYTE	*p=pBuffer+n*sizeof(CClientInfo);
								CClientInfo* pInfo=(CClientInfo*)p;
								{
									char	strTemp[50]={0};
									unsigned short nPort=pInfo->m_nPort;
									if(n)
										sprintf(strTemp, ",%s:%d", inet_ntoa(*((in_addr*)&(pInfo->m_nIPAddr))), nPort);
									else
										sprintf(strTemp, "%s:%d", inet_ntoa(*((in_addr*)&(pInfo->m_nIPAddr))), nPort);
									bstrClients +=CComBSTR(strTemp);
								}
							}
							m_bstrClients=bstrClients.m_str;
							bstrClients.m_str=NULL;
						}
					}
					break;
				default:
					Unlock();
					return S_OK;
					break;
				}
				lBytes -=StreamHeader.m_nLen;
			}
		}while(false);
		Unlock();
		Fire_OnDataAvailable(hSocket, lBytes, lError);
	}
	if(lBytes>0 && lBytes>sizeof(StreamHeader))
	{
		goto aa; 
//		::PostMessage((HWND)m_hWnd, WM_SOCKET_CLIENT_NOTIFY, m_hSocket, FD_READ); //smoother but slight slower
	}
	return S_OK;
}

HRESULT __stdcall CDNS::OnSendingData(long hSocket, long lError)
{
	return Fire_OnSendingData(hSocket, lError);	
}

HRESULT __stdcall CDNS::OnSocketConnected(long hSocket, long lError)
{
	if(lError==S_OK)
	{
		CComPtr<ISktClient> pISktClient;
		Lock();
		m_hrDNS=m_pIUnknown.QueryInterface(&pISktClient);
		if(!FAILED(m_hrDNS))
			m_hrDNS=pISktClient->SwitchTo(g_nDResolverClassID);
		Unlock();
		ATLTRACE(_T("The client socket %d is connected with a host\n"), hSocket);
	}
	return Fire_OnSocketConnected(hSocket, lError);
}

HRESULT __stdcall CDNS::OnConnecting(long hSocket, long hWnd)
{
	ATLTRACE(_T("The client socket %d is connecting to a host......\n"), hSocket);
	m_hWnd=hWnd;
	m_hSocket=hSocket;
	return Fire_OnConnecting(hSocket, hWnd);
}

HRESULT __stdcall CDNS::OnSocketClosed(long hSocket, long lError)
{
	ATLTRACE(_T("The connected host is shut down\n"));
	return Fire_OnSocketClosed(hSocket, lError);
}

HRESULT __stdcall CDNS::OnOtherMessages(long nMsg, long wParam, long lParam)
{
	return Fire_OnOtherMessages(nMsg, wParam, lParam);
}

STDMETHODIMP CDNS::GetRtn(long *plResult)
{
	Lock();
	if(plResult)
	{
		if(m_hrDNS!=S_OK)
			*plResult=m_hrDNS;
		else
		{
			CComPtr<ISktClient> pISktClient;
			m_pIUnknown.QueryInterface(&pISktClient);
			pISktClient->GetRtn(plResult);
		}
	}
	Unlock();
	return S_OK;
}

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior)
United States United States
Yuancai (Charlie) Ye, an experienced C/C++ software engineer, lives in Atlanta, Georgia. He is an expert at continuous inline request/result batching, real-time stream processing, asynchronous data transferring and parallel computation for the best communication throughput and latency. He has been working at SocketPro (https://github.com/udaparts/socketpro) for more than fifteen years.

Comments and Discussions