include/wipal/wifi/frame/filter/time_adjuster.hxx

00001 /*
00002  * WiPal - A library and a set of tools to manipulate wireless traces.
00003  * Copyright (C) 2007  Universite Pierre et Marie Curie - Paris 6
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00018  * MA  02110-1301  USA
00019  *
00020  * Author: Thomas Claveirole <thomas.claveirole@lip6.fr>
00021  */
00022 #ifndef WIFI_FRAME_FILTER_TIME_ADJUSTER_HXX_
00023 # define WIFI_FRAME_FILTER_TIME_ADJUSTER_HXX_
00024 
00025 # include "time_adjuster.hh"
00026 
00027 # include <boost/shared_ptr.hpp>
00028 # include <boost/shared_array.hpp>
00029 
00030 # include <wipal/phy/prism_header.hh>
00031 # include <wipal/wifi/frame/filter/microseconds_stamper.hh>
00032 # include <wipal/wifi/frame/filter/linear_regression_synchronizer.hh>
00033 
00034 namespace wifi
00035 {
00036   namespace frame
00037   {
00038     namespace filter
00039     {
00040 
00041       namespace internals
00042       {
00043 
00044         template <class I1, class I2, class HT, class B1, class B2>
00045         time_adjuster_iterator<I1, I2, HT, B1, B2>::
00046         time_adjuster_iterator(const iterable_type& i, bool end):
00047           super_type (),
00048           iterable_ (&i),
00049           next1_ (end ? i.last1_ : i.first1_),
00050           next2_ (end ? i.last2_ : i.first2_)
00051         {
00052           if (not end)
00053             increment();
00054         }
00055 
00056         template <class I1, class I2, class HT, class B1, class B2>
00057         bool
00058         time_adjuster_iterator<I1, I2, HT, B1, B2>::
00059         equal(const time_adjuster_iterator& rhs) const
00060         {
00061           if (not rhs.value())
00062             return not this->value();
00063           return next1_ == rhs.next1_;
00064         }
00065 
00066         template <class I1, class I2, class HT, class B1, class B2>
00067         void
00068         time_adjuster_iterator<I1, I2, HT, B1, B2>::increment()
00069         {
00070           using tool::endian::endianness;
00071 
00072           typedef tool::microseconds                            microseconds;
00073           typedef typename time_converter<>::time_values        time_values;
00074           typedef pcapxx::pkthdr                                pkthdr;
00075           typedef boost::shared_ptr<pkthdr>                     pkthdr_ptr;
00076           typedef boost::shared_array<uint8_t>                  bytes_ptr;
00077 
00078 
00079           if (next1_ == iterable_->last1_)
00080             {
00081               this->value() = boost::none_t ();
00082 
00083               // Flush next2_ so it may print a summary of its operation.
00084               while (next2_ != iterable_->last2_)
00085                 ++next2_;
00086 
00087               return;
00088             }
00089           update_coefs();
00090 
00091           const tool::microseconds      us (next1_->microseconds() *
00092                                             coefs_->first + coefs_->second);
00093           const time_values             tv = iterable_->convert_(us);
00094 
00095           const pcapxx::pkthdr* pcaph   = next1_->pcap_header().get();
00096           const size_t          caplen  = pcaph->caplen;
00097           const bool            swapped = need_swap(iterable_->phy_end_,
00098                                                     pcaph->swapped);
00099           const pkthdr_ptr      v_pcap_header (new pkthdr (*pcaph));
00100           const bytes_ptr       v_bytes       (new uint8_t[caplen]);
00101 
00102           v_pcap_header->ts = tv.pcaptime;
00103           memcpy(v_bytes.get(), next1_->bytes().get(), caplen);
00104           internals::adjust(reinterpret_cast<HT*> (v_bytes.get()),
00105                             caplen, swapped, tv);
00106           this->value() =
00107             value_type (us, pcapxx::frame_descriptor (v_pcap_header, v_bytes));
00108           ++next1_;
00109         }
00110 
00111         template <class I1, class I2, class HT, class B1, class B2>
00112         void
00113         time_adjuster_iterator<I1, I2, HT, B1, B2>::update_coefs()
00114         {
00115           const tool::microseconds      us = next1_->microseconds();
00116           const I2&                     last2 = iterable_->last2_;
00117 
00118           // FIXME: There used to be a bug in the following check.  It checked
00119           // FIXME: for next2_->*second*.microseconds() <= us instead of
00120           // FIXME: next2_->first.microseconds().  Unfortunately the current
00121           // FIXME: test suite does not catch this bug, though this is a
00122           // FIXME: dramatic malfunction.  One should write a regression
00123           // FIXME: test for this case.
00124           while (next2_ != last2 and next2_->first.microseconds() <= us)
00125             {
00126               coefs_ = next2_->coefs;
00127               ++next2_;
00128             }
00129           if (not coefs_)
00130             {
00131               if (next2_ != last2)
00132                 coefs_ = next2_->coefs;
00133               else
00134                 throw std::runtime_error ("No reference frames: "
00135                                           "impossible to synchronize");
00136             }
00137         }
00138 
00139         template <>
00140         inline
00141         time_converter<>
00142         time_reference<prism::header>(const pcapxx::pkthdr&     pcap_header,
00143                                       const prism::header*      bytes,
00144                                       tool::endian::endianness  phy_end)
00145         {
00146           using tool::endian::need_swap;
00147 
00148           if (pcap_header.caplen < sizeof (prism::header))
00149             return time_converter<> (pcap_header.ts, 0, 0,
00150                                      tool::microseconds (0));
00151 
00152           const bool     swapped  = need_swap(phy_end, pcap_header.swapped);
00153           const uint32_t hosttime = bytes->hosttime.get(swapped);
00154           const uint32_t mactime  = bytes->mactime.get(swapped);
00155 
00156           return time_converter<> (pcap_header.ts, hosttime, mactime,
00157                                    tool::microseconds (mactime));
00158         }
00159 
00160         template <>
00161         inline
00162         void
00163         adjust<prism::header>(prism::header* bytes, size_t caplen, bool swap,
00164                               const time_converter<>::time_values& time)
00165         {
00166           if (caplen < sizeof (prism::header))
00167             return;
00168 
00169           bytes->hosttime.set(time.hosttime, swap);
00170           bytes->mactime.set(time.mactime, swap);
00171         }
00172 
00173       } // End of namespace wifi::frame::filter::internals.
00174 
00175 
00176       template <class I1, class I2, class HT, class B>
00177       time_adjuster<I1, I2, HT, B>::
00178       time_adjuster(const I1& first1, const I1& last1,
00179                     const I2& first2, const I2& last2,
00180                     const pcapxx::frame_descriptor&     tref,
00181                     tool::endian::endianness            phy_end):
00182         convert_ (internals::time_reference(*tref.pcap_header(),
00183                                             reinterpret_cast<const HT*>
00184                                                           (tref.bytes().get()),
00185                                             phy_end)),
00186         phy_end_ (phy_end),
00187         first1_ (first1),
00188         last1_ (last1),
00189         first2_ (first2),
00190         last2_ (last2)
00191       {
00192       }
00193 
00194       namespace internals
00195       {
00196 
00197         template <class HT, class I1, class I2, class F>
00198         struct provide_time_adjuster
00199         {
00200           provide_time_adjuster(const I1& first1, const I1& last1,
00201                                 const I2& first2, const I2& last2,
00202                                 F&                              func,
00203                                 bool                            filter_prism,
00204                                 tool::endian::endianness        phy_end):
00205             first1_ (first1),
00206             last1_ (last1),
00207             first2_ (first2),
00208             last2_ (last2),
00209             func_ (func),
00210             filter_prism_ (filter_prism),
00211             phy_end_ (phy_end)
00212           {
00213           }
00214 
00215           template <class Synchronizer>
00216           void
00217           operator () (const Synchronizer& s)
00218           {
00219             if (first2_ == last2_)
00220               throw std::runtime_error ("No packets in reference trace. "
00221                                         "Cannot synchronize with no time "
00222                                         "reference and no unique frames");
00223             if (filter_prism_)
00224               {
00225                 typedef non_noisy_prism<I2>                     nnp;
00226                 typedef typename nnp::const_iterator            n_iterator;
00227                 typedef microseconds_stamper<n_iterator, HT>    us_stamper;
00228                 typedef typename us_stamper::const_iterator     u_iterator;
00229                 typedef typename Synchronizer::const_iterator   s_iterator;
00230                 typedef time_adjuster<u_iterator, s_iterator, HT> adjuster;
00231 
00232                 nnp             n (first1_, last1_);
00233                 us_stamper      u (n.begin(), n.end(), phy_end_);
00234                 adjuster        a (u.begin(), u.end(),
00235                                    s.begin(), s.end(), *first2_, phy_end_);
00236                 func_(a);
00237               }
00238             else
00239               {
00240                 typedef microseconds_stamper<I2, HT>            us_stamper;
00241                 typedef typename us_stamper::const_iterator     u_iterator;
00242                 typedef typename Synchronizer::const_iterator   s_iterator;
00243                 typedef time_adjuster<u_iterator, s_iterator, HT> adjuster;
00244 
00245                 us_stamper      u (first1_, last1_, phy_end_);
00246                 adjuster        a (u.begin(), u.end(),
00247                                    s.begin(), s.end(), *first2_, phy_end_);
00248                 func_(a);
00249               }
00250           }
00251 
00252         private:
00253           const I1&                     first1_;
00254           const I1&                     last1_;
00255           const I2&                     first2_;
00256           const I2&                     last2_;
00257           F&                            func_;
00258           bool                          filter_prism_;
00259           tool::endian::endianness      phy_end_;
00260         };
00261 
00262       } // End of namespace wifi::frame::filter::internals.
00263 
00264       template <class U, class HT, template <class, class, class> class Int,
00265                 class I1, class I2, class F, class BL>
00266       void
00267       provide_time_adjuster(const I1& first1, const I1& last1,
00268                             const I2& first2, const I2& last2,
00269                             addr_mapping&               mapping,
00270                             F&                          func,
00271                             bool                        filter_prism,
00272                             tool::endian::endianness    phy_end,
00273                             const BL&                   blist)
00274       {
00275         internals::provide_time_adjuster<HT, I1, I2, F> func2 (first1, last1,
00276                                                                first2, last2,
00277                                                                func,
00278                                                                filter_prism,
00279                                                                phy_end);
00280 
00281         provide_lr_synchronizer<U, HT, Int>(first1, last1,
00282                                             first2, last2,
00283                                             mapping, func2,
00284                                             filter_prism, phy_end, blist);
00285       }
00286 
00287     } // End of namespace wifi::frame::filter.
00288 
00289   } // End of namespace wifi::frame.
00290 
00291 } // End of namespace wifi.
00292 
00293 #endif // ! WIFI_FRAME_FILTER_TIME_ADJUSTER_HXX_

Generated on Tue Jan 15 19:32:31 2008 for wipal by  doxygen 1.5.4