Menu

OutOfOrderEventDataReconstructor.h

Go to the documentation of this file.
00001 /*******************************************************************************
00002  *
00003  * Copyright (c) 2009-2010 Philipp Werner <philipp.werner@st.ovgu.de>
00004  * All rights reserved.
00005  *
00006  *    Redistribution and use in source and binary forms, with or without
00007  *    modification, are permitted provided that the following conditions
00008  *    are met:
00009  *
00010  *    * Redistributions of source code must retain the above copyright
00011  *      notice, this list of conditions and the following disclaimer.
00012  *
00013  *    * Redistributions in binary form must reproduce the above copyright
00014  *      notice, this list of conditions and the following disclaimer in
00015  *      the documentation and/or other materials provided with the
00016  *      distribution.
00017  *
00018  *    * Neither the name of the copyright holders nor the names of
00019  *      contributors may be used to endorse or promote products derived
00020  *      from this software without specific prior written permission.
00021  *
00022  *
00023  *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
00024  *    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00025  *    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00026  *    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00027  *    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00028  *    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00029  *    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00030  *    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00031  *    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00032  *    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00033  *    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034  *
00035  *
00036  * $Id$
00037  *
00038  ******************************************************************************/
00039 
00040 
00041 #ifndef __OUTOFORDEREVENTDATARECONSTRUCTOR_H_3E331BC5510F68__
00042 #define __OUTOFORDEREVENTDATARECONSTRUCTOR_H_3E331BC5510F68__
00043 
00044 
00045 #include "debug.h"
00046 
00047 #include "mw/afp/defrag/detail/VarHeaderLength.h"
00048 
00049 #include <string.h>
00050 
00051 
00052 namespace famouso {
00053     namespace mw {
00054         namespace afp {
00055             namespace defrag {
00056 
00057 
00067                 template <class DCP>
00068                 class OutOfOrderEventDataReconstructor {
00069 
00070                         typedef typename DCP::SizeProp::elen_t elen_t;
00071                         typedef typename DCP::SizeProp::flen_t flen_t;
00072                         typedef typename DCP::SizeProp::fcount_t fcount_t;
00073 
00074                         typedef class DCP::DefragStatistics Statistics;
00075                         typedef class DCP::Allocator Allocator;
00076                         typedef detail::VarHeaderLength<DCP> VHL;
00077                         typedef typename VHL::eelen_t eelen_t;
00078 
00079                     public:
00080 
00081                         typedef NoFECHeaderSupport<DCP> FECHeaderPolicy;
00082 
00083                     protected:
00084 
00085                         uint8_t * event_data;             
00086                         uint8_t * behind_event_data;      
00087                         elen_t event_length;              
00088 
00089                         bool event_fragment_count_final;  
00090                         fcount_t event_fragment_count;    
00091 
00092                         fcount_t arrived_fragment_count;  
00093 
00094                         flen_t no_ext_mtu;                
00095 
00096 
00101                         void realloc_event_data(fcount_t new_fragment_count) {
00102                             eelen_t old_len = behind_event_data - event_data;
00103                             eelen_t new_len = VHL::get_payload(new_fragment_count, no_ext_mtu);
00104 
00105                             uint8_t * new_data = Allocator::alloc(new_len);
00106                             if (!new_data) {
00107                                 ::logging::log::emit< ::logging::Warning>()
00108                                     << PROGMEMSTRING("AFP: Out of memory -> drop")
00109                                     << ::logging::log::endl;
00110                                 no_ext_mtu = 0;
00111                                 return;
00112                             }
00113 
00114                             memcpy(new_data + (new_len - old_len), event_data, old_len);
00115                             Allocator::free(event_data);
00116 
00117                             event_data = new_data;
00118                             behind_event_data = new_data + new_len;
00119                             event_fragment_count = new_fragment_count;
00120                         }
00121                     public:
00122 
00127                         OutOfOrderEventDataReconstructor(flen_t no_ext_mtu)
00128                                 : event_data(0), event_length(0),
00129                                 event_fragment_count_final(false), event_fragment_count(0),
00130                                 arrived_fragment_count(0), no_ext_mtu(no_ext_mtu) {
00131                         }
00132 
00134                         ~OutOfOrderEventDataReconstructor() {
00135                             // Hack: check whether there is a derived class
00136                             // - event_data will surely be always not equal to the maximum pointer value
00137                             // - set event_data to maximum pointer in derived class if there is one
00138                             if (event_data != reinterpret_cast<uint8_t *>(-1)) {
00139                                 // There is no derived class
00140 
00141                                 // ... this check may have to be done in derived class
00142                                 if (!is_complete())
00143                                     Statistics::event_incomplete();
00144 
00145                                 Statistics::fragments_currently_expected_sub(event_fragment_count - arrived_fragment_count);
00146                                 if (event_data)
00147                                     Allocator::free(event_data);
00148                             }
00149                         }
00150 
00157                         void put_fragment(const Headers<DCP> & header, const uint8_t * data, flen_t length) {
00158                             // Only last fragment may be smaller than maximum
00159                             FOR_FAMOUSO_ASSERT_ONLY(bool wrong_mtu_or_frag_len = length != no_ext_mtu - VHL::get_basic_header_len(header.fseq) && header.fseq != 0);
00160                             FAMOUSO_ASSERT(!wrong_mtu_or_frag_len); // Wrong MTU will lead to undefined behaviour
00161                             FAMOUSO_ASSERT(!is_complete());         // Event should not be already complete
00162 
00163                             if (no_ext_mtu == 0)            // Do nothing on error status
00164                                 return;
00165                             if (header.fec.occurs()) {      // Cannot handle events using FEC -> error
00166                                 ::logging::log::emit< ::logging::Warning>()
00167                                     << PROGMEMSTRING("AFP: FEC not supported -> drop")
00168                                     << ::logging::log::endl;
00169                                 goto set_error;
00170                             }
00171 
00172                             if (header.first_fragment)
00173                                 event_fragment_count_final = true;
00174 
00175                             if (!event_data) {
00176                                 // put_fragment() called first time
00177                                 event_fragment_count = header.fseq + (header.first_fragment ? 1 : 2);
00178 
00179                                 eelen_t buffer_length = VHL::get_payload(event_fragment_count, no_ext_mtu);
00180                                 event_data = Allocator::alloc(buffer_length);
00181                                 if (!event_data) {
00182                                     ::logging::log::emit< ::logging::Warning>()
00183                                         << PROGMEMSTRING("AFP: Out of memory -> drop")
00184                                         << ::logging::log::endl;
00185                                     goto set_error;
00186                                 }
00187                                 behind_event_data = event_data + buffer_length;
00188 
00189                                 Statistics::fragments_expected(event_fragment_count);
00190                                 Statistics::fragments_currently_expected_add(event_fragment_count - 1);
00191 
00192                             } else if (header.fseq >= event_fragment_count) {
00193                                 // Current fragment much too late. It has to be placed somewhere in front of
00194                                 // all data chunks received till now
00195                                 fcount_t new_frag_count = header.fseq + 1;
00196                                 fcount_t additional_frag = new_frag_count - event_fragment_count;
00197 
00198                                 realloc_event_data(new_frag_count);
00199 
00200                                 Statistics::fragments_expected(additional_frag);
00201                                 Statistics::fragments_currently_expected_add(additional_frag - 1);
00202 
00203                             } else {
00204                                 // Fragment fitting in allocated buffer
00205                                 Statistics::fragments_currently_expected_sub(1);
00206                             }
00207 
00208                             // Copy into event_data buffer
00209                             memcpy(behind_event_data - VHL::get_payload(header.fseq + 1, no_ext_mtu), data, length);
00210 
00211                             arrived_fragment_count++;
00212                             event_length += length;
00213 
00214                             Statistics::fragment_used();
00215 
00216                             if (is_complete())
00217                                 Statistics::event_complete();
00218 
00219                             return;
00220 
00221                         set_error:
00222                             no_ext_mtu = 0;
00223                             return;
00224                         }
00225 
00229                         bool is_complete() {
00230                             return arrived_fragment_count == event_fragment_count && event_fragment_count_final && !error();
00231                         }
00232 
00237                         uint8_t * get_data() {
00238                             FAMOUSO_ASSERT(is_complete());
00239                             return event_data;
00240                         }
00241 
00246                         elen_t get_length() {
00247                             FAMOUSO_ASSERT(is_complete());
00248                             return event_length;
00249                         }
00250 
00254                         bool error() {
00255                             return no_ext_mtu == 0;
00256                         }
00257                 };
00258 
00259 
00260             } // namespace defrag
00261         } // namespace afp
00262     } // namespace mw
00263 } // namespace famouso
00264 
00265 
00266 #endif // __OUTOFORDEREVENTDATARECONSTRUCTOR_H_3E331BC5510F68__
00267