/*
* This file is part of rasdaman community.
*
* Rasdaman community is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Rasdaman community is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with rasdaman community. If not, see .
*
* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
rasdaman GmbH.
*
* For more information please see
* or contact Peter Baumann via .
*/
/****************************************************************************
*
*
* COMMENTS:
*
****************************************************************************/
#include
#include
#include "debug.hh"
using namespace rnp;
const char* RnpTransport::carrierNames[] =
{
"(unknown)","RNP","HTTP","(bad)"
};
const char* RnpTransport::getCarrierName(RnpTransport::CarrierProtocol x) throw()
{
if(x < crp_Unknown || x >= crp_HowMany) return carrierNames[0];
return carrierNames[x];
}
const int RnpReceiver::headerBufferLength = 1000;
RnpReceiver::RnpReceiver() throw()
{
headerBuffer.allocate(headerBufferLength);
reset();
}
RnpReceiver::~RnpReceiver() throw()
{
}
void RnpReceiver::reset() throw()
{
rnpMessageBuffer.freeBuffer();
headerBuffer.clearToRead();
status = waitingHeader;
carrier = RnpTransport::crp_Unknown;
}
akg::CommBuffer* RnpReceiver::getCurrentBuffer() throw()
{
return status == readingMessage ? &rnpMessageBuffer : &headerBuffer;
}
akg::CommBuffer* RnpReceiver::getMessageBuffer() throw()
{
return &rnpMessageBuffer;
}
RnpTransport::CarrierProtocol
RnpReceiver::getCarrierProtocol() const throw()
{
return carrier;
}
int RnpReceiver::getCarrierHeaderSize() const throw()
{
return carrierHeaderLength;
}
const void* RnpReceiver::getCarrierHeader() throw()
{
return headerBuffer.getData();
}
bool RnpReceiver::isDiscarding() const throw()
{
return status == discarding ? true:false;
}
bool RnpReceiver::validateMessage() throw()
{
ENTER( "RnpReceiver::validateMessage()");
if(status == waitingHeader)
{ rnpHeader = NULL;
if(isHttpCarrier() || isRnpCarrier())
{ // a valid carrier header was detected
if(rnpHeader != NULL)
{ // we can switch to reading the message
if(prepareMessageBuffer())
{
status = readingMessage;
}
else {
status = discarding;
LEAVE( "RnpReceiver::validateMessage() -> false - discarding message: not enough memory for message buffer.");
return false;
}
}
else
{
// status == readingHeader, but rnpHeader == NULL
// so we wait for some more message
LEAVE( "RnpReceiver::validateMessage - wait for more message(s)");
return false;
}
}
else
{ status = discarding;
LEAVE( "RnpReceiver::validateMessage() -> false - discarding message: no valid carrier header.");
return false;
}
}
if(status == readingMessage)
{
if(rnpMessageBuffer.getNotFilledSize() != 0)
{
LEAVE( "RnpReceiver::validateMessage() -> false");
return false;
}
}
if(status == discarding)
{
TALK( "RnpReceiver::validateMessage - discarding(3)." );
headerBuffer.clearToRead();
LEAVE( "RnpReceiver::validateMessage() -> false");
return false;
}
LEAVE( "RnpReceiver::validateMessage() -> true");
return true;
}
/* the isXXXCarrier() functions have to:
- return true if the message is or might be an XXX embedded RnpMessage
- set rnpHeader only if there is a valid carrier header
- set carrierHeaderLength in this case
so:
- invalid carrier returns false / rnpHeader == NULL
- valid carrier but not rnp - false /rnpHeader != NULL
- valid carrier but not enough data to be sure it's also valid rnp - true/rnpHeader == NULL
- valid carrier & valid rnp header =>true/rnpHeader != NULL carrierHeaderLength set
*/
bool RnpReceiver::isHttpCarrier() throw()
{
ENTER( "RnpReceiver::isHttpCarrier()" );
char *data = (char*)headerBuffer.getData();
rnpHeader = NULL;
carrierHeaderLength = -1;
bool isHttpReqHeader = strncmp(data,"POST RnpMessage HTTP/1.1",24) ? false : true;
bool isHttpAnsHeader = strncmp(data,"HTTP/1.1 200 OK" ,15) ? false : true;
if(isHttpReqHeader == false && isHttpAnsHeader == false)
{
LEAVE( "RnpReceiver::isHttpCarrier() -> false" );
return false;
}
char *eoHttp = strstr(data,"\r\n\r\n");
if(eoHttp == NULL)
{
LEAVE( "RnpReceiver::isHttpCarrier() -> false" );
return false;
}
carrierHeaderLength = eoHttp - data + 4;
if( carrierHeaderLength == -1)
{
LEAVE( "RnpReceiver::isHttpCarrier() -> false" );
return false;
}
if(carrierHeaderLength + sizeof(RnpHeader) > headerBuffer.getDataSize())
{ // is HTTP carrier, but we need more data to say if it's an embedded RnpMessage
LEAVE( "RnpReceiver::isHttpCarrier() -> true" );
return true;
}
rnpHeader = (RnpHeader*)(data + carrierHeaderLength);
bool isRnp = rnpHeader->isRnpMessage();
if(isRnp)
{ carrier = RnpTransport::crp_Http;
TALK( "RnpReceiver::isHttpCarrier - valid HTTP carrier detected.");
}
LEAVE( "RnpReceiver::isHttpCarrier() -> " << isRnp);
return isRnp;
}
bool RnpReceiver::isRnpCarrier() throw()
{
ENTER( "RnpReceiver::isRnpCarrier()" );
char *data = (char*)headerBuffer.getData();
rnpHeader = NULL;
carrierHeaderLength = -1;
if(sizeof(RnpHeader) > headerBuffer.getDataSize())
{ // we need more data to say if it's an RnpMessage
LEAVE( "RnpReceiver::isRnpCarrier() -> true" );
return true;
}
rnpHeader = (RnpHeader*)data;
carrierHeaderLength = 0;
bool isRnp = rnpHeader->isRnpMessage();
if(isRnp)
{ carrier = RnpTransport::crp_Rnp;
TALK( "RnpReceiver::isRnpCarrier - valid RNP carrier detected!");
}
LEAVE( "RnpReceiver::isRnpCarrier() -> " << isRnp );
return isRnp;
}
bool RnpReceiver::prepareMessageBuffer() throw()
{
if(rnpMessageBuffer.allocate(rnpHeader->getTotalLength()) == false)
return false;
char *data = (char*)headerBuffer.getData();
rnpMessageBuffer.read(data + carrierHeaderLength, headerBuffer.getDataSize() - carrierHeaderLength);
RnpHeader *nRnpHeader = (RnpHeader*)rnpMessageBuffer.getData();
return true;
}
//########################################################################################################
RnpTransmitter::RnpTransmitter() throw()
{
carrier = NULL;
carrierType = RnpTransport::crp_Http;
}
RnpTransmitter::~RnpTransmitter() throw()
{
if(carrier != NULL) delete carrier;
}
bool RnpTransmitter::startRequest(RnpQuark serverType, RnpTransport::CarrierProtocol desiredProtocol) throw()
{
getCarrierObject(desiredProtocol);
if(carrier == NULL) return false;
startMessage(serverType, carrier->getRequestHeaderLength());
return true;
}
bool RnpTransmitter::startAnswer(RnpQuark serverType, RnpTransport::CarrierProtocol desiredProtocol) throw()
{
getCarrierObject(desiredProtocol);
if(carrier == NULL) return false;
startMessage(serverType, carrier->getAnswerHeaderLength());
return true;
}
akg::CommBuffer* RnpTransmitter::endMessage() throw()
{
if(carrier == NULL) return NULL;
akg::CommBuffer *theBuffer = RnpProtocolEncoder::endMessage();
carrier->putHeader(theBuffer);
return theBuffer;
}
RnpTransport::CarrierProtocol
RnpTransmitter::getCarrierProtocol() throw()
{
return carrierType;
}
RnpCarrier* RnpTransmitter::getCarrierObject(RnpTransport::CarrierProtocol desiredProtocol) throw()
{
carrierType = desiredProtocol;
if(carrier != NULL) delete carrier;
switch(carrierType)
{
case RnpTransport::crp_Rnp : carrier = new RnpCarrier;break;
case RnpTransport::crp_Http: carrier = new HttpRnpCarrier;break;
case RnpTransport::crp_BadCarrier:
carrier = new BadRnpCarrier;break;
default : carrier = NULL;break;
}
return carrier;
}
int RnpTransmitter::getBufferSize() const throw()
{
if ( ! ( commBuffer != 0 ) )
{
TALK( "RnpTransmitter::getBufferSize(): warning: assert will fire." );
}
assert(commBuffer != 0);
return commBuffer->getBufferSize();
}
int RnpTransmitter::getNotFilledSize() const throw()
{
if ( ! ( commBuffer != 0 ) )
{
TALK( "RnpTransmitter::getNotFilledSize(): warning: assert will fire." );
}
assert(commBuffer != 0);
return commBuffer->getNotFilledSize();
}
int RnpTransmitter::getDataSize() const throw()
{
if ( ! ( commBuffer != 0 ) )
{
TALK( "RnpTransmitter::getDataSize(): warning: assert will fire." );
}
assert(commBuffer != 0);
return commBuffer->getDataSize();
}
//################################################
RnpCarrier::RnpCarrier() throw()
{
type = RnpTransport::crp_Rnp;
}
RnpCarrier::~RnpCarrier() throw()
{
}
RnpTransport::CarrierProtocol RnpCarrier::getType() throw()
{
return type;
}
int RnpCarrier::getRequestHeaderLength() throw()
{
requestHeader = true;
return 0;
}
int RnpCarrier::getAnswerHeaderLength() throw()
{
requestHeader = false;
return 0;
}
void RnpCarrier::putHeader(akg::CommBuffer*) throw()
{ // nothing!!
}
HttpRnpCarrier::HttpRnpCarrier() throw()
{
type = RnpTransport::crp_Http;
}
int HttpRnpCarrier::getRequestHeaderLength() throw()
{
requestHeader = true;
return strlen(theRequestHeader);
}
int HttpRnpCarrier::getAnswerHeaderLength() throw()
{
requestHeader = false;
return strlen(theAnswerHeader);
}
void HttpRnpCarrier::putHeader(akg::CommBuffer *messageBuffer) throw()
{
char *data = (char*)messageBuffer->getData();
const char *header = requestHeader ? theRequestHeader : theAnswerHeader;
int headerLength = strlen(header);
int posOfLength = headerLength - 14;
strncpy(data,header,posOfLength);
sprintf(data + posOfLength, "%10d",messageBuffer->getDataSize() - headerLength);
strncpy(data + headerLength - 4,"\r\n\r\n",4); // it shouldn't be null terminated!
}
const char HttpRnpCarrier::theRequestHeader[]=
"POST RnpMessage HTTP/1.1\r\nAccept: bin/rnp\r\nUserAgent: RnpClient/1.0\r\nContent-length: uxxxyyyzzz\r\n\r\n";
// ^10 digits
const char HttpRnpCarrier::theAnswerHeader[]=
"HTTP/1.1 200 OK\r\nContent-type: bin/rnp\r\nContent-length: uxxxyyyzzz\r\n\r\n";
BadRnpCarrier::BadRnpCarrier() throw()
{
type = RnpTransport::crp_BadCarrier;
}
int BadRnpCarrier::getRequestHeaderLength() throw()
{
requestHeader = true;
return strlen(theHeader);
}
int BadRnpCarrier::getAnswerHeaderLength() throw()
{
requestHeader = false;
return strlen(theHeader);
}
void BadRnpCarrier::putHeader(akg::CommBuffer *messageBuffer) throw()
{
char *data = (char*)messageBuffer->getData();
strncpy(data,theHeader,strlen(theHeader));
}
const char BadRnpCarrier::theHeader[]="BadCarrier";