Menu

InOrderEventDataReconstructor.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 __INORDEREVENTDATARECONSTRUCTOR_H_3E331BC5510F68__
00042 #define __INORDEREVENTDATARECONSTRUCTOR_H_3E331BC5510F68__
00043 
00044 
00045 #include "debug.h"
00046 
00047 #include "mw/afp/defrag/detail/VarHeaderLength.h"
00048 
00049 
00050 namespace famouso {
00051     namespace mw {
00052         namespace afp {
00053             namespace defrag {
00054 
00055 
00065                 template <class DCP>
00066                 class InOrderEventDataReconstructor {
00067 
00068                         typedef typename DCP::SizeProp::elen_t elen_t;
00069                         typedef typename DCP::SizeProp::flen_t flen_t;
00070                         typedef typename DCP::SizeProp::fcount_t fcount_t;
00071 
00072                         typedef class DCP::DefragStatistics Statistics;
00073                         typedef class DCP::Allocator Allocator;
00074                         typedef detail::VarHeaderLength<DCP> VHL;
00075 
00076                     public:
00077 
00078                         typedef NoFECHeaderSupport<DCP> FECHeaderPolicy;
00079 
00080                     private:
00081 
00082                         uint8_t * event_data;             
00083 
00084                         elen_t event_length;              
00085 
00086                         fcount_t event_fragment_count;    
00087 
00088                         fcount_t arrived_fragment_count;  
00089 
00090                         flen_t no_ext_mtu;                
00091 
00092                     public:
00093 
00098                         InOrderEventDataReconstructor(flen_t no_ext_mtu)
00099                                 : event_data(0), event_length(0),
00100                                 event_fragment_count(0),
00101                                 arrived_fragment_count(0),
00102                                 no_ext_mtu(no_ext_mtu) {
00103                         }
00104 
00106                         ~InOrderEventDataReconstructor() {
00107                             if (!is_complete())
00108                                 Statistics::event_incomplete();
00109 
00110                             Statistics::fragments_currently_expected_sub(event_fragment_count - arrived_fragment_count);
00111 
00112                             if (event_data)
00113                                 Allocator::free(event_data);
00114                         }
00115 
00122                         void put_fragment(const Headers<DCP> & header, const uint8_t * data, flen_t length) {
00123                             // Only last fragment may be smaller than maximum
00124                             FOR_FAMOUSO_ASSERT_ONLY(bool wrong_mtu_or_frag_len = length != no_ext_mtu - VHL::get_basic_header_len(header.fseq) && header.fseq != 0);
00125                             FAMOUSO_ASSERT(!wrong_mtu_or_frag_len); // Wrong MTU will lead to undefined behaviour
00126                             FAMOUSO_ASSERT(!is_complete());         // Event should not be already complete
00127 
00128                             if (no_ext_mtu == 0)            // Do nothing on error status
00129                                 return;
00130                             if (header.fec.occurs()) {      // Cannot handle events using FEC -> error
00131                                 ::logging::log::emit< ::logging::Warning>()
00132                                     << PROGMEMSTRING("AFP: FEC not supported -> drop")
00133                                     << ::logging::log::endl;
00134                                 goto set_error;
00135                             }
00136 
00137                             if (!event_data) {
00138                                 // First fragment
00139                                 if (!header.first_fragment)
00140                                     goto set_error;
00141 
00142                                 event_fragment_count = header.fseq + 1;
00143 
00144                                 event_data = Allocator::alloc(VHL::get_payload(event_fragment_count, no_ext_mtu));
00145                                 if (!event_data) {
00146                                     ::logging::log::emit< ::logging::Warning>()
00147                                         << PROGMEMSTRING("AFP: Out of memory -> drop")
00148                                         << ::logging::log::endl;
00149                                     goto set_error;
00150                                 }
00151 
00152                                 memcpy(event_data, data, length);
00153 
00154                                 Statistics::fragments_expected(event_fragment_count);
00155                                 Statistics::fragments_currently_expected_add(event_fragment_count - 1);
00156                             } else {
00157                                 // Later fragment
00158                                 fcount_t seq_upcount = event_fragment_count - header.fseq - 1;
00159 
00160                                 if (seq_upcount != arrived_fragment_count)  // Packet loss or out of order -> error
00161                                     goto set_error;
00162 
00163                                 memcpy(event_data + event_length, data, length);
00164 
00165                                 Statistics::fragments_currently_expected_sub(1);
00166                             }
00167 
00168                             arrived_fragment_count++;
00169                             event_length += length;
00170 
00171                             Statistics::fragment_used();
00172 
00173                             if (is_complete())
00174                                 Statistics::event_complete();
00175 
00176                             return;
00177 
00178                         set_error:
00179                             no_ext_mtu = 0;
00180                             return;
00181                         }
00182 
00186                         bool is_complete() {
00187                             return get_data();
00188                         }
00189 
00194                         uint8_t * get_data() {
00195                             // To avoid an extra condition checking for initialization case this function is
00196                             // used to implement is_complete(). To achieve this the behaviour goes beyonds
00197                             // the specification of get_data(): it returns NULL in case of an incomplete
00198                             // event.
00199                             return (arrived_fragment_count == event_fragment_count && !error()) ? event_data : 0;
00200                         }
00201 
00206                         elen_t get_length() {
00207                             FAMOUSO_ASSERT(is_complete());
00208                             return event_length;
00209                         }
00210 
00214                         bool error() {
00215                             return no_ext_mtu == 0;
00216                         }
00217                 };
00218 
00219 
00220             } // namespace defrag
00221         } // namespace afp
00222     } // namespace mw
00223 } // namespace famouso
00224 
00225 
00226 #endif // __INORDEREVENTDATARECONSTRUCTOR_H_3E331BC5510F68__
00227