TCPSerializer.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2005 Christian Dankbar, Irene Ruengeler, Michael Tuexen, Andras Varga
00003 // Copyright (C) 2009 Thomas Reschka
00004 //
00005 // This program is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 //
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program; if not, see <http://www.gnu.org/licenses/>.
00017 //
00018 
00019 
00020 //Define_Module(TCPSerializer);
00021 #include <platdep/sockets.h>
00022 #include "TCPSerializer.h"
00023 
00024 #include "IPProtocolId_m.h"
00025 #include "TCPIPchecksum.h"
00026 
00027 namespace INETFw // load headers into a namespace, to avoid conflicts with platform definitions of the same stuff
00028 {
00029 #include "headers/bsdint.h"
00030 #include "headers/in.h"
00031 #include "headers/in_systm.h"
00032 };
00033 
00034 #if !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) && !defined(__CYGWIN__) && !defined(_WIN64)
00035 #include <netinet/in.h>  // htonl, ntohl, ...
00036 //#include <sys/types.h>
00037 //#include <sys/socket.h>
00038 //#include <arpa/inet.h>
00039 #endif
00040 
00041 using namespace INETFw;
00042 
00043 int TCPSerializer::serialize(const TCPSegment *tcpseg,
00044         unsigned char *buf, unsigned int bufsize)
00045 {
00046     ASSERT(buf);
00047     ASSERT(tcpseg);
00048     //cMessage* cmsg;
00049     struct tcphdr *tcp = (struct tcphdr*) (buf);
00050     //int writtenbytes = sizeof(struct tcphdr)+tcpseg->payloadLength();
00051     int writtenbytes = tcpseg->getByteLength();
00052 
00053     // fill TCP header structure
00054     tcp->th_sum = 0;
00055     tcp->th_sport = htons(tcpseg->getSrcPort());
00056     tcp->th_dport = htons(tcpseg->getDestPort());
00057     tcp->th_seq = htonl(tcpseg->getSequenceNo());
00058     tcp->th_ack = htonl(tcpseg->getAckNo());
00059     tcp->th_offs = TCP_HEADER_OCTETS / 4;
00060 
00061     // set flags
00062     unsigned char flags = 0;
00063     if(tcpseg->getFinBit())
00064         flags |= TH_FIN;
00065     if(tcpseg->getSynBit())
00066         flags |= TH_SYN;
00067     if(tcpseg->getRstBit())
00068         flags |= TH_RST;
00069     if(tcpseg->getPshBit())
00070         flags |= TH_PUSH;
00071     if(tcpseg->getAckBit())
00072         flags |= TH_ACK;
00073     if(tcpseg->getUrgBit())
00074         flags |= TH_URG;
00075     tcp->th_flags = (TH_FLAGS & flags);
00076     tcp->th_win = htons(tcpseg->getWindow());
00077     tcp->th_urp = htons(tcpseg->getUrgentPointer());
00078 
00079     unsigned short numOptions = tcpseg->getOptionsArraySize();
00080     unsigned int lengthCounter = 0;
00081     unsigned char * options = (unsigned char * )tcp->th_options;
00082     if (numOptions > 0) // options present?
00083     {
00084         unsigned int maxOptLength = tcpseg->getHeaderLength()-TCP_HEADER_OCTETS;
00085 
00086         for (unsigned short i=0; i < numOptions; i++)
00087         {
00088             TCPOption option = tcpseg->getOptions(i);
00089             unsigned short kind = option.getKind();
00090             unsigned short length = option.getLength(); // length >= 1
00091             options = ((unsigned char * )tcp->th_options)+lengthCounter;
00092 
00093             lengthCounter += length;
00094 
00095             ASSERT(lengthCounter <= maxOptLength);
00096 
00097             options[0] = kind;
00098             if(length>1)
00099             {
00100                 options[1] = length;
00101             }
00102             unsigned int optlen = option.getValuesArraySize();
00103             for(unsigned int k=0; k<optlen; k++)
00104             {
00105                 unsigned int value = option.getValues(k);
00106                 unsigned int p0 = 2 + 4*k;
00107                 for (unsigned int p = std::min((unsigned int)length-1, 5 + 4*k); p >= p0; p--)
00108                 {
00109                     options[p] = value & 0xFF;
00110                     value = value >> 8;
00111                 }
00112             }
00113         } // for
00114         //padding:
00115         options = (unsigned char * )(tcp->th_options);
00116         while (lengthCounter % 4)
00117             options[lengthCounter++] = 0;
00118 
00119         ASSERT(TCP_HEADER_OCTETS+lengthCounter <= TCP_MAX_HEADER_OCTETS);
00120         tcp->th_offs = (TCP_HEADER_OCTETS+lengthCounter)/4; // TCP_HEADER_OCTETS = 20
00121     } // if options present
00122 
00123     // write data
00124     if (tcpseg->getByteLength() > tcpseg->getHeaderLength()) // data present? FIXME TODO: || tcpseg->getEncapsulatedMsg()!=NULL
00125     {
00126         unsigned int dataLength = tcpseg->getByteLength() - tcpseg->getHeaderLength();
00127         // TCPPayloadMessage *tcpP = check_and_cast<TCPPayloadMessage* >(tcpseg->getEncapsulatedMsg()); // FIXME
00128         char *tcpData = (char *)options+lengthCounter;
00129         memset(tcpData, 't', dataLength); // fill data part with 't'
00130         /*
00131         for (unsigned int i=0; i < dataLength; i++)
00132         {
00133             if (i < tcpseg->getPayloadArraySize())
00134             {
00135 //              tcpData[i] = (unsigned char) tcpP.msg; // FIXME
00136                 tcpData[i] = 't'; // FIXME - write 't' as dummy data
00137             }
00138             else
00139                 {tcpData[i] = 't';} // write 't' as dummy data
00140         }
00141         */
00142     }
00143     return writtenbytes;
00144 }
00145 
00146 int TCPSerializer::serialize(const TCPSegment *tcpseg,
00147         unsigned char *buf, unsigned int bufsize,
00148         const IPvXAddress &srcIp, const IPvXAddress &destIp)
00149 {
00150     int writtenbytes = serialize(tcpseg, buf, bufsize);
00151     struct tcphdr *tcp = (struct tcphdr*) (buf);
00152     tcp->th_sum = checksum(tcp, writtenbytes, srcIp, destIp);
00153 
00154     return writtenbytes;
00155 }
00156 
00157 void TCPSerializer::parse(const unsigned char *buf, unsigned int bufsize, TCPSegment *tcpseg)
00158 {
00159     ASSERT(buf);
00160     ASSERT(tcpseg);
00161     struct tcphdr const * const tcp = (struct tcphdr * const ) (buf);
00162 
00163     // fill TCP header structure
00164     tcpseg->setSrcPort(ntohs(tcp->th_sport));
00165     tcpseg->setDestPort(ntohs(tcp->th_dport));
00166     tcpseg->setSequenceNo(ntohl(tcp->th_seq));
00167     tcpseg->setAckNo(ntohl(tcp->th_ack));
00168     unsigned short hdrLength =tcp->th_offs * 4;
00169     tcpseg->setHeaderLength(hdrLength);
00170 
00171     // set flags
00172     unsigned char flags = tcp->th_flags;
00173     if ((flags & TH_FIN) == TH_FIN)
00174         tcpseg->setFinBit(true);
00175     if ((flags & TH_SYN) == TH_SYN)
00176         tcpseg->setSynBit(true);
00177     if ((flags & TH_RST) == TH_RST)
00178         tcpseg->setRstBit(true);
00179     if ((flags & TH_PUSH) == TH_PUSH)
00180         tcpseg->setPshBit(true);
00181     if ((flags & TH_ACK) == TH_ACK)
00182         tcpseg->setAckBit(true);
00183     if ((flags & TH_URG) == TH_URG)
00184         tcpseg->setUrgBit(true);
00185 
00186     tcpseg->setWindow(ntohs(tcp->th_win));
00187     // Checksum (header checksum): modelled by cMessage::hasBitError()
00188     tcpseg->setUrgentPointer(ntohs(tcp->th_urp));
00189 
00190     if (hdrLength > TCP_HEADER_OCTETS) // options present?
00191     {
00192         unsigned short optionBytes = hdrLength - TCP_HEADER_OCTETS; // TCP_HEADER_OCTETS = 20
00193         unsigned short optionsCounter = 0; // index for tcpseg->setOptions[]
00194 
00195         unsigned short length = 0;
00196         for (unsigned short j=0; j<optionBytes; j+=length)
00197         {
00198             unsigned char * options = ((unsigned char * )tcp->th_options)+j;
00199             unsigned short kind = options[0];
00200             length = options[1];
00201 
00202             TCPOption tmpOption;
00203             switch(kind)
00204             {
00205                 case TCPOPTION_END_OF_OPTION_LIST: // EOL
00206                 case TCPOPTION_NO_OPERATION: // NOP
00207                     length = 1;
00208                     break;
00209 
00210                 default:
00211                     break;
00212             } // switch
00213 
00214             // kind
00215             tmpOption.setKind(kind);
00216             // length
00217             tmpOption.setLength(length);
00218             // value
00219             int optlen = (length+1)/4;
00220             tmpOption.setValuesArraySize(optlen);
00221             for (short int k=0; k<optlen; k++)
00222             {
00223                 unsigned int value = 0;
00224                 for (short int l=2+4*k; l<length && l<6+4*k; l++)
00225                 {
00226                     value = (value << 8) + options[l];
00227                 }
00228                 tmpOption.setValues(k, value);
00229             }
00230             // write option to tcp header
00231             tcpseg->setOptionsArraySize(tcpseg->getOptionsArraySize()+1);
00232             tcpseg->setOptions(optionsCounter,tmpOption);
00233             optionsCounter++;
00234         } // for j
00235     } // if options present
00236 
00237     tcpseg->setByteLength(bufsize);
00238     tcpseg->setPayloadLength(bufsize - tcpseg->getHeaderLength());
00239 }
00240 
00241 uint16_t TCPSerializer::checksum(const void *addr, unsigned int count,
00242         const IPvXAddress &srcIp, const IPvXAddress &destIp)
00243 {
00244     uint32_t sum = TCPIPchecksum::_checksum(addr, count);
00245 
00246     ASSERT(srcIp.wordCount() == destIp.wordCount());
00247 
00248     //sum += srcip;
00249     sum += htons(TCPIPchecksum::_checksum(srcIp.words(), sizeof(uint32)*srcIp.wordCount()));
00250 
00251     //sum += destip;
00252     sum += htons(TCPIPchecksum::_checksum(destIp.words(), sizeof(uint32)*destIp.wordCount()));
00253 
00254     sum += htons(count); // TCP length
00255 
00256     sum += htons(IP_PROT_TCP); // PTCL
00257 
00258     while (sum >> 16)
00259         sum = (sum & 0xFFFF) + (sum >> 16);
00260 
00261     return (uint16_t)~sum;
00262 }