rq.cc

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) Intel Corporation 2001. All rights reserved.
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *   http://www.apache.org/licenses/LICENSE-2.0
00008  *
00009  * Unless required by applicable law or agreed to in writing, software
00010  * distributed under the License is distributed on an "AS IS" BASIS,
00011  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012  * See the License for the specific language governing permissions and
00013  * limitations under the License.
00014 */
00015 
00016 /*
00017  * Copyright (c) 1991-1997 Regents of the University of California.
00018  * All rights reserved.
00019  *
00020  * Redistribution and use in source and binary forms, with or without
00021  * modification, are permitted provided that the following conditions
00022  * are met:
00023  * 1. Redistributions of source code must retain the above copyright
00024  *    notice, this list of conditions and the following disclaimer.
00025  * 2. Redistributions in binary form must reproduce the above copyright
00026  *    notice, this list of conditions and the following disclaimer in the
00027  *    documentation and/or other materials provided with the distribution.
00028  * 3. All advertising materials mentioning features or use of this software
00029  *    must display the following acknowledgement:
00030  *  This product includes software developed by the Computer Systems
00031  *  Engineering Group at Lawrence Berkeley Laboratory.
00032  * 4. Neither the name of the University nor of the Laboratory may be used
00033  *    to endorse or promote products derived from this software without
00034  *    specific prior written permission.
00035  *
00036  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00037  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00038  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00039  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00040  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00041  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00042  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00043  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00044  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00045  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00046  * SUCH DAMAGE.
00047  *
00048  */
00049 
00050 #include "rq.h"
00051 
00052 ReassemblyQueue::seginfo* ReassemblyQueue::freelist_ = NULL;
00053 
00054 ReassemblyQueue::seginfo* ReassemblyQueue::newseginfo()
00055 {
00056     seginfo *s;
00057     
00058     if( (s = freelist_) ){
00059         freelist_ = s->next_;
00060         return s;
00061     }else{
00062         return new seginfo;
00063     }
00064 }
00065 
00066 void ReassemblyQueue::deleteseginfo(ReassemblyQueue::seginfo* s)
00067 {
00068     s->next_ = freelist_;
00069     freelist_ = s;
00070 }
00071 
00072 /*
00073  * unlink a seginfo from its FIFO
00074  */
00075 void
00076 ReassemblyQueue::fremove(seginfo* p)
00077 {
00078     if (hint_ == p)
00079         hint_ = NULL;
00080 
00081     if (p->prev_)
00082         p->prev_->next_ = p->next_;
00083     else
00084         head_ = p->next_;
00085     if (p->next_)
00086         p->next_->prev_ = p->prev_;
00087     else
00088         tail_ = p->prev_;
00089 }
00090 
00091 /*
00092  * unlink a seginfo from its LIFO
00093  */
00094 void
00095 ReassemblyQueue::sremove(seginfo* p)
00096 {
00097     if (hint_ == p)
00098         hint_ = NULL;
00099 
00100     if (p->sprev_)
00101         p->sprev_->snext_ = p->snext_;
00102     else
00103         top_ = p->snext_;
00104     if (p->snext_)
00105         p->snext_->sprev_ = p->sprev_;
00106     else
00107         bottom_ = p->sprev_;
00108 
00109 }
00110 
00111 /*
00112  * push a seginfo on the LIFO
00113  */
00114 void
00115 ReassemblyQueue::push(seginfo *p)
00116 {
00117     p->snext_ = top_;
00118     p->sprev_ = NULL;
00119     top_ = p;
00120     if (p->snext_)
00121         p->snext_->sprev_ = p;
00122     else
00123         bottom_ = p;
00124 }
00125 
00126 /*
00127  * counts: return the # of blks and byte counts in
00128  * them starting at the given node
00129  */
00130 void
00131 ReassemblyQueue::cnts(seginfo *p, int& blkcnt, int& bytecnt)
00132 {
00133     int blks = 0;
00134     int bytes = 0;
00135 
00136     while (p != NULL) {
00137         ++blks;
00138         bytes += (p->endseq_ - p->startseq_);
00139         p = p->next_;
00140     }
00141     blkcnt = blks;
00142     bytecnt = bytes;
00143     return;
00144 }
00145 
00146 
00147 /*
00148  * clear out reassembly queue and stack
00149  */
00150 
00151 void
00152 ReassemblyQueue::clear()
00153 {
00154     // clear stack and end of queue
00155     tail_ = top_ = bottom_ = hint_ = NULL;
00156 
00157     seginfo *p = head_;
00158     while (head_) {
00159         p = head_;
00160         head_= head_->next_;
00161         ReassemblyQueue::deleteseginfo(p);
00162     }
00163     tail_ = NULL;
00164     total_ = 0;
00165     return;
00166 }
00167 
00168 /*
00169  * clear out reassembly queue (and stack) up
00170  * to the given sequence number
00171  */
00172 
00173 TcpFlag
00174 ReassemblyQueue::clearto(TcpSeq seq)
00175 {
00176     TcpFlag flag = 0;
00177     seginfo *p = head_, *q;
00178     while (p) {
00179         if (p->endseq_ <= seq) {
00180             q = p->next_;
00181             flag |= p->pflags_;
00182             total_ -= (p->endseq_ - p->startseq_);
00183             sremove(p);
00184             fremove(p);
00185             ReassemblyQueue::deleteseginfo(p);
00186             p = q;
00187         } else
00188             break;
00189     }
00190     /* we might be trimming in the middle */
00191     if (p && p->startseq_ <= seq && p->endseq_ > seq) {
00192         total_ -= (seq - p->startseq_);
00193         p->startseq_ = seq;
00194         flag |= p->pflags_;
00195     }
00196     return flag;
00197 }
00198 
00199 /*
00200  * gensack() -- generate 'maxsblock' sack blocks (start/end seq pairs)
00201  * at specified address
00202  * returns the number of blocks written into the buffer specified
00203  *
00204  * According to RFC2018, a sack block contains:
00205  *  left edge of block (first seq # of the block)
00206  *  right edge of block (seq# immed. following last seq# of the block)
00207  */
00208 
00209 int
00210 ReassemblyQueue::gensack(int *sacks, int maxsblock)
00211 {
00212     seginfo *p = top_;
00213     int cnt = maxsblock;
00214 
00215     while (p && maxsblock) {
00216         *sacks++ = p->startseq_;
00217         *sacks++ = p->endseq_;
00218         --maxsblock;
00219         p = p->snext_;
00220     }
00221     return (cnt - maxsblock);
00222 }
00223 
00224 /*
00225  * dumplist -- print out FIFO and LIFO (for debugging)
00226  */
00227 
00228 void
00229 ReassemblyQueue::dumplist()
00230 {
00231 
00232     printf("FIFO [size:%d]: ", total_);
00233     if (head_ == NULL) {
00234         printf("NULL\n");
00235     } else {
00236         register seginfo* p = head_;
00237         while (p != NULL) {
00238             if (p->rqflags_ & RQF_MARK) {
00239                 printf("OOPS: LOOP1\n");
00240                 abort();
00241             }
00242             printf("[->%d, %d<-<f:0x%x,c:%d>]",
00243                 p->startseq_, p->endseq_, p->pflags_, p->cnt_);
00244             p->rqflags_ |= RQF_MARK;
00245             p = p->next_;
00246         }
00247         printf("\n");
00248         p = tail_;
00249         while (p != NULL) {
00250             printf("[->%d, %d<-]",
00251                 p->startseq_, p->endseq_);
00252             p = p->prev_;
00253         }
00254         printf("\n");
00255     }
00256 
00257     printf("LIFO: ");
00258     if (top_ == NULL) {
00259         printf("NULL\n");
00260     } else {
00261         register seginfo* s = top_;
00262         while (s != NULL) {
00263             if (s->rqflags_ & RQF_MARK)
00264                 s->rqflags_ &= ~RQF_MARK;
00265             else {
00266                 printf("OOPS: LOOP2\n");
00267                 abort();
00268             }
00269             printf("[->%d, %d<-]",
00270                 s->startseq_, s->endseq_);
00271             s = s->snext_;
00272         }
00273         printf("\n");
00274         s = bottom_;
00275         while (s != NULL) {
00276             printf("[->%d, %d<-]",
00277                 s->startseq_, s->endseq_);
00278             s = s->sprev_;
00279         }
00280         printf("\n");
00281     }
00282     printf("RCVNXT: %d\n", rcv_nxt_);
00283     printf("\n");
00284     fflush(stdout);
00285 }
00286 
00287 /*
00288  *
00289  * add() -- add a segment to the reassembly queue
00290  *  this is where the real action is...
00291  *  add the segment to both the LIFO and FIFO
00292  *
00293  * returns the aggregate header flags covering the block
00294  * just inserted (for historical reasons)
00295  *
00296  * add start/end seq to reassembly queue
00297  * start specifies starting seq# for segment, end specifies
00298  * last seq# number in the segment plus one
00299  */
00300 
00301 TcpFlag
00302 ReassemblyQueue::add(TcpSeq start, TcpSeq end, TcpFlag tiflags, RqFlag rqflags)
00303 {
00304 
00305     int needmerge = FALSE;
00306     int altered = FALSE;
00307     int initcnt = 1;    // initial value of cnt_ for new blk
00308 
00309     if (end < start) {
00310         fprintf(stderr, "ReassemblyQueue::add() - end(%d) before start(%d)\n",
00311             end, start);
00312         abort();
00313     }
00314 
00315     if (head_ == NULL) {
00316         if (top_ != NULL) {
00317             fprintf(stderr, "ReassemblyQueue::add() - problem: FIFO empty, LIFO not\n");
00318             abort();
00319         }
00320 
00321         // nobody there, just insert this one
00322 
00323 
00324         tail_ = head_ = top_ = bottom_ =  ReassemblyQueue::newseginfo();
00325         head_->prev_ = head_->next_ = head_->snext_ = head_->sprev_ = NULL;
00326         head_->startseq_ = start;
00327         head_->endseq_ = end;
00328         head_->pflags_ = tiflags;
00329         head_->rqflags_ = rqflags;
00330         head_->cnt_ = initcnt;
00331 
00332         total_ = (end - start);
00333 
00334         //
00335         // this shouldn't really happen, but
00336         // do the right thing just in case
00337         if (rcv_nxt_ >= start)
00338             rcv_nxt_ = end;
00339 
00340         return (tiflags);
00341     } else {
00342 
00343 again2:
00344         seginfo *p = NULL, *q = NULL, *n, *r;
00345 
00346         //
00347         // in the code below, arrange for:
00348         // q: points to segment after this one
00349         // p: points to segment before this one
00350         //
00351 
00352         if (start >= tail_->endseq_) {
00353             // at tail, no overlap
00354             p = tail_;
00355             if (start == tail_->endseq_)
00356                 needmerge = TRUE;
00357             goto endfast;
00358         }
00359 
00360         if (end <= head_->startseq_) {
00361             // at head, no overlap
00362             q = head_;
00363             if (end == head_->startseq_)
00364                 needmerge = TRUE;
00365             goto endfast;
00366         }
00367 
00368         //
00369         // search for segments before and after
00370         // the new one; could be overlapped
00371         //
00372         q = head_;
00373         while (q && q->startseq_ < end)
00374             q = q->next_;
00375 
00376         p = tail_;
00377         while (p && p->endseq_ > start)
00378             p = p->prev_;
00379 
00380 #ifdef notdef
00381 printf("Thinking of merging (s:%d, e:%d), p:%p (%d,%d), q:%p (%d,%d) into: \n",
00382 start, end, p, q,
00383     p ? p->startseq_ : 0,
00384     p ? p->endseq_ : 0,
00385     q ? n->startseq_ : 0,
00386     q ? n->endseq_ : 0);
00387 #endif
00388 
00389 
00390         //
00391         // kill anything that is completely overlapped
00392         //
00393         r = p ? p : head_;
00394         while (r && r != q)  {
00395             if (start == r->startseq_ && end == r->endseq_) {
00396                 // exact overlap
00397                 r->pflags_ |= tiflags;
00398                 if (RQC_CNTDUPS == TRUE)
00399                     r->cnt_++;
00400                 return (r->pflags_);
00401             } else if (start <= r->startseq_ && end >= r->endseq_) {
00402                 // complete overlap, not exact
00403                 total_ -= (r->endseq_ - r->startseq_);
00404                 n = r;
00405                 r = r->next_;
00406                 tiflags |= n->pflags_;
00407                 initcnt += n->cnt_;
00408                 fremove(n);
00409                 sremove(n);
00410                 ReassemblyQueue::deleteseginfo(n);
00411                 altered = TRUE;
00412             } else
00413                 r = r->next_;
00414         }
00415 
00416 
00417         //
00418         // if we completely overlapped everything, the list
00419         // will now be empty.  In this case, just add the new one
00421 
00422         if (empty())
00423             goto endfast;
00424 
00425         if (altered) {
00426             altered = FALSE;
00427             goto again2;
00428         }
00429 
00430         // look for left-side merge
00431         // update existing seg's start seq with new start
00432         if (p == NULL || p->next_->startseq_ < start) {
00433             if (p == NULL)
00434                 p = head_;
00435             else
00436                 p = p->next_;
00437                 
00438             if (start < p->startseq_) {
00439                 total_ += (p->startseq_ - start);
00440                 p->startseq_ = start;
00441             }
00442             start = p->endseq_;
00443             needmerge = TRUE;
00444             p->pflags_ |= tiflags;
00445             p->cnt_++;
00446             --initcnt;
00447         }
00448 
00449         // look for right-side merge
00450         // update existing seg's end seq with new end
00451         if (q == NULL || q->prev_->endseq_ > end) {
00452             if (q == NULL)
00453                 q = tail_;
00454             else
00455                 q = q->prev_;
00456 
00457             if (end > q->endseq_) {
00458                 total_ += (end - q->endseq_);
00459                 q->endseq_ = end;
00460             }
00461             end = q->startseq_;
00462             needmerge = TRUE;
00463             q->pflags_ |= tiflags;
00464             if (!needmerge) {
00465                 // if needmerge is TRUE, that can
00466                 // only be the case if we did a left-side
00467                 // merge (above), which has already taken
00468                 // accounting of the new segment
00469                 q->cnt_++;
00470                 --initcnt;
00471             }
00472         }
00473 
00474 
00475         if (end <= start) {
00476             if (rcv_nxt_ >= head_->startseq_)
00477                 rcv_nxt_ = head_->endseq_;
00478             return (tiflags);
00479         }
00480             
00481 
00482         //
00483         // if p & q are adjacent and new one
00484         // fits between, that is an easy case
00485         //
00486 
00487         if (!needmerge && p->next_ == q && p->endseq_ <= start && q->startseq_ >= end) {
00488             if (p->endseq_ == start || q->startseq_ == end)
00489                 needmerge = TRUE;
00490         }
00491 
00492 endfast:
00493         n = ReassemblyQueue::newseginfo();
00494         n->startseq_ = start;
00495         n->endseq_ = end;
00496         n->pflags_ = tiflags;
00497         n->rqflags_ = rqflags;
00498         n->cnt_=  initcnt;
00499 
00500         n->prev_ = p;
00501         n->next_ = q;
00502 
00503         push(n);
00504 
00505         if (p)
00506             p->next_ = n;
00507         else
00508             head_ = n;
00509 
00510         if (q)
00511             q->prev_ = n;
00512         else
00513             tail_ = n;
00514 
00515 
00516         //
00517         // If there is an adjacency condition,
00518         // call coalesce to deal with it.
00519         // If not, there is a chance we inserted
00520         // at the head at the rcv_nxt_ point.  In
00521         // this case we ned to update rcv_nxt_ to
00522         // the end of the newly-inserted segment
00523         //
00524 
00525         total_ += (end - start);
00526 
00527         if (needmerge)
00528             return(coalesce(p, n, q));
00529         else if (rcv_nxt_ >= start) {
00530             rcv_nxt_ = end;
00531         }
00532 
00533         return tiflags;
00534     }
00535 }
00536 /*
00537  * We need to see if we can coalesce together the
00538  * blocks in and around the new block
00539  *
00540  * Assumes p is prev, n is new, p is after
00541  */
00542 TcpFlag
00543 ReassemblyQueue::coalesce(seginfo *p, seginfo *n, seginfo *q)
00544 {
00545     TcpFlag flags = 0;
00546 
00547 #ifdef RQDEBUG
00548 printf("coalesce(%p,%p,%p)\n", p, n, q);
00549 printf(" [(%d,%d),%d],[(%d,%d),%d],[(%d,%d),%d]\n",
00550     p ? p->startseq_ : 0,
00551     p ? p->endseq_ : 0,
00552     p ? p->cnt_ : -1000,
00553     n ? n->startseq_ : 0,
00554     n ? n->endseq_ : 0,
00555     n ? n->cnt_ : -1000,
00556     q ? n->startseq_ : 0,
00557     q ? n->endseq_ : 0,
00558     q ? n->cnt_ : -1000);
00559 dumplist();
00560 #endif
00561 
00562     if (p && q && p->endseq_ == n->startseq_ && n->endseq_ == q->startseq_) {
00563         // new block fills hole between p and q
00564         // delete the new block and the block after, update p
00565         sremove(n);
00566         fremove(n);
00567         sremove(q);
00568         fremove(q);
00569         p->endseq_ = q->endseq_;
00570         p->cnt_ += (n->cnt_ + q->cnt_);
00571         flags = (p->pflags_ |= n->pflags_);
00572         ReassemblyQueue::deleteseginfo(n);
00573         ReassemblyQueue::deleteseginfo(q);
00574     } else if (p && (p->endseq_ == n->startseq_)) {
00575         // new block joins p, but not q
00576         // update p with n's seq data, delete new block
00577         sremove(n);
00578         fremove(n);
00579         p->endseq_ = n->endseq_;
00580         flags = (p->pflags_ |= n->pflags_);
00581         p->cnt_ += n->cnt_;
00582         ReassemblyQueue::deleteseginfo(n);
00583     } else if (q && (n->endseq_ == q->startseq_)) {
00584         // new block joins q, but not p
00585         // update q with n's seq data, delete new block
00586         sremove(n);
00587         fremove(n);
00588         q->startseq_ = n->startseq_;
00589         flags = (q->pflags_ |= n->pflags_);
00590         q->cnt_ += n->cnt_;
00591         ReassemblyQueue::deleteseginfo(n);
00592         p = q;  // ensure p points to something
00593     }
00594 
00595     //
00596     // at this point, p points to the updated/coalesced
00597     // block.  If it advances the highest in-seq value,
00598     // update rcv_nxt_ appropriately
00599     //
00600     if (rcv_nxt_ >= p->startseq_)
00601         rcv_nxt_ = p->endseq_;
00602     return (flags);
00603 }
00604 
00605 /*
00606  * look for the next hole, starting with the given
00607  * sequence number.  If this seq number is contained in
00608  * a SACK block we have, return the ending sequence number
00609  * of the block.  Also, fill in the nxtcnt and nxtbytes fields
00610  * with the number and sum total size of the sack regions above
00611  * the block.
00612  */
00613 int
00614 ReassemblyQueue::nexthole(TcpSeq seq, int& nxtcnt, int& nxtbytes)
00615 {
00616 
00617     nxtbytes = nxtcnt = -1;
00618     hint_ = head_;
00619 
00620     seginfo* p;
00621     for (p = hint_; p; p = p->next_) {
00622         // seq# is prior to SACK region
00623         // so seq# is a legit hole
00624         if (p->startseq_ > seq) {
00625             cnts(p, nxtcnt, nxtbytes);
00626             return (seq);
00627         }
00628 
00629         // seq# is covered by SACK region
00630         // so the hole is at the end of the region
00631         if ((p->startseq_ <= seq) && (p->endseq_ >= seq)) {
00632             if (p->next_) {
00633                 cnts(p->next_, nxtcnt, nxtbytes);
00634             }
00635             return (p->endseq_);
00636         }
00637     }
00638     return (-1);
00639 }
00640 
00641 
00642 #ifdef RQDEBUG
00643 main()
00644 {
00645     int rcvnxt = 1;
00646     ReassemblyQueue rq(rcvnxt);
00647 
00648     static int blockstore[64];
00649     int *blocks = blockstore;
00650     int nblocks = 5;
00651     int i;
00652 
00653     printf("Simple---\n");
00654     rq.add(2, 4, 0, 0);
00655     rq.add(6, 8, 0, 0); // disc
00656     printf("D1\n");
00657     rq.dumplist();  // [(2,4),1], [(6,8),1]
00658 
00659     rq.add(1,2, 0, 0);  // l merge
00660     printf("D2\n");
00661     rq.dumplist();  // [(1,4),2], [(6,8),1]
00662 
00663     rq.add(8, 10, 0, 00);   // r merge
00664     printf("D3\n");
00665     rq.dumplist();  // [(1,4),2], [(6, 10),2]
00666 
00667     rq.add(4, 6, 0, 0); // m merge
00668     printf("Simple output:\n");
00669     rq.dumplist();  // [(1, 10),5]
00670 
00671     printf("X0:\n");
00672     rq.init(1);
00673     rq.add(5,10, 0, 0);
00674     rq.add(11,20, 0, 0);
00675     rq.add(5,10, 0, 0); // dup left
00676     rq.dumplist();  // [(5,10),1], [(11,20),1]
00677 
00678     printf("X1:\n");
00679     rq.init(1);
00680     rq.add(5,10, 0, 0);
00681     rq.add(11,20, 0, 0);
00682     rq.add(11,20, 0, 0);    // dup rt
00683     rq.dumplist();  // [(5,10),1], [(11,20),1]
00684 
00685     printf("X2:\n");
00686     rq.init(1);
00687     rq.add(5,10, 0, 0);
00688     rq.add(11,20, 0, 0);
00689     rq.add(30, 40, 0, 0);
00690     rq.add(11,20, 0, 0);    // dup mid
00691     rq.dumplist();  // [(5,10),1], [(11,20),1], [(30,40),1]
00692 
00693     printf("X3\n");
00694     rq.add(30,50,0,0);  // dup rt
00695     rq.dumplist();  // [(5,10),1], [(11,20),1], [(30,50),2]
00696 
00697     printf("X4\n");
00698     rq.add(1,10,0,0);   // dup lt
00699     rq.dumplist();  // [(1,10),2], [(11,20),1], [(30,50),2]
00700 
00701     printf("C1:\n");
00702     rq.init(1);
00703     rq.add(2, 4, 0, 0);
00704     rq.add(1, 4, 0, 0); // l overlap full
00705     rq.dumplist();  // [(1,4),2]
00706 
00707     printf("C2:\n");
00708     rq.init(1);
00709     rq.add(2, 4, 0, 0);
00710     rq.add(1, 3, 0, 0); // l overlap part
00711     rq.dumplist();  // [(1,4),2]
00712 
00713     printf("C3:\n");
00714     rq.init(1);
00715     rq.add(2, 4, 0, 0);
00716     rq.add(2, 7, 0, 0); // r overlap full
00717     rq.dumplist();  // [(2,7),2]
00718 
00719     printf("C4:\n");
00720     rq.init(1);
00721     rq.add(2, 4, 0, 0);
00722     rq.add(3, 7, 0, 0); // r overlap part
00723     rq.dumplist();  // [(2,7),2]
00724 
00725     printf("C5:\n");
00726     rq.init(1);
00727     rq.add(2, 4, 0, 0);
00728     rq.add(6, 8, 0, 0);
00729     rq.add(1, 9, 0, 0); // double olap - ends
00730     rq.dumplist();  // [(1,9),3]
00731 
00732     printf("C6:\n");
00733     rq.init(1);
00734     rq.add(2, 4, 0, 0);
00735     rq.add(6, 8, 0, 0);
00736     rq.add(15, 20, 0, 0);
00737     rq.dumplist();  // [(2,4),1], [(6,8),1], [(15,20),1]
00738     rq.add(5, 9, 0, 0); // overlap middle
00739     rq.dumplist();  // [(2,4),1], [(5,9),2], [(15,20),1]
00740 
00741     printf("C7:\n");
00742     rq.init(1);
00743     rq.add(1, 2, 0, 0);
00744     rq.add(3, 5, 0, 0);
00745     rq.add(6, 8, 0, 0);
00746     rq.add(9, 10, 0, 0);
00747     rq.dumplist();  // [(1,2),1],[(3,5),1],[(6,8),1],[(9,10),1]
00748     rq.add(4, 7, 0, 0); // double olap middle
00749     rq.dumplist();  // [(1,2),1], [(3,8),3], [(9,10),1]
00750 
00751     printf("C8:\n");
00752     rq.init(1);
00753     rq.add(1, 2, 0, 0);
00754     rq.add(3, 5, 0, 0);
00755     rq.add(10, 12, 0, 0);
00756     rq.add(20, 30, 0, 0);
00757     rq.dumplist();  // [(1,2),1], [(3,5),1], [(10,12),1], [(20,30),1]
00758     rq.add(4, 8, 0, 0); // single olap middle
00759     rq.dumplist();  // [(1,2),1], [(3,8),2], [(10,12),1], [(20,30),1]
00760 
00761     rq.init(1);
00762     rq.add(1, 5, 0, 0);
00763     rq.add(10, 20, 0, 0);
00764     //rq.add(40321, 41281, 0, 0);
00765     //rq.add(42241, 43201, 0, 0);
00766     //rq.add(44161, 45121, 0, 0);
00767     rq.dumplist();  // [(1,5),1], [(10,20),1]
00768     //rq.add(40321, 41281, 0, 0);
00769     rq.add(1, 5, 0, 0);
00770     rq.dumplist();  // [(1,5),1], [(10,20),1]
00771 
00772     int x, y;
00773     printf("NH1: %d\n", rq.nexthole(3, x, y));
00774     printf("NH2: %d\n", rq.nexthole(5, x, y));
00775     printf("CLR to 4\n");
00776     rq.clearto(4);
00777     rq.dumplist();
00778 
00779     exit(0);
00780 }
00781 #endif
00782 

Generated on Tue Mar 6 16:47:50 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6