|
INET Framework for OMNeT++/OMNEST
|
00001 // 00002 // Copyright (C) 2008 Irene Ruengeler 00003 // Copyright (C) 2010 Thomas Dreibholz 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 #include "SCTPReceiveStream.h" 00020 #include "SCTPAssociation.h" 00021 00022 00023 SCTPReceiveStream::SCTPReceiveStream() 00024 { 00025 streamId = 0; 00026 expectedStreamSeqNum = 0; 00027 deliveryQ = new SCTPQueue(); 00028 orderedQ = new SCTPQueue(); 00029 unorderedQ = new SCTPQueue(); 00030 } 00031 00032 SCTPReceiveStream::~SCTPReceiveStream() 00033 { 00034 delete deliveryQ; 00035 delete orderedQ; 00036 delete unorderedQ; 00037 } 00038 00039 uint32 SCTPReceiveStream::reassemble(SCTPQueue* queue, uint32 tsn) 00040 { 00041 uint32 begintsn = tsn, endtsn = 0; 00042 00043 sctpEV3 << "Trying to reassemble message..." << endl; 00044 00045 /* test if we have all fragments down to the first */ 00046 while (orderedQ->getChunk(begintsn) && !(orderedQ->getChunk(begintsn))->bbit) 00047 begintsn--; 00048 00049 if (orderedQ->getChunk(begintsn)) 00050 { 00051 endtsn = begintsn; 00052 00053 /* test if we have all fragments up to the end */ 00054 while (orderedQ->getChunk(endtsn) && !(orderedQ->getChunk(endtsn))->ebit) 00055 endtsn++; 00056 00057 if (orderedQ->getChunk(endtsn)) 00058 { 00059 sctpEV3 << "All fragments found, now reassembling..." << endl; 00060 00061 SCTPDataVariables *firstVar = orderedQ->getChunk(begintsn), *processVar; 00062 SCTPSimpleMessage* firstSimple=check_and_cast<SCTPSimpleMessage*>(firstVar->userData); 00063 00064 sctpEV3 << "First fragment has " << firstVar->len / 8 << " bytes." << endl; 00065 00066 while (++begintsn <= endtsn) 00067 { 00068 processVar = orderedQ->getAndExtractChunk(begintsn); 00069 SCTPSimpleMessage* processSimple=check_and_cast<SCTPSimpleMessage*>(processVar->userData); 00070 00071 sctpEV3 << "Adding fragment with " << processVar->len / 8 << " bytes." << endl; 00072 00073 firstSimple->setDataArraySize(firstSimple->getDataArraySize() + processSimple->getDataArraySize()); 00074 firstSimple->setDataLen(firstSimple->getDataLen() + processSimple->getDataLen()); 00075 firstSimple->setByteLength(firstSimple->getByteLength() + processSimple->getByteLength()); 00076 /* copy data */ 00077 for (uint32 i = 0; i < (processVar->len / 8); i++) 00078 firstSimple->setData(i + (firstVar->len / 8), processSimple->getData(i)); 00079 00080 firstVar->len += processVar->len; 00081 00082 delete processVar->userData; 00083 delete processVar; 00084 } 00085 00086 firstVar->ebit = 1; 00087 00088 sctpEV3 << "Reassembly done. Length=" << firstVar->len<<"\n"; 00089 return firstVar->tsn; 00090 } 00091 } 00092 return tsn; 00093 } 00094 00095 00096 uint32 SCTPReceiveStream::enqueueNewDataChunk(SCTPDataVariables* dchunk) 00097 { 00098 uint32 delivery = 0; //0:orderedQ=false && deliveryQ=false; 1:orderedQ=true && deliveryQ=false; 2:oderedQ=true && deliveryQ=true; 3:fragment 00099 00100 SCTPDataVariables* chunk; 00101 //sctpEV3 << "Enqueueing NEW data chunk (TSN="<<dchunk->tsn<<") for Stream ID "<<dchunk->sid<<"\n"; 00102 /* append to the respective queue */ 00103 if (!dchunk->ordered) 00104 { 00105 if (dchunk->bbit && dchunk->ebit) 00106 { 00107 /* put message into deliveryQ */ 00108 if (deliveryQ->checkAndInsertChunk(dchunk->tsn, dchunk)) 00109 { 00110 delivery = 2; 00111 } 00112 } else { 00113 unorderedQ->checkAndInsertChunk(dchunk->tsn, dchunk); 00114 delivery = 3; 00115 00116 /* try to reassemble here */ 00117 uint32 reassembled = reassemble(unorderedQ, dchunk->tsn); 00118 00119 if ((unorderedQ->getChunk(reassembled))->bbit && (unorderedQ->getChunk(reassembled))->bbit) 00120 { 00121 /* put message into deliveryQ */ 00122 if (deliveryQ->checkAndInsertChunk(reassembled, unorderedQ->getAndExtractChunk(reassembled))) 00123 { 00124 delivery = 2; 00125 } 00126 } 00127 } 00128 } 00129 else if (dchunk->ordered) 00130 { 00131 /* put message into streams ->reassembyQ */ 00132 if (orderedQ->checkAndInsertChunk(dchunk->tsn, dchunk)) 00133 delivery = 1; 00134 00135 if (!dchunk->bbit || !dchunk->ebit) 00136 { 00137 delivery = 3; 00138 /* try to reassemble */ 00139 reassemble(orderedQ, dchunk->tsn); 00140 } 00141 00142 if (orderedQ->getQueueSize()>0) 00143 { 00144 /* dequeue first from orderedQ */ 00145 chunk = orderedQ->dequeueChunkBySSN(expectedStreamSeqNum); 00146 if (chunk) 00147 { 00148 if (deliveryQ->checkAndInsertChunk(chunk->tsn, chunk)) 00149 { 00150 ++expectedStreamSeqNum; 00151 if (expectedStreamSeqNum > 65535) 00152 expectedStreamSeqNum = 0; 00153 delivery = 2; 00154 } 00155 } 00156 } 00157 } 00158 00159 return delivery; 00160 }