Menu

FECFragmenter.h

Go to the documentation of this file.
00001 /*******************************************************************************
00002  *
00003  * Copyright (c) 2009-2010 Philipp Werner <philipp.werner@st.ovgu.de>
00004  *                         Michael Schulze <mschulze@ivs.cs.uni-magdeburg.de>
00005  * All rights reserved.
00006  *
00007  *    Redistribution and use in source and binary forms, with or without
00008  *    modification, are permitted provided that the following conditions
00009  *    are met:
00010  *
00011  *    * Redistributions of source code must retain the above copyright
00012  *      notice, this list of conditions and the following disclaimer.
00013  *
00014  *    * Redistributions in binary form must reproduce the above copyright
00015  *      notice, this list of conditions and the following disclaimer in
00016  *      the documentation and/or other materials provided with the
00017  *      distribution.
00018  *
00019  *    * Neither the name of the copyright holders nor the names of
00020  *      contributors may be used to endorse or promote products derived
00021  *      from this software without specific prior written permission.
00022  *
00023  *
00024  *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
00025  *    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00026  *    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00027  *    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00028  *    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00029  *    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00030  *    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00031  *    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00032  *    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00033  *    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00034  *    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00035  *
00036  *
00037  * $Id$
00038  *
00039  ******************************************************************************/
00040 
00041 
00042 #ifndef __FECFRAGMENTER_H_248EC79C4F9347__
00043 #define __FECFRAGMENTER_H_248EC79C4F9347__
00044 
00045 
00046 #include "debug.h"
00047 
00048 #include "mw/afp/frag/NoFECFragmenter.h"
00049 #include "mw/afp/frag/UseFEC.h"
00050 #include "mw/afp/shared/div_round_up.h"
00051 
00052 // memcpy
00053 #include <string.h>
00054 
00055 
00056 namespace famouso {
00057     namespace mw {
00058         namespace afp {
00059             namespace frag {
00060 
00061 
00069                 template < class FCP >
00070                 class FECFragmenter : public NoFECFragmenter<FCP> {
00071 
00072                         typedef NoFECFragmenter<FCP> Base;
00073 
00074                         typedef typename FCP::SizeProp::elen_t   elen_t;
00075                         typedef typename FCP::SizeProp::flen_t   flen_t;
00076                         typedef typename FCP::SizeProp::fcount_t fcount_t;
00077 
00078                         typedef class FCP::OverflowErrorChecking OverflowErrorCheck;
00079                         typedef UseFEC<FCP> FEC;
00080 
00081                     protected:
00082 
00084                         FEC fec;
00085 
00087                         bool redundancy;
00088 
00089                     public:
00090 
00092                         enum { min_header_length = Base::min_header_length + FEC::header_length };
00093 
00095                         enum { extension_header_length = Base::extension_header_length + FEC::header_length };
00096 
00103                         void init(const uint8_t * event_data, elen_t event_length, flen_t mtu) {
00104                             // Check if MTU is big enough (may be optimized away)
00105                             // (+1 to catch payload_length = 1 which will lead to payload_length = 0)
00106                             if (mtu <= min_header_length + 1) {
00107                                 Base::err = true;
00108                                 ::logging::log::emit< ::logging::Error>()
00109                                     << PROGMEMSTRING("AFP: MTU too small for selected features.")
00110                                     << ::logging::log::endl;
00111                                 return;
00112                             }
00113 
00114                             Base::err = false;
00115                             OverflowErrorCheck overflow_err;
00116 
00117                             // Find header and payload size and the number of fragments
00118 
00119                             flen_t header_length = min_header_length;
00120                             flen_t payload_length = mtu - header_length;
00121 
00122                             // FEC library supports only even paylaod lengths
00123                             if (payload_length & 1)
00124                                 payload_length--;
00125 
00126                             elen_t k = shared::div_round_up(event_length, (elen_t)payload_length);
00127                             overflow_err.check_equal(k, (fcount_t)k);
00128 
00129                             fcount_t frag_count = FEC::k2n(k);
00130                             overflow_err.check_smaller_or_equal(k, frag_count);
00131 
00132                             fcount_t max_fragments = 32;
00133 
00134                             while (frag_count > max_fragments &&
00135                                     !overflow_err.error()) {
00136                                 header_length++;
00137                                 payload_length = mtu - header_length;
00138                                 if (payload_length & 1)
00139                                     payload_length--;
00140 
00141                                 if (payload_length == 0)
00142                                     break;
00143 
00144                                 k = shared::div_round_up(event_length, (elen_t)payload_length);
00145                                 overflow_err.check_equal(k, (fcount_t)k);
00146 
00147                                 frag_count = FEC::k2n(k);
00148                                 overflow_err.check_smaller_or_equal(k, frag_count);
00149 
00150                                 overflow_err.check_smaller(max_fragments, max_fragments << 7);
00151                                 max_fragments <<= 7;
00152                             }
00153 
00154                             if (frag_count == k) {
00155                                 // No redundancy fragment -> use base class
00156                                 redundancy = false;
00157                                 Base::init(event_data, event_length, mtu);
00158                                 return;
00159                             } else {
00160                                 redundancy = true;
00161                             }
00162 
00163                             ::logging::log::emit< ::logging::Info>()
00164                                 << PROGMEMSTRING("AFP: Fragmenter: ")
00165                                 << ::logging::log::dec << static_cast<uint64_t>(event_length)
00166                                 << PROGMEMSTRING(" bytes data -> ")
00167                                 << static_cast<uint64_t>(payload_length)
00168                                 << PROGMEMSTRING(" bytes payload in ")
00169                                 << static_cast<uint64_t>(frag_count)
00170                                 << PROGMEMSTRING(" fragments")
00171                                 << ::logging::log::endl;
00172 
00173                             if (payload_length == 0 || overflow_err.error()) {
00174                                 Base::err = true;
00175                                 ::logging::log::emit< ::logging::Error>()
00176                                     << PROGMEMSTRING("AFP: Event of size ")
00177                                     << ::logging::log::dec << static_cast<uint64_t>(event_length)
00178                                     << PROGMEMSTRING(" could not be fragmented with this configuration (too large).")
00179                                     << ::logging::log::endl;
00180                                 return;
00181                             }
00182 
00183                             FAMOUSO_ASSERT(frag_count > 0);
00184                             Base::remaining_fragments = frag_count;
00185                             Base::next_header_shorten_fseq = get_next_header_shorten_fseq(frag_count-1);
00186 
00187                             Base::payload_length = payload_length;
00188                             Base::first_fragment = true;
00189                             Base::basic_header_length = header_length - extension_header_length;
00190                             Base::remaining_data = event_data;
00191                             Base::remaining_length = event_length;
00192 
00193                             fec.init(event_length, payload_length, k);
00194                         }
00195 
00196                     public:
00197 
00203                         flen_t get_fragment(uint8_t * fragment_data) {
00204                             if (!redundancy)
00205                                 return Base::get_fragment(fragment_data);
00206 
00207                             if (!Base::remaining_fragments)
00208                                 return 0;
00209 
00210                             Base::remaining_fragments--;
00211 
00212                             // Reduce header length?
00213                             if (Base::remaining_fragments == Base::next_header_shorten_fseq) {
00214                                 Base::basic_header_length--;
00215                                 Base::next_header_shorten_fseq = Base::get_next_header_shorten_fseq(Base::remaining_fragments);
00216                                 FAMOUSO_ASSERT(Base::basic_header_length > 0);
00217                             }
00218 
00219                             // Insert header (basic and non-FEC extension headers)
00220                             flen_t fragment_length = Base::get_header(fragment_data, true);
00221                             fragment_data += fragment_length;
00222 
00223                             // Insert FEC extension header
00224                             fec.get_header(fragment_data, false);
00225                             fragment_length += FEC::header_length;
00226                             fragment_data += FEC::header_length;
00227 
00228                             // Insert payload
00229                             if (Base::remaining_length == 0) {
00230 
00231                                 // Done with data fragments, get FEC redundancy fragment
00232                                 fec.get_red_fragment(fragment_data);
00233                                 fragment_length += Base::payload_length;
00234 
00235                             } else if (Base::remaining_length >= Base::payload_length) {
00236 
00237                                 // Get full data fragment
00238                                 memcpy(fragment_data, Base::remaining_data, Base::payload_length);
00239                                 fec.put_nonred_fragment(Base::remaining_data);
00240                                 fragment_length += Base::payload_length;
00241 
00242                                 Base::remaining_length -= Base::payload_length;
00243                                 Base::remaining_data += Base::payload_length;
00244 
00245                             } else {
00246 
00247                                 // Get smaller data fragment (smaller than max. payload)
00248                                 memcpy(fragment_data, Base::remaining_data, Base::remaining_length);
00249                                 fec.put_smaller_nonred_fragment(Base::remaining_data, Base::remaining_length);
00250                                 fragment_length += Base::remaining_length;
00251 
00252                                 Base::remaining_length = 0;
00253                             }
00254 
00255                             return fragment_length;
00256                         }
00257 
00258                 };
00259 
00260 
00261             } // namespace frag
00262         } // namespace afp
00263     } // namespace mw
00264 } // namespace famouso
00265 
00266 
00267 
00268 #endif // __FECFRAGMENTER_H_248EC79C4F9347__
00269