www.pudn.com > pueblo.zip > ChMsgCon.cpp
/*----------------------------------------------------------------------------
_ _ _
/\ | | | (_)
/ \ _ __ __| |_ __ ___ _ __ ___ ___ __| |_ __ _
/ /\ \ | '_ \ / _` | '__/ _ \| '_ ` _ \ / _ \/ _` | |/ _` |
/ ____ \| | | | (_| | | | (_) | | | | | | __/ (_| | | (_| |
/_/ \_\_| |_|\__,_|_| \___/|_| |_| |_|\___|\__,_|_|\__,_|
The contents of this file are subject to the Andromedia Public
License Version 1.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at http://www.andromedia.com/APL/
Software distributed under the License is distributed on an
"AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.
The Original Code is Pueblo client code, released November 4, 1998.
The Initial Developer of the Original Code is Andromedia Incorporated.
Portions created by Andromedia are Copyright (C) 1998 Andromedia
Incorporated. All Rights Reserved.
Andromedia Incorporated 415.365.6700
818 Mission Street - 2nd Floor 415.365.6701 fax
San Francisco, CA 94103
Contributor(s):
--------------------------------------------------------------------------
Chaco team: Dan Greening, Glenn Crocker, Jim Doubek,
Coyote Lussier, Pritham Shetty.
Wrote and designed original codebase.
------------------------------------------------------------------------------
This file contains the implementation of the ChMsgConn class, used to
manage a connection for sending ChMsg objects.
sockbuf (sockinetbuf on the client)
ChConn
ChMsgConn
----------------------------------------------------------------------------*/
// $Header: /home/cvs/chaco/api/ChMsgCon.cpp,v 2.7 1995/11/07 02:11:17 coyote Exp $
#if (CH_UNIX)
#include
#include
#include
#include
#include
#include
#include
#endif
#include "headers.h"
#include
#include
/*----------------------------------------------------------------------------
ChMsgConn class
----------------------------------------------------------------------------*/
ChMsgConn::ChMsgConn( const char *pstrHost, chuint16 suPort ) :
ChConn(), m_lModuleID( 2 )
{
lReadCount = 0;
lReadNeeded = 0;
connect( pstrHost, suPort );
}
#if defined( CH_MSW )
ChMsgConn::ChMsgConn( const char *pstrHost, chuint16 suPort,
ChSocketHandler pHandler, chparam userData ) :
ChConn( pHandler, userData ), m_lModuleID( 2 )
{
lReadCount = 0;
lReadNeeded = 0;
connect( pstrHost, suPort );
}
#endif // defined( CH_MSW )
void ChMsgConn::Post( ChMsg& msg, chflag16 fPriority ) const
{
ChMsgPacket *pPacket;
chuint32 luDataLen;
chuint32 luPacketLen;
luDataLen = msg.GetSize();
luPacketLen = luDataLen + sizeof( ChMsgPacket );
pPacket = (ChMsgPacket *)new chuint8[luPacketLen];
memset( (void *)pPacket, 0, sizeof( ChMsgPacket ) );
/* Construct the packet in network
byte order */
pPacket->packet_type = 1;
if (msg.GetDestinationModule())
pPacket->idModule = htonl( msg.GetDestinationModule() );
else
pPacket->idModule = htonl( m_lModuleID );
pPacket->message_type = htonl( msg.GetMessage() );
pPacket->param1 = htonl( msg.GetParam1() );
pPacket->param2 = htonl( msg.GetParam2() );
pPacket->version = htonl( msg.GetVersion().GetPacked() );
pPacket->data_length = htonl( luDataLen );
if (luDataLen)
{ /* Copy the data associated with
the message to the end of the
packet */
ChMemCopy( pPacket + 1, msg.GetBuffer(), luDataLen );
}
SendBlock( pPacket, luPacketLen );
#if defined( CH_VERBOSE )
{
// LogPacket( (chuint8 *)pPacket, luPacketLen );
}
#endif // defined( CH_VERBOSE )
// Free the packet storage
delete pPacket;
}
void ChMsgConn::Post( chint32 lMessage, chparam param1,
chparam param2, chflag16 fPriority ) const
{
ChMsg msg( lMessage, param1, param2 );
Post( msg, fPriority );
}
/*----------------------------------------------------------------------------
FUNCTION || ChMsgConn::ProcessInput
------------------------------------------------------------------------------
Reads the contents of the socket and attempts to interpret the data as
a packet.
----------------------------------------------------------------------------*/
chint32 ChMsgConn::ProcessInput()
{
chuint32 luLen;
ASSERT( this );
luLen = GetBytesAvailable();
if (luLen > 0)
{
if (lReadCount + luLen > 2048)
{
#if defined( CH_VERBOSE )
// cerr << "ChMsgConn::ProcessInput( socketBuf ): "
// "buffer overrun" << endl;
#endif
return -1;
}
/* Read the contents of the socket
to the end of 'inputbuf' */
read( inputbuf + lReadCount, (chuint)luLen );
lReadCount += luLen;
/* Process the contents of the
internal buffer */
ProcessBuffer();
}
return 0;
}
chint32 ChMsgConn::ProcessInput( void *pBuf, chint32 lLen )
{
#if defined( CH_VERBOSE )
{
// cerr << "ChMsgConn::ProcessInput lLen=" << lLen << endl;
// LogPacket( (chuint8 *)pBuf, lLen );
}
#endif
if (lReadCount + lLen > 2048)
{
#if defined( CH_VERBOSE )
cerr << "ChMsgConn::ProcessInput: buffer overrun" << endl;
#endif
return -1;
}
// Append 'buf' to 'inputbuf'
ChMemCopy( inputbuf + lReadCount, pBuf, lLen );
lReadCount += lLen;
/* Process the contents of the
internal buffer */
ProcessBuffer();
return 0;
}
/*----------------------------------------------------------------------------
FUNCTION || ChMsgConn::ResetPacketBuffer
------------------------------------------------------------------------------
Resets the packet construction buffer to recieve a new packet
or to process an already-received one which follows the just-processed
one in 'inputbuf'.
----------------------------------------------------------------------------*/
void ChMsgConn::ResetPacketBuffer()
{
if (lReadCount > lReadNeeded) {
/* There was too much data read earlier, and only some of it has been
used, so: */
// copy the excess back into the beginning of 'inputbuf'
ChMemCopy(inputbuf, &inputbuf[lReadNeeded], lReadCount - lReadNeeded);
lReadCount -= lReadNeeded; /* Take out the size of what we've
already used. */
lReadNeeded = sizeof(ChMsgPacket); // Default, we need at least this
} else {
// 'inputbuf' has no leftover stuff, just zero these:
lReadCount = 0;
lReadNeeded = 0;
}
}
/*----------------------------------------------------------------------------
FUNCTION || ChMsgConn::ProcessBuffer
------------------------------------------------------------------------------
Processes the contents of the internal buffer and determines whether
there is enough data to compose a message block.
----------------------------------------------------------------------------*/
chint32 ChMsgConn::ProcessBuffer()
{
/* Figure out how long 'inputbuf'
needs to be before we're
done */
if (lReadCount)
{
int packet_type = inputbuf[0];
if (1 == packet_type)
{
ProcessType1();
}
else
{
ResetPacketBuffer();
}
}
return 0;
}
/*----------------------------------------------------------------------------
FUNCTION || ChMsgConn::ProcessType1
------------------------------------------------------------------------------
This function will package up a type 1 packet. When the packet is
completely constructed, it will be dispatched.
----------------------------------------------------------------------------*/
chint32 ChMsgConn::ProcessType1()
{
lReadNeeded = sizeof( ChMsgPacket ); /* The minimum number of bytes
needed */
/* Process messages out of 'inputdata' until there isn't enough
to form a packet header */
while (lReadCount && (lReadCount >= lReadNeeded) )
{ /* We've received at least the
packet structure */
ChMsgPacket *pPacket = (ChMsgPacket *)inputbuf;
/* Check if we have additional
data */
if (ntohl(pPacket->data_length))
{ /* Adjust number of bytes needed
so it includes 'data_length' */
lReadNeeded = sizeof( ChMsgPacket ) + ntohl(pPacket->data_length);
}
// If we have enough after including 'data_length',
if (lReadCount >= lReadNeeded)
{ /* We have enough to package
up the message. */
ChModuleID idModule = ntohl( pPacket->idModule );
ChMsg msg( ntohl( pPacket->message_type ),
(ChVersion)ntohl( pPacket->version ),
ntohl( pPacket->param1 ),
ntohl( pPacket->param2 ) );
// Copy in the packet 'data' field
msg.Write( pPacket + 1, ntohl(pPacket->data_length) );
/* Set the message origination
connection */
msg.SetOrigin( this );
// Dispatch the message
ResetPacketBuffer();
ChCore::GetCore()->DispatchMsg( idModule, msg );
}
// Awww, didn't get enough yet. Punt.
if (lReadCount < lReadNeeded)
{
#if 0
#if defined( CH_VERBOSE )
{
cerr << "ChMsgConn::ProcessType1: Packet fragment, "
"continuing to read."
<< "lReadCount=" << lReadCount
<< " lReadNeeded=" << lReadNeeded << endl;
}
#endif // defined( CH_VERBOSE )
#endif
}
}
return 0;
}
// Local Variables: ***
// tab-width:4 ***
// End: ***