| /************************************************************** |
| * |
| * 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; |
| } |