Click here to Skip to main content
15,885,842 members
Articles / Desktop Programming / MFC

Peer-to-Peer Communicator and File Transfer

Rate me:
Please Sign up or sign in to vote.
4.33/5 (57 votes)
14 Aug 20013 min read 390.4K   21.9K   167  
Get youself a peer-to-peer communicator and exchange files across a network.
// NetStream.cpp: implementation of the CNetStream class.
//
// Written by Marat Bedretdinov (maratb@hotmail.com)
// Copyright (c) 2000.
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed unmodified by any means PROVIDING it is 
// not sold for profit without the authors written consent, and 
// providing that this notice and the authors name is included. 
//
// If the source code in  this file is used in any commercial application 
// then acknowledgement must be made to the author of this file 
// and permissions to use this file are requested from the author
//
// (in whatever form you wish).// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability if it causes any damage whatsoever.
// It's free - so you get what you pay for.//

#include "stdafx.h"

#include "NetConnection.h"
#include "NetFileConnector.h"
#include "NetMessage.h"
#include "NetStream.h"

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


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CNetStream::CNetStream() :
m_pConnector(0),
m_pFactory(0)
{
  m_pFactory = g_getDefaultMsgFactory();
}

CNetStream::~CNetStream()
{
// if there is a connection, close it and release the object
  _DELETE(m_pConnector)
}

//////////////////////////////////////////////////////////////////////
// this method lets the stream to redirect its data flow through a 
// differnet connector the return value is the previously used connector 

CNetConnection* CNetStream::Attach(CNetConnection* pConnector)
{
  CNetConnection* pPrevConnector = m_pConnector;
// assign new connection to the stream
  m_pConnector = pConnector;
  return pPrevConnector;
}

//////////////////////////////////////////////////////////////////////
// this method lets the stream to handle different type of messages
// the return value is the previsouly used message factory 
// there is no Deatch(CMsgFactory*) method, based on assumtion
// that factories are created statically

CMsgFactory* CNetStream::Attach(CMsgFactory* pFactory)
{
  CMsgFactory* pPrevFactory = m_pFactory;
// assign new msg factory to the stream
  m_pFactory = pFactory;
  return pPrevFactory;
}

//////////////////////////////////////////////////////////////////////
// this method makes the stream unusable, however the connector is
// preserved and may be reassociated with a different stream

CNetConnection* CNetStream::Detach()
{
  CNetConnection* pPrevConnector = m_pConnector;
  m_pConnector = 0;
  return pPrevConnector;
}

// returns true if underlaying protocol is connected
bool CNetStream::IsOpen() const
{
  return m_pConnector && m_pConnector->IsConnected();
}

bool CNetStream::IsThereData()
{
  return IsOpen() && m_pConnector->CanRead();
}

// reads data from the CNetConnector and constructs a CNetMsg out of it
CNetStream& CNetStream::operator>>(CNetMsg*& pMsg)
{
  pMsg = 0;
// if not connected - exception
  if (!m_pConnector || !m_pConnector->IsConnected()) 
    throw CNetException(ERR_NET_NOT_CONNECTED, "bool CNetStream::Read()");

  try {
// wait until there is data. Note that if connection is broken CanRead() throws an exception
   while (!m_pConnector->CanRead())
     Sleep(0);
// read the message from the stream
   CNetMsg::Read(this, pMsg);
  } catch (CNetException e) {
	_DELETE(pMsg);
	pMsg = 0;
	throw e;
  }
  return *this;
}

// write data from CNetMsg into the CNetConnector
CNetStream& CNetStream::operator<<(CNetMsg& msg)
{
// if not connected - exception
  if (!m_pConnector || !m_pConnector->IsConnected()) 
	throw CNetException(ERR_NET_NOT_CONNECTED, "bool CNetStream::Read()");
// wait until I can write in. Note that if connection is broken CanWrite() throws an exception
  try {
    while (!m_pConnector->CanWrite())
      Sleep(0);
// write the member variables (header + message body) into void* and send it
    msg.Write(this);
  } catch (CNetException e) {
	throw e;
  }
  return *this;
}

// this sends only with a single message at a time and only its "simple" data
// a CNetMsg derivable takes care of its children
void CNetStream::Write(CNetMsg& msg)
{
// get the message header
  CNetMsgHdr* pHdr = msg.GetMsgHdr();
// write the message header data into the socket stream
  m_pConnector->Write(pHdr->GetData(), pHdr->GetSize_Write());
// now write the message body data into the socket stream
  m_pConnector->Write(msg.GetData(), msg.GetSize_Write());
// the void* buffer is not needed any longer
  pHdr->EmptyBuffer();
  msg.EmptyBuffer();
}

CNetMsg* CNetStream::CreateMessage(long nClassId)
{
  if (!m_pFactory)  
    throw CNetMsgException(ERR_NET_NO_MSG_FACTORY, "CNetMsg* CNetStream::CreateMessage()");

  return m_pFactory->CreateMessage(nClassId);
}

/*
// read the header data. CNetMsgHdr::m_pData now points to the data
   m_pConnector->Read(pHeader->AllocateData(), pHeader->GetSize_Read());
// parse out the member variables from m_pData
   pHeader->Read();
// create the message class based on the message class name
   //pMsg = dynamic_cast<CNetMsg*>(CREATE(g_MessageClassNames[pHeader->GetMSG().m_nClassId].m_strClassName));
   pMsg = CreateMessage(pHeader->GetMSG().m_nClassId);
   if (!pMsg) 
     throw CNetMsgException(ERR_NET_MSG_UKNOWN_TYPE, "CNetStream& CNetStream::operator>>(CNetMsg*&)");
// now read the message body data. CNetMsg[derived]::m_pData now points to the data
   m_pConnector->Read(pMsg->AllocateData(pHeader->GetMsgSize()), pHeader->GetMsgSize());
// release header.m_pData, because if I don't, then the CNetMsgHdr::operator=()
// will allocate a new m_pData for pMsg->m_header::m_pData and copy 
// the context. That would be an overkill. I don't need this info anymore, 
// since the member variables are properly populated already
   pHeader->EmptyBuffer();
// copy header's member variables
   pMsg->GetMsgHdr()->operator=(*pHeader);
// parse out the member variables from m_pData
   pMsg->ReadBody();
   if (pMsg->HasChildren())
	 pMsg->ReadChildren(this);
// release the message's m_Data
   pMsg->EmptyBuffer();
   delete pHeader;
*/

// reads data from the CNetConnector and constructs a CNetMsg out of it
CNetStream& CFlatStream::operator>>(CNetMsg*& pMsg)
{
  pMsg = 0;
  char* pBuff = 0;
// if not connected - exception
  if (!m_pConnector || !m_pConnector->IsConnected()) 
    throw CNetException(ERR_NET_NOT_CONNECTED, "bool CNetStream::Read()");

  try {
   CNetFileConnector* pConnector = dynamic_cast<CNetFileConnector*>(m_pConnector);
   if (!pConnector)
	 throw CNetMsgException(ERR_NET_BAD_CONNECTION_HANDLER, "CNetStream& CPacketStream::operator>>(CNetMsg*& pMsg)");
// wait until there is data. Note that if connection is broken CanRead() throws an exception
   while (!m_pConnector->CanRead())
     Sleep(0);
// find out how much I can read.
// request as mach as I can, return will have the max possible value
   ulong nLen = pConnector->CanRead(CNetPacket::GetMaxSize_Packet());
// read the message from the stream
   pMsg = new CNetPacket;
   pBuff = new char[nLen];
   pConnector->Read(pBuff, nLen);

// figure out the sequence number of this packet
   ulong nSeqN = (pConnector->GetCurrentPos() + CNetPacket::GetMaxSize_Packet() - 1) / CNetPacket::GetMaxSize_Packet();
   ((CNetPacket*)pMsg)->SetData(pBuff, nLen, nSeqN);

  } catch (CNetException e) {
	_DELETE(pMsg);
	_DELETE(pBuff);
	throw e;
  }
  delete pBuff;
  return *this;
}

// write data from CNetMsg into the CNetConnector
CNetStream& CFlatStream::operator<<(CNetMsg& msg)
{
// if not connected - exception
  if (!m_pConnector || !m_pConnector->IsConnected()) 
	throw CNetException(ERR_NET_NOT_CONNECTED, "bool CNetStream::Read()");
// wait until I can write in. Note that if connection is broken CanWrite() throws an exception
  try {
   CNetFileConnector* pConnector = dynamic_cast<CNetFileConnector*>(m_pConnector);
   while (!pConnector->CanWrite())
      Sleep(0);

// just write the body of the packet
    CNetPacket& packet = dynamic_cast<CNetPacket&>(msg);
	pConnector->Write(packet.GetData(), packet.GetSize());

  } catch (bad_cast e) {
	throw CNetMsgException(ERR_NET_MSG_UKNOWN_TYPE, "CNetStream& CPacketStream::operator<<(CNetMsg& msg)");
  } catch (CNetException e) {
	throw e;
  }
  return *this;
}

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



Comments and Discussions