blob: 6de9dd5703d8f0571bf1444861c6c633dd88a1fd [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_automation.hxx"
/*************************************************************************
*
* ATTENTION
* This file is intended to work inside and outside the StarOffice environment.
* Only adaption of file commtypes.hxx should be necessary. Else it is a bug!
*
************************************************************************/
#include "packethandler.hxx"
#include <automation/commtypes.hxx>
#include <automation/commdefines.hxx>
#include "communiio.hxx"
/**
Forces switch to multichannel headers even for old communication Method
**/
#define FORCE_MULTI_CHANNEL_HEADERS
PacketHandler::PacketHandler( ITransmiter* pTransmitter_, IReceiver* pReceiver_, comm_BOOL bMC )
: pTransmitter( pTransmitter_ )
, pReceiver( pReceiver_ )
, bMultiChannel( bMC )
{
}
unsigned char PacketHandler::CalcCheckByte( comm_UINT32 nBytes )
{
comm_UINT16 nRes = 0;
nRes += HIBYTE( HIWORD( nBytes ) ) ^ 0xf0;
nRes += LOBYTE( HIWORD( nBytes ) ) ^ 0x0f;
nRes += HIBYTE( LOWORD( nBytes ) ) ^ 0xf0;
nRes += LOBYTE( LOWORD( nBytes ) ) ^ 0x0f;
nRes ^= HIBYTE( nRes );
return LOBYTE( nRes );
}
#define READ_SOCKET( pBuffer, nLength )\
if ( !bWasError )\
{\
bWasError |= pReceiver->ReceiveBytes( pBuffer, nLength ) != C_ERROR_NONE;\
}
#define READ_SOCKET_LEN( pBuffer, nLength, nTotal )\
READ_SOCKET( pBuffer, nLength );\
if ( !bWasError )\
{nTotal += nLength;}
comm_BOOL PacketHandler::ReceiveData( void* &pData, comm_UINT32 &nLen )
{
DBG_ASSERT( !pData, "pData should be NULL -> memory leak" );
nLen = 0;
pData = NULL;
comm_BOOL bWasError = sal_False;
comm_BOOL bForceMultiChannelThisPacket = sal_False;
if ( pReceiver )
{
comm_UINT32 nBytes = 0;
nReceiveProtocol = CM_PROTOCOL_OLDSTYLE;
nReceiveHeaderType = CH_NoHeader;
READ_SOCKET( &nBytes, sizeof(nBytes) )
if ( bWasError )
return sal_False;
if ( 0xFFFFFFFF == nBytes ) // Expliziter Request für dieses Datenpaket auf MultiChannel umzuschalten
{
READ_SOCKET( &nBytes, sizeof(nBytes) )
if ( bWasError )
return sal_False;
bForceMultiChannelThisPacket = sal_True;
}
nBytes = NETDWORD( nBytes );
if ( bMultiChannel || bForceMultiChannelThisPacket )
{
comm_ULONG nReadSoFar = 0;
comm_ULONG nHeaderReadSoFar = 0;
// Prüfbyte für Längenangabe
unsigned char nLenCheck = 0;
READ_SOCKET_LEN( &nLenCheck, 1, nReadSoFar );
// Stimmt das Prüfbyte?
bWasError |= nLenCheck != CalcCheckByte( nBytes );
comm_UINT16 nHeaderBytes;
READ_SOCKET_LEN( &nHeaderBytes, 2, nReadSoFar );
nHeaderBytes = NETWORD( nHeaderBytes );
// reicht der Header über das Ende hinaus?
bWasError |= !(nBytes >= nReadSoFar + nHeaderBytes);
READ_SOCKET_LEN( &nReceiveHeaderType, 2, nHeaderReadSoFar );
nReceiveHeaderType = NETWORD( nReceiveHeaderType );
switch ( nReceiveHeaderType )
{
case CH_SimpleMultiChannel:
{
READ_SOCKET_LEN( &nReceiveProtocol, 2, nHeaderReadSoFar );
nReceiveProtocol = NETWORD( nReceiveProtocol );
}
break;
case CH_Handshake:
{
}
break;
default:
{
DBG_ERROR("Unbekannter Headertyp in der Kommunikation");
bWasError = sal_True;
}
}
if ( bWasError )
return sal_False;
/// Längen anpassen und ggf restheader überlesen.
while ( nHeaderBytes > nHeaderReadSoFar )
{
unsigned char nDummy;
READ_SOCKET_LEN( &nDummy, 1, nHeaderReadSoFar );
}
nReadSoFar += nHeaderReadSoFar;
nBytes -= nReadSoFar;
}
/* @@@ Notes @@@
*
* 1) a 'void*' allocated via 'new char[]' is always deallocated
* via plain 'delete()', not via array 'delete[]()'; it's just
* raw memory.
*
* 2) as the caller of this routine later-on changes ownership
* of 'pData' via 'SvMemoryStream::SetBuffer()' (in 'simplecm.cxx',
* 'SimpleCommunicationLinkViaSocket::DoReceiveDataStream()'),
* the allocator used here for 'void* pData' must match the
* deallocator used in 'SvMemoryStream::FreeMemory()', i.e.
* '::operator delete()'.
*/
pData = ::operator new(nBytes);
READ_SOCKET( pData, nBytes )
if ( bWasError )
{
::operator delete(pData), pData = 0;
return sal_False;
}
nLen = nBytes;
}
else
bWasError = sal_True;
return !bWasError;
}
/*#define WRITE_SOCKET( pBuffer, nLength )\
if ( !bWasError )\
bWasError |= !pStreamSocket || (pStreamSocket->write( pBuffer, nLength ) != nLength)*/
#define WRITE_SOCKET( pBuffer, nLength )\
if ( !bWasError )\
{bWasError |= pTransmitter->TransferBytes( pBuffer, nLength ) != C_ERROR_NONE;}
comm_BOOL PacketHandler::TransferData( const void* pData, comm_UINT32 nLen, CMProtocol nProtocol )
{
comm_UINT32 nBuffer = nLen;
comm_BOOL bWasError = sal_False;
#ifndef FORCE_MULTI_CHANNEL_HEADERS
if ( bMultiChannel )
#endif
nBuffer += 1+2+2+2; // für einen CH_SimpleMultiChannel
#ifdef FORCE_MULTI_CHANNEL_HEADERS
if ( !bMultiChannel )
{
comm_UINT32 n32;
n32 = 0xffffffff; // Umschalten auf MultiChannel
n32 = NETDWORD( n32 );
WRITE_SOCKET( &n32, 4 );
}
#endif
comm_UINT32 nNetworkBuffer = NETDWORD( nBuffer );
WRITE_SOCKET( &nNetworkBuffer, sizeof(nNetworkBuffer) );
#ifndef FORCE_MULTI_CHANNEL_HEADERS
if ( bMultiChannel )
#endif
{
comm_UINT16 n16;
unsigned char c;
c = CalcCheckByte( nBuffer );
WRITE_SOCKET( &c, 1 );
n16 = 4; // Länge des Headers für einen CH_SimpleMultiChannel
n16 = NETWORD( n16 );
WRITE_SOCKET( &n16, 2 );
n16 = CH_SimpleMultiChannel; // Typ des Headers
n16 = NETWORD( n16 );
WRITE_SOCKET( &n16, 2 );
nProtocol = NETWORD( nProtocol );
WRITE_SOCKET( &nProtocol, 2 );
}
WRITE_SOCKET( pData, nLen );
return !bWasError;
}
comm_BOOL PacketHandler::SendHandshake( HandshakeType aHandshakeType, const void* pData, comm_UINT32 nLen )
{
comm_BOOL bWasError = sal_False;
comm_UINT32 nBuffer = 0;
// if ( pMyManager->IsMultiChannel() ) Wir senden immer FFFFFFFF vorweg -> immer MultiChannel (Oder GPF bei älteren)
nBuffer += 1+2+2; // für einen CH_Handshake
nBuffer += 2; // für den Typ des Handshakes
switch ( aHandshakeType )
{
case CH_REQUEST_HandshakeAlive:
nBuffer += 0; // Keine extra Daten
break;
case CH_RESPONSE_HandshakeAlive:
nBuffer += 0; // Keine extra Daten
break;
case CH_REQUEST_ShutdownLink:
nBuffer += 0; // Keine extra Daten
break;
case CH_ShutdownLink:
nBuffer += 0; // Keine extra Daten
break;
case CH_SUPPORT_OPTIONS:
nBuffer += 2 ; // one word extradata for options
break;
case CH_SetApplication:
nBuffer += 0 ; // one word extradata for options
break;
default:
DBG_ERROR("Unknown HandshakeType");
}
if ( pData )
nBuffer += nLen; // Extra data in Buffer
comm_UINT32 n32;
n32 = 0xffffffff; // Umschalten auf MultiChannel
n32 = NETDWORD( n32 );
WRITE_SOCKET( &n32, 4 );
comm_UINT32 nNetworkBuffer = NETDWORD( nBuffer );
WRITE_SOCKET( &nNetworkBuffer, sizeof(nNetworkBuffer) );
comm_UINT16 n16;
unsigned char c;
c = CalcCheckByte( nBuffer );
WRITE_SOCKET( &c, 1 );
n16 = 2; // Länge des Headers für einen CH_Handshake
n16 = NETWORD( n16 );
WRITE_SOCKET( &n16, 2 );
n16 = CH_Handshake; // Typ des Headers
n16 = NETWORD( n16 );
WRITE_SOCKET( &n16, 2 );
n16 = aHandshakeType; // Typ des Handshakes
n16 = NETWORD( n16 );
WRITE_SOCKET( &n16, 2 );
switch ( aHandshakeType )
{
case CH_SUPPORT_OPTIONS:
n16 = OPT_USE_SHUTDOWN_PROTOCOL;
n16 = NETWORD( n16 );
WRITE_SOCKET( &n16, 2 );
break;
}
if ( pData )
WRITE_SOCKET( pData, nLen );
return !bWasError;
}