poco/FSM/samples/TCP/TcpSegment.cpp
2016-07-18 14:34:53 +02:00

472 lines
14 KiB
C++

//
// The contents of this file are subject to the Mozilla Public
// License Version 1.1 (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.mozilla.org/MPL/
//
// 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 State Machine Compiler (SMC).
//
// The Initial Developer of the Original Code is Charles W. Rapp.
// Portions created by Charles W. Rapp are
// Copyright (C) 2000 - 2007. Charles W. Rapp.
// All Rights Reserved.
//
// Contributor(s):
//
// Name
// TcpSegment.cpp
//
// Description
// Converts between raw bytes and segment objects.
//
// RCS ID
// $Id: TcpSegment.cpp,v 1.5 2007/12/28 12:34:40 cwrapp Exp $
//
// CHANGE LOG
// $Log: TcpSegment.cpp,v $
// Revision 1.5 2007/12/28 12:34:40 cwrapp
// Version 5.0.1 check-in.
//
// Revision 1.4 2005/05/28 13:31:18 cwrapp
// Updated C++ examples.
//
// Revision 1.0 2003/12/14 19:41:38 charlesr
// Initial revision
//
#include "TcpSegment.h"
#include <memory.h>
#include <string.h>
#include <stdio.h>
#if !defined(WIN32)
#include <netdb.h>
#include <arpa/inet.h>
#endif
using namespace std;
// Static member data declarations.
const int TcpSegment::TCP_HEADER_SIZE = 16;
//---------------------------------------------------------------
// TcpSegment(const sockaddr_in&, ...) (Public)
// Create an outbound segment.
//
TcpSegment::TcpSegment(const sockaddr_in& source_address,
const sockaddr_in& destination_address,
unsigned long sequence_number,
unsigned long ack_number,
unsigned short flags,
const char *data,
int offset,
int size)
{
(void) memcpy(&_src_address,
&source_address,
sizeof(source_address));
(void) memcpy(&_dest_address,
&destination_address,
sizeof(destination_address));
_sequence_number = sequence_number;
_ack_number = ack_number;
_flags = flags;
// Copy the data.
_data = new char[size];
_data_size = size;
(void) memcpy(_data, (data + offset), size);
return;
} // end of TcpSegment::TcpSegment(const sockaddr_in&, ...)
//---------------------------------------------------------------
// TcpSegment(const sockaddr_in&, ...) (Public)
// Create an inbound segment.
//
TcpSegment::TcpSegment(const sockaddr_in& source_address,
const sockaddr_in& dest_address,
const char *data,
int)
{
unsigned short srcPort;
unsigned short destPort;
unsigned long sequence;
unsigned long ack;
unsigned short flags;
unsigned short data_size;
srcPort = ((((unsigned short) data[ 0]) & 0x00ff) << 8) |
(((unsigned short) data[ 1]) & 0x00ff);
destPort = ((((unsigned short) data[ 2]) & 0x00ff) << 8) |
(((unsigned short) data[ 3]) & 0x00ff);
sequence = ((((unsigned long) data[ 4]) & 0x000000ff) << 24) |
((((unsigned long) data[ 5]) & 0x000000ff) << 16) |
((((unsigned long) data[ 6]) & 0x000000ff) << 8) |
(((unsigned long) data[ 7]) & 0x000000ff);
ack = ((((unsigned long) data[ 8]) & 0x000000ff) << 24) |
((((unsigned long) data[ 9]) & 0x000000ff) << 16) |
((((unsigned long) data[10]) & 0x000000ff) << 8) |
(((unsigned long) data[11]) & 0x000000ff);
flags = ((((unsigned short) data[12]) & 0x00ff) << 8) |
(((unsigned short) data[13]) & 0x00ff);
data_size = ((((unsigned short) data[14]) & 0x00ff) << 8) |
(((unsigned short) data[15]) & 0x00ff);
// Set the source address.
_src_address.sin_family = AF_INET;
_src_address.sin_port = ntohs(srcPort);
_src_address.sin_addr.s_addr = source_address.sin_addr.s_addr;
// Set the destination address.
_dest_address.sin_family = AF_INET;
_dest_address.sin_port = ntohs(destPort);
_dest_address.sin_addr.s_addr = dest_address.sin_addr.s_addr;
_sequence_number = sequence;
_ack_number = ack;
_flags = flags;
_data_size = data_size;
if (_data_size == 0)
{
_data = NULL;
}
else
{
_data = new char[_data_size];
(void) memcpy(_data,
&(data[TCP_HEADER_SIZE]),
_data_size);
}
return;
} // end of TcpSegment::TcpSegment(const char*, int)
//---------------------------------------------------------------
// ~TcpSegment() (Public)
// Destructor.
//
TcpSegment::~TcpSegment()
{
if (_data != NULL)
{
delete[] _data;
_data = NULL;
_data_size = 0;
}
} // end of TcpSegment::~TcpSegment()
//---------------------------------------------------------------
// getSource() const (Public)
// Return segment's source address.
//
const sockaddr_in& TcpSegment::getSource() const
{
return(_src_address);
} // end of TcpSegment::getSource() const
//---------------------------------------------------------------
// getDestination() const (Public)
// Return segment's destination address.
//
const sockaddr_in& TcpSegment::getDestination() const
{
return(_dest_address);
} // end of TcpSegment::getDestination() const
//---------------------------------------------------------------
// getSrcAddress() const (Public)
// Return the segment's source address.
//
unsigned long TcpSegment::getSrcAddress() const
{
return (_src_address.sin_addr.s_addr);
} // end of TcpSegment::getSrcAddress() const
//---------------------------------------------------------------
// getSrcPort() const (Public)
// Return the segment's source port.
//
unsigned short TcpSegment::getSrcPort() const
{
return (_src_address.sin_port);
} // end of TcpSegment::getSrcPort() const
//---------------------------------------------------------------
// getDestAddress() const (Public)
// Return the segment's destination address.
//
unsigned long TcpSegment::getDestAddress() const
{
return (_dest_address.sin_addr.s_addr);
} // end of TcpSegment::getDestAddress() const
//---------------------------------------------------------------
// getDestPort() const (Public)
// Return the segment's destination port.
//
unsigned short TcpSegment::getDestPort() const
{
return (_dest_address.sin_port);
} // end of TcpSegment::getDestPort() const
//---------------------------------------------------------------
// getSequenceNumber() const (Public)
// Return segment's sequence number.
//
unsigned long TcpSegment::getSequenceNumber() const
{
return(_sequence_number);
} // end of TcpSegment::getSequenceNumber() const
//---------------------------------------------------------------
// getAcknowledgeNumber() const (Public)
// Return segment's acknowledge number.
//
unsigned long TcpSegment::getAcknowledgeNumber() const
{
return(_ack_number);
} // end of TcpSegment::getAcknowledgeNumber() const
//---------------------------------------------------------------
// getFlags() const (Public)
// Return segment's flags.
//
unsigned short TcpSegment::getFlags() const
{
return(_flags);
} // end of TcpSegment::getFlags() const
//---------------------------------------------------------------
// getDataSize() const (Public)
// Return segment's data size.
//
int TcpSegment::getDataSize() const
{
return(_data_size);
} // end of TcpSegment::getDataSize() const
//---------------------------------------------------------------
// getData() const (Public)
// Return segment's data.
//
const char* TcpSegment::getData() const
{
return(_data);
} // end of TcpSegment::getData() const
//---------------------------------------------------------------
// packetize(char*&, int&) (Public)
// Convert this TCP segment into raw bytes.
//
void TcpSegment::packetize(char*& data, int& size)
{
unsigned short srcPort;
unsigned short destPort;
unsigned long sequence;
unsigned long ack;
unsigned short flags;
unsigned short data_size;
// The segment's size is the TCP header size + data size.
// (TCP options are *not* supported).
size = TCP_HEADER_SIZE + _data_size;
data = new char[size];
// Get data in network byte order.
srcPort = htons(_src_address.sin_port);
destPort = htons(_dest_address.sin_port);
sequence = _sequence_number;
ack = _ack_number;
flags = _flags;
data_size = _data_size;
// Fill in the TCP header.
data[ 0] = (char) (( srcPort & 0xff00) >> 8);
data[ 1] = (char) ( srcPort & 0x00ff);
data[ 2] = (char) (( destPort & 0xff00) >> 8);
data[ 3] = (char) ( destPort & 0x00ff);
data[ 4] = (char) (( sequence & 0xff000000) >> 24);
data[ 5] = (char) (( sequence & 0x00ff0000) >> 16);
data[ 6] = (char) (( sequence & 0x0000ff00) >> 8);
data[ 7] = (char) ( sequence & 0x000000ff);
data[ 8] = (char) (( ack & 0xff000000) >> 24);
data[ 9] = (char) (( ack & 0x00ff0000) >> 16);
data[10] = (char) (( ack & 0x0000ff00) >> 8);
data[11] = (char) ( ack & 0x000000ff);
data[12] = (char) (( flags & 0xff00) >> 8);
data[13] = (char) ( flags & 0x00ff);
data[14] = (char) ((data_size & 0xff00) >> 8);
data[15] = (char) (data_size & 0x00ff);
// Copy in the data.
if (_data_size > 0)
{
(void) memcpy((data + TCP_HEADER_SIZE),
_data,
_data_size);
}
return;
} // end of TcpSegment::packetize(char&*, int&)
//---------------------------------------------------------------
// flagsToString(unsigned short) (Static Private)
// Make a string representation of the TCP header flags.
//
char* TcpSegment::flagsToString(unsigned short flags)
{
char separator[3] = "{";
char *retval;
char *cptr;
(void) strcpy(separator, "{");
retval = new char[31];
(void) memset(retval, 0, 31);
cptr = retval;
if ((flags & FIN) == FIN)
{
(void) strcpy(cptr, separator);
cptr += strlen(separator);
(void) strcpy(cptr, "FIN");
cptr += 3;
(void) strcpy(separator, ", ");
}
if ((flags & SYN) == SYN)
{
(void) strcpy(cptr, separator);
cptr += strlen(separator);
(void) strcpy(cptr, "SYN");
cptr += 3;
(void) strcpy(separator, ", ");
}
if ((flags & RST) == RST)
{
(void) strcpy(cptr, separator);
cptr += strlen(separator);
(void) strcpy(cptr, "RST");
cptr += 3;
(void) strcpy(separator, ", ");
}
if ((flags & PSH) == PSH)
{
(void) strcpy(cptr, separator);
cptr += strlen(separator);
(void) strcpy(cptr, "PSH");
cptr += 3;
(void) strcpy(separator, ", ");
}
if ((flags & ACK) == ACK)
{
(void) strcpy(cptr, separator);
cptr += strlen(separator);
(void) strcpy(cptr, "ACK");
cptr += 3;
(void) strcpy(separator, ", ");
}
if ((flags & URG) == URG)
{
(void) strcpy(cptr, separator);
cptr += strlen(separator);
(void) strcpy(cptr, "URG");
cptr += 3;
}
if ((flags & FLAG_MASK) == 0)
{
(void) strcpy(cptr, separator);
cptr += strlen(separator);
(void) strcpy(cptr, "UNK");
cptr += 3;
}
*cptr = '}';
return(retval);
} // end of TcpSegment::flagsToString(unsigned short)
//---------------------------------------------------------------
// addressToString(const sockaddr_in&) (Static Private)
// Generate a string representation of an IP address.
//
char* TcpSegment::addressToString(const sockaddr_in& address)
{
struct hostent *hostEntry;
char *dotted_addr;
char port[6];
char *retval;
char *cptr;
unsigned short udp_port;
retval = new char[512];
(void) memset(retval, 0, 512);
cptr = retval;
hostEntry = gethostbyaddr((char *) &(address.sin_addr),
sizeof(address.sin_addr),
AF_INET);
(void) strcpy(cptr,
(hostEntry == NULL ?
"<no hostname>" :
hostEntry->h_name));
cptr += strlen(cptr);
*cptr++ = '(';
dotted_addr = inet_ntoa(address.sin_addr);
(void) strcpy(cptr, dotted_addr);
cptr += strlen(dotted_addr);
(void) strcpy(cptr, "):");
cptr += 2;
udp_port = ntohs(address.sin_port);
sprintf(port, "%d", udp_port);
(void) strcpy(cptr, port);
return(retval);
} // end of TcpSegment::addressToString(const sockaddr_in&)
//---------------------------------------------------------------
// operator<<(ostream&, const TcpSegment&) (Routine)
// Print this segment out to the stream.
//
ostream& operator<<(ostream& stream, const TcpSegment& segment)
{
char *srcAddrStr,
*destAddrStr,
*flagStr;
srcAddrStr = TcpSegment::addressToString(segment._src_address);
destAddrStr = TcpSegment::addressToString(segment._dest_address);
flagStr = TcpSegment::flagsToString(segment._flags);
stream << "\t Source: "
<< srcAddrStr
<< "\n\t Destination: "
<< destAddrStr
<< "\n\t Sequence #: "
<< segment._sequence_number
<< "\n\tAcknowledge #: "
<< segment._ack_number
<< "\n\t Flags: "
<< flagStr
<< " (0x"
<< ios::hex << segment._flags << ios::dec << ")"
<< "\n\t Data size: "
<< segment._data_size;
delete[] srcAddrStr;
delete[] destAddrStr;
delete[] flagStr;
return(stream);
} // end of operator<<(ostream&, const TcpSegment&)