Menu

NoFECFragmenter.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 __NOFECFRAGMENTER_H_248EC79C4F9347__
00043 #define __NOFECFRAGMENTER_H_248EC79C4F9347__
00044 
00045 
00046 #include "debug.h"
00047 
00048 #include "mw/afp/shared/div_round_up.h"
00049 #include "config/type_traits/ExpandedRangeTypeSelector.h"
00050 
00051 // memcpy
00052 #include <string.h>
00053 
00054 
00055 
00056 namespace famouso {
00057     namespace mw {
00058         namespace afp {
00059             namespace frag {
00060 
00061 
00068                 template < class FCP >
00069                 class NoFECFragmenter {
00070 
00071                         typedef typename FCP::SizeProp::elen_t   elen_t;
00072                         typedef typename FCP::SizeProp::flen_t   flen_t;
00073                         typedef typename FCP::SizeProp::fcount_t fcount_t;
00074 
00075                         typedef class FCP::EventSeqUsagePolicy EventSeqPolicy;
00076                         typedef class FCP::OverflowErrorChecking OverflowErrorCheck;
00077 
00078                     protected:
00079 
00081                         flen_t basic_header_length;
00082 
00084                         flen_t payload_length;
00085 
00087                         const uint8_t * remaining_data;
00088 
00090                         elen_t remaining_length;
00091 
00092 
00094                         fcount_t remaining_fragments;
00095 
00097                         fcount_t next_header_shorten_fseq;
00098 
00100                         bool first_fragment;
00101 
00102 
00104                         EventSeqPolicy event_seq;
00105 
00107                         bool err;
00108 
00109 
00110                     public:
00111 
00113                         enum { min_header_length = 1 + EventSeqPolicy::header_length };
00114 
00116                         enum { extension_header_length = EventSeqPolicy::header_length };
00117 
00124                         void init(const uint8_t * event_data, elen_t event_length, flen_t mtu) {
00125                             // Check if MTU is big enough (may be optimized away)
00126                             if (mtu <= min_header_length) {
00127                                 err = true;
00128                                 ::logging::log::emit< ::logging::Error>()
00129                                     << PROGMEMSTRING("AFP: MTU too small for selected features.")
00130                                     << ::logging::log::endl;
00131                                 return;
00132                             }
00133 
00134                             remaining_length = event_length;
00135 
00136                             err = false;
00137                             OverflowErrorCheck overflow_err;
00138 
00139                             // Find header and payload size and the number of fragments
00140                             elen_t rem_length = event_length;
00141                             fcount_t frag_count = 0;
00142                             flen_t header_length = min_header_length;
00143                             fcount_t curr_hl_frag_count = 32;
00144                             fcount_t max_frag_count = 32;
00145 
00146                             payload_length = mtu - header_length;
00147                             typedef typename ExpandedRangeTypeSelector<elen_t>::type eelen_t;
00148                             eelen_t curr_hl_payload = (eelen_t)curr_hl_frag_count * (eelen_t)payload_length;
00149                             overflow_err.check_equal(curr_hl_payload / payload_length, curr_hl_frag_count);
00150 
00151                             while (rem_length > curr_hl_payload &&
00152                                    !overflow_err.error()) {
00153                                 rem_length -= curr_hl_payload;
00154                                 overflow_err.check_smaller(frag_count, frag_count + curr_hl_frag_count);
00155                                 frag_count += curr_hl_frag_count;
00156                                 header_length++;
00157                                 payload_length--;
00158 
00159                                 if (header_length >= mtu)
00160                                     break;
00161 
00162                                 overflow_err.check_smaller(curr_hl_frag_count, 127 * curr_hl_frag_count);
00163                                 curr_hl_frag_count = 127 * max_frag_count;
00164 
00165                                 overflow_err.check_smaller(max_frag_count, max_frag_count << 7);
00166                                 max_frag_count <<= 7;
00167 
00168                                 curr_hl_payload = (eelen_t)curr_hl_frag_count * (eelen_t)payload_length;
00169                                 overflow_err.check_equal(curr_hl_payload / payload_length, curr_hl_frag_count);
00170                             }
00171 
00172                             if (header_length >= mtu || overflow_err.error()) {
00173                                 err = true;
00174                                 ::logging::log::emit< ::logging::Error>()
00175                                     << PROGMEMSTRING("AFP: Event of size ")
00176                                     << ::logging::log::dec << static_cast<uint64_t>(event_length)
00177                                     << PROGMEMSTRING(" could not be fragmented with this configuration (too large).")
00178                                     << ::logging::log::endl;
00179                                 return;
00180                             }
00181 
00182                             frag_count += shared::div_round_up(rem_length, (elen_t)payload_length);
00183 
00184                             ::logging::log::emit< ::logging::Info>()
00185                                 << PROGMEMSTRING("AFP: Fragmenter (no FEC): ")
00186                                 << ::logging::log::dec << static_cast<uint64_t>(remaining_length)
00187                                 << PROGMEMSTRING(" bytes data -> ")
00188                                 << static_cast<uint64_t>(payload_length)
00189                                 << PROGMEMSTRING(" bytes payload in ")
00190                                 << static_cast<uint64_t>(frag_count)
00191                                 << PROGMEMSTRING(" fragments")
00192                                 << ::logging::log::endl;
00193 
00194                             FAMOUSO_ASSERT(frag_count > 0);
00195                             remaining_fragments = frag_count;
00196                             next_header_shorten_fseq = get_next_header_shorten_fseq(frag_count-1);
00197 
00198                             basic_header_length = header_length - extension_header_length;
00199                             first_fragment = true;
00200                             remaining_data = event_data;
00201                         }
00202 
00203 
00209                         bool error() {
00210                             return err;
00211                         }
00212 
00218                         flen_t get_fragment(uint8_t * fragment_data) {
00219                             if (!remaining_fragments)
00220                                 return 0;
00221 
00222                             remaining_fragments--;
00223 
00224                             // Reduce header length? (and increase payload?)
00225                             if (remaining_fragments == next_header_shorten_fseq) {
00226                                 basic_header_length--;
00227                                 payload_length++;
00228                                 next_header_shorten_fseq = get_next_header_shorten_fseq(remaining_fragments);
00229                                 FAMOUSO_ASSERT(basic_header_length > 0);
00230                             }
00231 
00232                             // Insert header
00233                             flen_t fragment_length = get_header(fragment_data);
00234                             fragment_data += fragment_length;
00235 
00236                             // Insert payload
00237                             FAMOUSO_ASSERT(remaining_length > 0);
00238                             if (remaining_length >= payload_length) {
00239 
00240                                 // Get full data fragment
00241                                 memcpy(fragment_data, remaining_data, payload_length);
00242                                 fragment_length += payload_length;
00243 
00244                                 remaining_length -= payload_length;
00245                                 remaining_data += payload_length;
00246 
00247                             } else {
00248 
00249                                 // Get smaller data fragment (smaller than max. payload)
00250                                 memcpy(fragment_data, remaining_data, remaining_length);
00251                                 fragment_length += remaining_length;
00252 
00253                                 remaining_length = 0;
00254                             }
00255 
00256                             return fragment_length;
00257                         }
00258 
00259 
00260                     protected:
00261 
00266                         fcount_t get_next_header_shorten_fseq(fcount_t fseq) {
00267 
00268                             if (fseq <= 31)
00269                                 return (fcount_t)-1;
00270 
00271                             if (sizeof(fcount_t) == 1) {
00272                                 // One byte version
00273                                 return 31;
00274                             } else if (sizeof(fcount_t) == 2) {
00275                                 // Two byte version
00276                                 if (fseq <= 4095)
00277                                     return 31;
00278                                 else
00279                                     return (fcount_t)4095;
00280                             } else {
00281                                 // Generic version
00282                                 uint8_t c = 0;
00283 
00284                                 do {
00285                                     fseq >>= 7;
00286                                     c++;
00287                                 } while (fseq > 31);
00288 
00289                                 return (((fcount_t)1) << (7*c - 2)) - 1;
00290                             }
00291                         }
00292 
00293 
00300                         flen_t get_header(uint8_t * data, bool more_ext_hdr = false) {
00301                             // Write basic header
00302                             {
00303                                 fcount_t fseq = remaining_fragments;
00304 
00305                                 // TODO: support 8 byte basic header if (sizeof(fcount_t) > 4)
00306 
00307                                 // Fragment sequence number
00308                                 flen_t i = basic_header_length;
00309                                 while (i > 0) {
00310                                     data[--i] = fseq & 0xff;
00311                                     fseq >>= 8;
00312                                 }
00313 
00314                                 // Chaining
00315                                 uint8_t flags = (EventSeqPolicy::header_length || more_ext_hdr) ? 0x2 : 0;
00316 
00317                                 // First fragment
00318                                 if (first_fragment) {
00319                                     flags |= 0x1;
00320                                     first_fragment = false;
00321                                 }
00322 
00323 
00324                                 // Header length + write flags
00325                                 FAMOUSO_ASSERT(basic_header_length <= 6);
00326                                 FAMOUSO_ASSERT((data[0] & (0xff << (6 - basic_header_length))) == 0);
00327                                 data[0] |= ((0xf8 | flags) << (6 - basic_header_length));
00328                             }
00329                             data += basic_header_length;
00330 
00331                             // Write extension header: event sequence number
00332                             event_seq.get_header(data, more_ext_hdr);
00333                             data += EventSeqPolicy::header_length;
00334 
00335                             return basic_header_length + EventSeqPolicy::header_length;
00336                         }
00337                 };
00338 
00339 
00340             } // namespace frag
00341         } // namespace afp
00342     } // namespace mw
00343 } // namespace famouso
00344 
00345 
00346 
00347 #endif // __NOFECFRAGMENTER_H_248EC79C4F9347__
00348