Menu

FECEventDataReconstructor.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 __FECEVENTDATARECONSTRUCTOR_H_3E331BC5510F68__
00042 #define __FECEVENTDATARECONSTRUCTOR_H_3E331BC5510F68__
00043 
00044 
00045 #if !defined(__AVR__)
00046 // Non-AVR version
00047 
00048 #include "debug.h"
00049 
00050 #include "mw/afp/defrag/OutOfOrderEventDataReconstructor.h"
00051 #include "mw/afp/defrag/detail/VarHeaderLength.h"
00052 #include "mw/afp/shared/expandrange_cast.h"
00053 #include "mw/afp/shared/div_round_up.h"
00054 
00055 #include <string.h>
00056 
00057 
00058 namespace famouso {
00059     namespace mw {
00060         namespace afp {
00061             namespace defrag {
00062 
00063 
00064                 namespace vandermonde_fec {
00065                     extern "C" {
00066 // Forward error correction library (packet erasure code based on vandermonde matrices)
00067 #include "fec.h"
00068                     }
00069                 }
00070 
00071 
00083                 template <class DCP>
00084                 class FECEventDataReconstructor : public OutOfOrderEventDataReconstructor<DCP> {
00085 
00086                         typedef OutOfOrderEventDataReconstructor<DCP> Base;
00087 
00088                         typedef typename DCP::SizeProp::elen_t elen_t;
00089                         typedef typename DCP::SizeProp::flen_t flen_t;
00090                         typedef typename DCP::SizeProp::fcount_t fcount_t;
00091 
00092                         typedef class DCP::DefragStatistics Statistics;
00093                         typedef class DCP::Allocator Allocator;
00094                         typedef detail::VarHeaderLength<DCP> VHL;
00095 
00096                     public:
00097 
00098                         typedef FECHeaderSupport<DCP> FECHeaderPolicy;
00099 
00100                     private:
00101 
00102                         uint8_t ** fragments_data; 
00103                         int * fragments_order;     
00104 
00105 
00106                         fcount_t k;                
00107 
00108                         void * fec_code;           
00109 
00110                         flen_t payload_length;     
00111 
00113                         static fcount_t get_redundancy_fragment_count(fcount_t k, uint8_t redundancy) {
00114                             return shared::div_round_up(shared::expandrange_cast(k) * redundancy,
00115                                                         shared::expandrange_cast((fcount_t)100));
00116                         }
00117 
00118                     public:
00119 
00124                         FECEventDataReconstructor(flen_t no_ext_mtu)
00125                                 : Base(no_ext_mtu), fragments_data(0), fragments_order(0), k(1), fec_code(0), payload_length(0) {
00126                         }
00127 
00129                         ~FECEventDataReconstructor() {
00130                             // The check cannot be done in base class. Thats why this class have to
00131                             // communicate with the base class to avoid double increment on
00132                             // statistics. Problem solved with a hack... see below.
00133                             if (!is_complete())
00134                                 Statistics::event_incomplete();
00135 
00136                             Statistics::fragments_currently_expected_sub(Base::event_fragment_count - Base::arrived_fragment_count);
00137 
00138                             if (fec_code)
00139                                 vandermonde_fec::fec_free(fec_code);
00140 
00141                             if (fragments_data) {
00142                                 for (fcount_t i = 0; i < k; i++)
00143                                     if (fragments_data[i])
00144                                         Allocator::free(fragments_data[i]);
00145                                 Allocator::free_array(fragments_data);
00146                             }
00147 
00148                             if (fragments_order)
00149                                 Allocator::free_array(fragments_order);
00150 
00151                             if (Base::event_data)
00152                                 Allocator::free(Base::event_data);
00153 
00154                             // Hack: give base class the information that there is a derived class
00155                             // - event_data will surely be always not equal to the maximum pointer value
00156                             // - set event_data to maximum pointer
00157                             Base::event_data = reinterpret_cast<uint8_t *>(-1);
00158 
00159                             // Base class destructor will be called...
00160                         }
00161 
00168                         void put_fragment(const Headers<DCP> & header, const uint8_t * data, flen_t length) {
00169                             FAMOUSO_ASSERT(!is_complete());       // Event should not be already complete
00170 
00171                             if (Base::error())                    // Do nothing on error status
00172                                 return;
00173 
00174                             if (!header.fec.occurs()) {           // Enter non FEC mode
00175                                 Base::put_fragment(header, data, length);
00176                                 k = 0;
00177                                 return;
00178                             } else if (k == 0) {                  // FEC fragment in non FEC mode -> drop
00179                                 goto set_error;
00180                             }
00181 
00182                             if (!fragments_data) {
00183                                 // put_fragment() called first time... init parameters from header
00184                                 k = header.fec.get_k();
00185                                 Base::event_fragment_count = k + get_redundancy_fragment_count(k, header.fec.get_red());
00186 
00187                                 payload_length = Base::no_ext_mtu - VHL::get_basic_header_len(Base::event_fragment_count - 1);
00188                                 // FEC library supports only even paylaod lengths
00189                                 if (payload_length & 1)
00190                                     payload_length--;
00191 
00192                                 Base::event_length = (k - 1) * payload_length + header.fec.get_len_rest();
00193 
00194                                 Statistics::fragments_expected(Base::event_fragment_count);
00195                                 Statistics::fragments_currently_expected_add(Base::event_fragment_count);
00196 
00197                                 fragments_data = Allocator::template alloc_array< uint8_t* >(k);
00198                                 fragments_order = Allocator::template alloc_array<int>(k);
00199 
00200                                 if (Base::event_fragment_count > 0xffff) {
00201                                     ::logging::log::emit< ::logging::Warning>()
00202                                         << PROGMEMSTRING("AFP: invalid FEC parameter (too many fragmens) -> drop")
00203                                         << ::logging::log::endl;
00204                                     goto set_error;
00205                                 }
00206 
00207                                 if (!fragments_data || !fragments_order) {
00208                                     ::logging::log::emit< ::logging::Warning>()
00209                                         << PROGMEMSTRING("AFP: Out of memory -> drop")
00210                                         << ::logging::log::endl;
00211                                     goto set_error;
00212                                 }
00213 
00214                                 memset(fragments_data, 0, k * sizeof(uint8_t *));
00215 
00216                                 ::logging::log::emit< ::logging::Info>()
00217                                     << PROGMEMSTRING("AFP: FEC: payload length ")
00218                                     << ::logging::log::dec
00219                                     << (unsigned int)payload_length
00220                                     << PROGMEMSTRING(", k ")
00221                                     << (unsigned int)k
00222                                     << PROGMEMSTRING(", n ")
00223                                     << (unsigned int)Base::event_fragment_count
00224                                     << ::logging::log::endl;
00225                             }
00226 
00227                             FAMOUSO_ASSERT(header.fseq < Base::event_fragment_count);
00228 
00229                             // Wrong MTU will lead to undefined behaviour...
00230                             // Only last non-redundancy fragment may be smaller than maximum
00231                             {
00232                                 FOR_FAMOUSO_ASSERT_ONLY(bool wrong_mtu_or_frag_len = length != payload_length && header.fseq != Base::event_fragment_count - k);
00233                                 FAMOUSO_ASSERT(!wrong_mtu_or_frag_len);
00234                             }
00235 
00236                             // Collect data
00237                             fragments_data[Base::arrived_fragment_count] = Allocator::alloc(payload_length);
00238                             if (!fragments_data[Base::arrived_fragment_count]) {
00239                                 // Do not set error... may be reconstructable although we have to drop this fragment
00240                                 ::logging::log::emit< ::logging::Warning>()
00241                                     << PROGMEMSTRING("AFP: Out of memory -> drop")
00242                                     << ::logging::log::endl;
00243                                 return;
00244                             }
00245 
00246                             memcpy(fragments_data[Base::arrived_fragment_count], data, length);
00247                             if (payload_length > length)
00248                                 memset(fragments_data[Base::arrived_fragment_count] + length, 0, payload_length - length);
00249 
00250                             fragments_order[Base::arrived_fragment_count] = Base::event_fragment_count - header.fseq - 1;
00251 
00252                             Base::arrived_fragment_count++;
00253 
00254                             Statistics::fragments_currently_expected_sub(1);
00255                             Statistics::fragment_used();
00256 
00257                             if (is_complete())
00258                                 Statistics::event_complete();
00259 
00260                             return;
00261 
00262                         set_error:
00263                             Base::no_ext_mtu = 0;
00264                             return;
00265                         }
00266 
00267 
00271                         bool is_complete() {
00272                             // In non FEC mode ask base class
00273                             if (k == 0)
00274                                 return Base::is_complete();
00275 
00276                             // If we have less than k fragments, reconstruction is not possible (yet).
00277                             return Base::arrived_fragment_count >= k && !Base::error();
00278                         }
00279 
00284                         uint8_t * get_data() {
00285                             // In non FEC mode ask base class
00286                             if (k == 0)
00287                                 return Base::get_data();
00288 
00289                             FAMOUSO_ASSERT(is_complete());
00290 
00291                             if (!Base::event_data) {
00292                                 fec_code = vandermonde_fec::fec_new(k, Base::event_fragment_count);
00293 
00294                                 Base::event_data = Allocator::alloc(Base::event_length);
00295                                 if (!fec_code || !Base::event_data) {
00296                                     ::logging::log::emit< ::logging::Warning>()
00297                                         << PROGMEMSTRING("AFP: Out of memory -> drop")
00298                                         << ::logging::log::endl;
00299                                     goto set_error;
00300                                 }
00301 
00302                                 // Decode data
00303                                 int err = vandermonde_fec::fec_decode(fec_code,
00304                                                                       reinterpret_cast<void **>(
00305                                                                           const_cast<uint8_t **>(fragments_data)
00306                                                                       ),
00307                                                                       fragments_order,
00308                                                                       payload_length);
00309                                 if (err != 0) {
00310                                     ::logging::log::emit< ::logging::Warning>()
00311                                         << PROGMEMSTRING("AFP: FEC decode error -> drop")
00312                                         << ::logging::log::endl;
00313                                     goto set_error;
00314                                 }
00315 
00316                                 // Copy to one output buffer
00317                                 uint8_t * p = Base::event_data;
00318                                 fcount_t km1 =  k - 1;
00319                                 for (fcount_t i = 0; i < km1; i++, p += payload_length)
00320                                     memcpy(p, fragments_data[i], payload_length);
00321                                 memcpy(p, fragments_data[km1], Base::event_length - (km1 * payload_length));
00322                             }
00323 
00324                             return Base::event_data;
00325 
00326                         set_error:
00327                             Base::no_ext_mtu = 0;
00328                             return 0;
00329                         }
00330 
00335                         elen_t get_length() {
00336                             FAMOUSO_ASSERT(is_complete());
00337                             return Base::event_length;
00338                         }
00339                 };
00340 
00341 
00342             } // namespace defrag
00343         } // namespace afp
00344     } // namespace mw
00345 } // namespace famouso
00346 
00347 
00348 #else
00349 // AVR version
00350 
00351 #include "assert/staticerror.h"
00352 
00353 namespace famouso {
00354     namespace mw {
00355         namespace afp {
00356             namespace defrag {
00357                 template <class DCP>
00358                 class FECEventDataReconstructor {
00359                     FAMOUSO_STATIC_ASSERT_ERROR(false, FEC_not_supported_on_AVR, ());
00360                 };
00361             } // namespace defrag
00362         } // namespace afp
00363     } // namespace mw
00364 } // namespace famouso
00365 
00366 #endif
00367 
00368 
00369 #endif // __FECEVENTDATARECONSTRUCTOR_H_3E331BC5510F68__
00370