1: 
   2: 
   3: /**********************
   4: *                     *
   5: *  COMPILER INCLUDES  *
   6: *                     *
   7: **********************/
   8: 
   9: 
  10: #include <cassert> 
  11: 
  12: 
  13: /*********************
  14: *                    *
  15: *  PROJECT INCLUDES  *
  16: *                    *
  17: *********************/
  18: 
  19: 
  20: #include "buffer.h" 
  21: #include "dnsutil.h" 
  22: 
  23: 
  24: using std::memset;
  25: using std::memcmp;
  26: 
  27: 
  28: /***********************
  29: *                      *
  30: *  BUFFER CONSTRUCTOR  *
  31: *                      *
  32: ***********************/
  33: 
  34: 
  35: Buffer::Buffer(size_t i_szBufferMax) {
  36:   m_szBuffer = 0;
  37:   m_szBufferMax = i_szBufferMax;
  38:   m_ucpBuffer = new unsigned char[m_szBufferMax];
  39:   m_ofPos = 0;
  40:   memset(m_ucpBuffer,0,m_szBufferMax);
  41: }
  42: 
  43: 
  44: /***********************
  45: *                      *
  46: *  METHOD FINDINRANGE  *
  47: *                      *
  48: ***********************/
  49: 
  50: 
  51: off_t Buffer::FindInRange(off_t i_ofBegin, off_t i_ofEnd, const unsigned char *ci_ucpFind, size_t i_szFind) {
  52:   off_t i_ofMax = i_ofEnd - i_szFind;
  53:   while(i_ofBegin<i_ofMax) {
  54:     if (memcmp(m_ucpBuffer+i_ofBegin,ci_ucpFind,i_szFind)==0) return i_ofBegin;
  55:     i_ofBegin++;
  56:   }
  57:   return i_ofEnd;
  58: }
  59: 
  60: 
  61: /*********************************
  62: *                                *
  63: *  METHOD FINDPREVIOUSLABELLIST  *
  64: *                                *
  65: *********************************/
  66:  
  67: 
  68: off_t Buffer::FindPreviousLabelList(off_t i_ofBegin, off_t i_ofEnd, const unsigned char *ci_ucpFind, size_t i_szFind) {
  69:   while(i_ofBegin<i_ofEnd) {
  70:     if (TestLabelList(ci_ucpFind,i_szFind,i_ofBegin)==true) return i_ofBegin;
  71:     i_ofBegin++;    
  72:   }
  73:   return i_ofEnd;
  74: }
  75: 
  76: 
  77: /*******************
  78: *                  *
  79: *  METHOD READBIT  *
  80: *                  *
  81: *******************/
  82: 
  83: 
  84: /*
  85:  *  Note that the RFC simply doesn't represent bit values in a fashion that
  86:  *  makes sense to me.  It shows:
  87:  *
  88:  *                      1 1 1 1 1 1
  89:  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
  90:  *
  91:  *  Whereas the sensible values for my purposes are:
  92:  *
  93:  *  (byte 0)------> (byte 1)------>
  94:  *  7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
  95:  *
  96:  *  Hence, ReadBit/WriteBit use this approach.
  97:  */
  98: 
  99: 
 100: bool Buffer::ReadBit(off_t i_off, unsigned char i_ucBit) const {
 101:   assert(i_off<(off_t)m_szBuffer);
 102:   unsigned char ucVal = 1;
 103:   ucVal <<= i_ucBit;
 104:   if ((m_ucpBuffer[i_off]&ucVal)==ucVal) return true;
 105:   return false;
 106: }
 107: 
 108: 
 109: /********************
 110: *                   *
 111: *  METHOD READBITS  *
 112: *                   *
 113: ********************/
 114: 
 115: 
 116: void Buffer::ReadBits(bool &o_br7, bool &o_br6, bool &o_br5, bool &o_br4, bool &o_br3, bool &o_br2, bool &o_br1, bool &o_br0) const {
 117:   unsigned char uc;
 118:   this->Read(uc);
 119:   o_br7 = ((uc&128)==128);
 120:   o_br6 = ((uc&64)==64);
 121:   o_br5 = ((uc&32)==32);
 122:   o_br4 = ((uc&16)==16);
 123:   o_br3 = ((uc&8)==8);
 124:   o_br2 = ((uc&4)==4);
 125:   o_br1 = ((uc&2)==2);
 126:   o_br0 = ((uc&1)==1);
 127: }
 128: 
 129: 
 130: /********************
 131: *                   *
 132: *  METHOD READDATA  *
 133: *                   *
 134: ********************/
 135: 
 136: 
 137: void Buffer::ReadData(void *o_ptrData, size_t i_szData) const {
 138:   this->ReadData(o_ptrData,i_szData,m_ofPos);
 139: }
 140: 
 141: 
 142: void Buffer::ReadData(void *o_ptrData, size_t i_szData, off_t &io_of) const {
 143:   assert(o_ptrData!=NULL);
 144:   //cerr << "ReadData: " << i_szData << " bytes at " << io_off << " of " << m_szBuffer << endl;
 145:   if (io_of+i_szData>m_szBuffer) 
 146:     throw BufferEx(FOUT("Buffer::ReadData: overflow reading ",i_szData," bytes at ",io_of," (max ",m_szBuffer-1,")"));
 147:   memcpy(o_ptrData,m_ucpBuffer+io_of,i_szData); 
 148:   /* DEBUG: this->DumpRange(cerr,m_ucpBuffer+io_of,i_szData); */
 149:   io_of += i_szData;
 150: }
 151: 
 152: 
 153: /*************************
 154: *                        *
 155: *  METHOD READLABELLIST  *
 156: *                        *
 157: *************************/
 158: 
 159:   
 160: void Buffer::ReadLabelList(unsigned char *o_ucpOut, size_t i_szOut, unsigned short &o_usLength, bool i_bUseCompression) const {
 161:   o_usLength = 0;
 162:   this->ReadLabelList(o_ucpOut,i_szOut,o_usLength,i_bUseCompression,m_ofPos);
 163: }
 164:  
 165: 
 166: 
 167: void Buffer::ReadLabelList(unsigned char *o_ucpOut, size_t i_szOut, unsigned short &o_usLength, bool i_bUseCompression, off_t &io_ofrPos) const {
 168:   unsigned char uc;
 169:   LogHandle lh(LF_PACKETFORMAT,LY_DEBUG);
 170: 
 171:   lh << "LABEL(" << io_ofrPos << "): ";
 172:   uc = this->Get(io_ofrPos++);
 173:   while(uc!=0) {
 174:     if ((uc>=192)&&(i_bUseCompression==true)) {
 175:       off_t offCache;
 176:       offCache = uc - 192;
 177:       offCache <<= 8;
 178:       offCache += this->Get(io_ofrPos++);
 179:       // cerr << " J";  // DEBUG
 180:       return this->ReadLabelList(o_ucpOut,i_szOut,o_usLength,i_bUseCompression,offCache);
 181:     }
 182:     if (uc>=64) {
 183:       lh << "!" << (unsigned)uc << " at " << (io_ofrPos-1) << endl;
 184:       throw BadParseEx(FOUT("Buffer::ReadLabelList: unexpected high bit at ",io_ofrPos-1));
 185:     }
 186:     // STUB: check for overflow
 187:     *o_ucpOut++ = uc;
 188:     i_szOut--;
 189:     this->ReadData(o_ucpOut,uc,io_ofrPos);
 190:     //for(unsigned char i=0;i<uc;i++) cerr << o_ucpOut[i]; // DEBUG
 191:     o_ucpOut += uc;
 192:     i_szOut -= uc;
 193:     o_usLength += (uc + 1);
 194:     uc = this->Get(io_ofrPos++);
 195:     lh << ".";
 196:   }
 197:   *o_ucpOut = 0;
 198:   i_szOut--;
 199:   o_usLength++;
 200: }
 201: 
 202: 
 203: void Buffer::ReadLabelList(LabelListPtr &o_llpr, bool i_bUseCompression) const {
 204:   unsigned char uca[256];
 205:   unsigned short us;
 206:   this->ReadLabelList(uca,255,us,i_bUseCompression);
 207:   o_llpr = new LabelList(uca);
 208: }
 209: 
 210: 
 211: /*************************
 212: *                        *
 213: *  METHOD TESTLABELLIST  *
 214: *                        *
 215: *************************/
 216: 
 217: 
 218: bool Buffer::TestLabelList(const unsigned char *i_ucpLabels, size_t i_szLabels, off_t i_ofPos) {
 219:   unsigned short us;
 220:   while(1) {
 221:     //cerr << "TestLabelList: " << i_ofPos << endl;
 222:     if ((*i_ucpLabels==0)&&(m_ucpBuffer[i_ofPos]==0)) return true;
 223:     if (m_ucpBuffer[i_ofPos]>=192) {
 224:       this->PReadNBO(us,i_ofPos);
 225:       us -= 0xC000;
 226:       if(us>=i_ofPos) return false;
 227:       return this->TestLabelList(i_ucpLabels,i_szLabels,us);
 228:     }
 229:     if (*i_ucpLabels != m_ucpBuffer[i_ofPos]) return false;
 230:     if (MemCaseCmp((const char*)i_ucpLabels+1,(const char*)m_ucpBuffer+i_ofPos+1,*i_ucpLabels)!=0) return false;
 231:     i_ucpLabels += (*i_ucpLabels + 1);
 232:     i_ofPos += (m_ucpBuffer[i_ofPos] + 1);
 233:   }
 234: }
 235: 
 236: 
 237: 
 238: /**************************
 239: *                         *
 240: *  METHOD TRYCOMPRESSION  *
 241: *                         *
 242: **************************/
 243: 
 244: 
 245: // INFO: this compression technique causes a TC if there isn't enough room to write
 246: // the uncompressed label, but there is enough room w/compression.  I prefer this
 247: // approach, because the extra copy is not worth it for such a rare case.
 248: 
 249: void Buffer::TryCompression(off_t i_ofStart) {
 250:   assert(i_ofStart<=m_ofPos);
 251:   unsigned short usPrev;
 252:   size_t sz = size_t(m_ofPos - i_ofStart);
 253: 
 254:   while(sz>3) {
 255:     //cerr << "TryCompression: " << i_ofStart << " - " << m_ofPos << " (" << sz << ")" << endl;
 256:     usPrev = this->FindPreviousLabelList(12,i_ofStart,m_ucpBuffer+i_ofStart,sz);
 257:     if (usPrev!=i_ofStart) {
 258:       //cerr << "TryCompression: success " << i_ofStart << " to " << usPrev << endl;
 259:       usPrev += 0xC000;
 260:       this->SetPos(i_ofStart);
 261:       this->WriteNBO(usPrev);
 262:       return;
 263:     }
 264:     i_ofStart += (this->Get(i_ofStart) + 1);
 265:     sz = size_t(m_ofPos - i_ofStart);
 266:   }
 267:   //cerr << "TryCompression: no" << endl;
 268: }
 269: 
 270: 
 271: /********************
 272: *                   *
 273: *  METHOD WRITEBIT  *
 274: *                   *
 275: ********************/
 276: 
 277: 
 278: void Buffer::WriteBit(bool i_bBit, off_t i_off, unsigned char i_ucBit) {
 279:   assert(i_off<(off_t)m_szBuffer);
 280:   unsigned char ucVal = (1 << i_ucBit);
 281:   if (i_bBit==false) {
 282:     ucVal = 255 - ucVal;
 283:     m_ucpBuffer[i_off] &= ucVal;
 284:   } else {
 285:     m_ucpBuffer[i_off] |= ucVal;
 286:   }
 287: }
 288: 
 289: 
 290: /*********************
 291: *                    *
 292: *  METHOD WRITEBITS  *
 293: *                    *
 294: *********************/
 295: 
 296: 
 297: void Buffer::WriteBits(bool i_b7, bool i_b6, bool i_b5, bool i_b4, bool i_b3, bool i_b2, bool i_b1, bool i_b0) {
 298:   unsigned char uc = FromBits(i_b7,i_b6,i_b5,i_b4,i_b3,i_b2,i_b1,i_b0);
 299:   this->Write(uc);
 300: }
 301: 
 302: 
 303: /**********************
 304: *                     *
 305: *  METHODS WRITEDATA  *
 306: *                     *
 307: **********************/
 308: 
 309: 
 310: void Buffer::WriteData(const void *i_ptrData, size_t i_szData) {
 311:   this->WriteData(i_ptrData,i_szData,m_ofPos);
 312:   m_ofPos += i_szData;
 313: }
 314: 
 315: 
 316: void Buffer::WriteData(const void *i_ptrData, size_t i_szData, off_t i_of) {
 317:   //cerr << "Writing " << i_szData << " bytes at " << i_of << "/" << m_szBufferMax << endl;
 318:   if ((i_of+i_szData) > m_szBufferMax) 
 319:     throw BufferEx(FOUT("Buffer::WriteData: buffer overflow writing ",i_szData," bytes at ",i_of," (max ",m_szBufferMax-1,")"));
 320:   memcpy(m_ucpBuffer+i_of,i_ptrData,i_szData);
 321:   /* DEBUG:
 322:   HexDump(cerr,m_ucpBuffer+i_of,i_szData);
 323:   cerr << endl; */
 324:   if (m_szBuffer<(size_t)(i_of+i_szData)) m_szBuffer = (size_t)i_of + i_szData;
 325: }
 326: 
 327: 
 328: /**************************
 329: *                         *
 330: *  METHOD WRITELABELLIST  *
 331: *                         *
 332: **************************/
 333: 
 334: 
 335: unsigned short Buffer::WriteLabelList(LabelListConstPtr ci_llp, bool i_bUseCompression) {
 336:   LabelList::const_iterator lni;
 337:   off_t ofStart = m_ofPos;
 338: 
 339:   for(lni=ci_llp->begin();lni!=ci_llp->end();++lni) {
 340:     assert((*lni).GetLength()<64);
 341:     this->Write((unsigned char)(*lni).GetLength());
 342:     this->WriteData( (*lni).GetString(), (*lni).GetLength());
 343:   }
 344:   this->Write((unsigned char)0);
 345:   this->TryCompression(ofStart);
 346:   return (unsigned short)(m_ofPos-ofStart);
 347: }
 348: 
 349: 
 350: /**********************
 351: *                     *
 352: *  BUFFER DESTRUCTOR  *
 353: *                     *
 354: **********************/
 355: 
 356: 
 357: Buffer::~Buffer() {
 358:   SoftDeleteArray(m_ucpBuffer);
 359:   m_szBuffer = 0;
 360:   m_szBufferMax = 0;
 361: }
 362: 
 363: 
 364: /****************
 365: *               *
 366: *  OPERATOR <<  *
 367: *               *
 368: ****************/
 369: 
 370: 
 371: ostream& operator<<(ostream &io_smr, const Buffer &ci_bfr) {
 372:   ci_bfr.DumpRange(io_smr,0,ci_bfr.GetSize());
 373:   io_smr << std::endl;
 374:   return io_smr;
 375: }
 376: 
 377: 
 378: ostream& operator<<(ostream &io_smr, BufferConstPtr ci_bfp) {
 379:   io_smr << *ci_bfp;
 380:   return io_smr;    
 381: }
 382: 
 383: