src/probe-stats/wifi_stats.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_STATS_HXX_
00023 # define WIFI_STATS_HXX_
00024 
00025 # include <cmath>
00026 # include <iostream>
00027 
00028 # include <wipal/wifi/frame/frame.hh>
00029 
00030 # include "wifi_stats.hh"
00031 
00032 namespace wifi
00033 {
00034 
00035   namespace stats
00036   {
00037 
00038     /*-------------.
00039     | distribution |
00040     `-------------*/
00041 
00042     inline
00043     distribution::distribution(float min, float max, float gran):
00044       min_ (min),
00045       max_ (max),
00046       gran_ (gran),
00047       dist_ (2 + size_t (std::ceil((max - min) / gran))),
00048       total_ (0)
00049     {
00050     }
00051 
00052     inline
00053     void
00054     distribution::insert(float p)
00055     {
00056       size_t    i;
00057 
00058       if (p < min_)
00059         i = 0;
00060       else if (p > max_)
00061         i = dist_.size() - 1;
00062       else
00063         i = 1 + size_t ((p - min_) / gran_);
00064 
00065       ++dist_[i];
00066       ++total_;
00067     }
00068 
00069     inline
00070     std::ostream&
00071     operator << (std::ostream& os, const distribution& d)
00072     {
00073       return d.dump(os);
00074     }
00075 
00076     /*-------------.
00077     | timed_events |
00078     `-------------*/
00079 
00080     inline
00081     boost::posix_time::time_duration
00082     timed_events::insert(const ptime& ev)
00083     {
00084       const size_t      old_size = evs_.size();
00085 
00086       evs_.push_back(ev);
00087       return
00088         old_size ? ev - evs_[old_size - 1]: boost::posix_time::not_a_date_time;
00089     }
00090 
00091     inline
00092     const std::vector<boost::posix_time::ptime>&
00093     timed_events::evs() const
00094     {
00095       return evs_;
00096     }
00097 
00098     template <class C>
00099     std::vector<boost::posix_time::time_duration>
00100     its(const C& evs)
00101     {
00102       using boost::posix_time::time_duration;
00103 
00104       typedef typename C::const_iterator        const_iterator;
00105 
00106       std::vector<time_duration>        r;
00107 
00108       const_iterator    curr = evs.begin();
00109       for (const_iterator prev = curr++; curr != evs.end(); prev = curr++)
00110         r.push_back(*curr - *prev);
00111 
00112       return r;
00113     }
00114 
00115     template <class C>
00116     boost::posix_time::time_duration
00117     mean(const C& its)
00118     {
00119       boost::posix_time::time_duration  m (0, 0, 0, 0);
00120 
00121       for (typename C::const_iterator i = its.begin(); i != its.end(); ++i)
00122         m += *i;
00123       return m / its.size();
00124     }
00125 
00126     template <class C>
00127     boost::posix_time::time_duration
00128     stddev(const C& its, const boost::posix_time::time_duration* mean_)
00129     {
00130       using boost::posix_time::time_duration;
00131       using boost::posix_time::microseconds;
00132 
00133       time_duration     m = mean_ ? *mean_ : mean(its);
00134       double            d = 0;
00135 
00136       for (typename C::const_iterator i = its.begin(); i != its.end(); ++i)
00137         d += std::pow(double ((*i - m).total_microseconds()), 2);
00138       return microseconds (unsigned (std::sqrt(d / its.size())));
00139     }
00140 
00141     template <class C>
00142     boost::posix_time::time_duration
00143     median(const C& its)
00144     {
00145       using boost::posix_time::time_duration;
00146 
00147       const size_t                      s = its.size();
00148       const size_t                      m = s / 2;
00149       std::vector<time_duration>        r (m + 1);
00150 
00151       std::partial_sort_copy(its.begin(), its.end(), r.begin(), r.end());
00152       return s % 2 ? r[m] : (r[m - 1] + r[m]) / 2;
00153     }
00154 
00155     template <class C>
00156     distribution
00157     make_distribution(float min, float max, float gran, const C& its)
00158     {
00159       distribution      r (min, max, gran);
00160 
00161       for (typename C::const_iterator it = its.begin(); it != its.end(); ++it)
00162         r.insert(it->total_microseconds());
00163 
00164       return r;
00165     }
00166 
00167     /*-----------.
00168     | addr_state |
00169     `-----------*/
00170 
00171     inline
00172     addr_state::addr_state():
00173       pr_answers (),
00174       last_presp (0),
00175       heard_as_tmiter (0),
00176       mentioned_as_ap (0)
00177     {
00178       for (unsigned i = 0; i < sizeof (pr_stats) / sizeof (*pr_stats); ++i)
00179         pr_stats[i] = timed_events ();
00180     }
00181 
00182     inline
00183     addr_state::presp_attr::presp_attr():
00184       arrival (),
00185       ack_expected_arrival (),
00186       ack_arrival (),
00187       retries (0),
00188       acks (0)
00189     {
00190     }
00191 
00192     /*---------------.
00193     | probe_requests |
00194     `---------------*/
00195 
00196     inline
00197     probe_requests::probe_requests(addr_state_map& m):
00198       count (0),
00199       addrs (&m),
00200       it_dist (min, max, gran)
00201     {
00202     }
00203 
00204     inline
00205     void
00206     probe_requests::update(const frame::mgt::header     *frame,
00207                            const ptime&                 toa)
00208     {
00209       using boost::posix_time::time_duration;
00210       using frame::mgt::header;
00211 
00212       addr_state_map&   m = *addrs;
00213 
00214       count++;
00215       m[frame->addrs[header::da]].pr_stats[header::da].insert(toa);
00216       m[frame->addrs[header::bssid]].pr_stats[header::bssid].insert(toa);
00217 
00218       addr_state&       s = m[frame->addrs[header::sa]];
00219 
00220       const time_duration d = s.pr_stats[header::sa].insert(toa);
00221       if (not d.is_not_a_date_time())
00222         it_dist.insert(d.total_microseconds());
00223 
00224       s.pr_answers.push_back(addr_state::preq_answer_set ());
00225     }
00226 
00227     /*-------.
00228     | frames |
00229     `-------*/
00230 
00231     inline
00232     frames::frames():
00233       frame_count (0),
00234       total_len (0),
00235       total_caplen (0),
00236       phy_error_count (0),
00237       pr (addrs),
00238       first (),
00239       last ()
00240     {
00241     }
00242 
00243     inline
00244     void
00245     frames::update(const pcapxx::pkthdr* h, const void* f)
00246     {
00247       using boost::posix_time::microseconds;
00248 
00249       const ptime       toa = update_counters(h);
00250       const addr        *ta = frame::transmitter_address(f);
00251       const addr        *ba = frame::bssid_address(f);
00252 
00253       if (ta)
00254         ++addrs[*ta].heard_as_tmiter;
00255       if (ba and *ba != addr::broadcast())
00256         ++addrs[*ba].mentioned_as_ap;
00257 
00258       const frame::type::frame_type     ty = frame::type_of(f);
00259       const unsigned                    subty = frame::subtype_of(f);
00260 
00261       switch (ty)
00262         {
00263         case frame::type::management:
00264           {
00265             namespace mgt       = frame::mgt;
00266             namespace subtype   = frame::mgt::subtype;
00267 
00268             const mgt::header* mh = reinterpret_cast<const mgt::header*> (f);
00269 
00270             switch (subty)
00271               {
00272               case subtype::probe_req:
00273 //              std::cerr << toa << " PReq " << mh->addrs[mgt::header::sa]
00274 //                        << '\n';
00275 
00276                 pr.update(mh, toa);
00277                 break;
00278               case subtype::probe_resp:
00279                 {
00280                   typedef addr_state::pr_answers_t      pr_answers_t;
00281 
00282                   const addr&   sa = mh->addrs[mgt::header::sa];
00283                   const addr&   da = mh->addrs[mgt::header::da];
00284                   pr_answers_t& pr_answers = addrs[da].pr_answers;
00285 
00286 //                std::cerr << toa << " PResp " << sa << " -> " << da << '\n';
00287 
00288                   if (not pr_answers.empty())
00289                     {
00290                       typedef addr_state::presp_attr                presp_attr;
00291                       typedef addr_state::preq_answer_set::iterator iterator;
00292                       typedef
00293                         addr_state::preq_answer_set::value_type
00294                         value_type;
00295 
00296                       const unsigned duration =
00297                         ntohs(tool::extract_swapped_short(mh->duration));
00298                       if (duration > 32767)
00299                         std::cerr << "WARNING: Invalid duration." << std::endl;
00300 
00301                       std::pair<iterator, bool> insertion = pr_answers.back().
00302                         insert(value_type (sa, presp_attr ()));
00303                       presp_attr&               attr = insertion.first->second;
00304 
00305                       if (not insertion.second)
00306                         ++attr.retries;
00307                       addrs[sa].last_presp = &attr;
00308                       attr.arrival = toa;
00309                       attr.ack_expected_arrival = toa + microseconds(duration);
00310                       attr.ack_arrival = boost::posix_time::not_a_date_time;
00311                     }
00312                   break;
00313                 }
00314               default:
00315                 break;
00316               }
00317             break;
00318           }
00319 
00320         case frame::type::control:
00321           {
00322             namespace ack       = frame::ctl::ack;
00323             namespace subtype   = frame::ctl::subtype;
00324 
00325             if (subty == subtype::ack)
00326               {
00327                 const ack::header* ah =
00328                   reinterpret_cast<const ack::header*> (f);
00329 
00330 
00331                 addr_state::presp_attr* last_presp = addrs[ah->ra].last_presp;
00332 
00333                 if (last_presp and
00334                     toa < last_presp->ack_expected_arrival + microseconds(1))
00335                   {
00336                     ++last_presp->acks;
00337                     last_presp->ack_arrival = toa;
00338 
00339 //                  std::cerr << toa << " ACK -> " << ah->ra
00340 //                            << " (" << last_presp->acks << ", "
00341 //                            << (last_presp->ack_expected_arrival - toa)
00342 //                            << ")\n";
00343                   }
00344               }
00345           }
00346           break;
00347 
00348         default:
00349           break;
00350         }
00351     }
00352 
00353     inline
00354     void
00355     frames::update(const pcapxx::pkthdr* h, const prism::header* p)
00356     {
00357       if (p->noise.get(false)) // Incorrectly received frame.
00358         {
00359           update_counters(h);
00360           phy_error_count++;
00361           return;
00362         }
00363 
00364       update(h, reinterpret_cast<const void*> (p + 1));
00365     }
00366 
00367     inline
00368     boost::posix_time::ptime
00369     frames::update_counters(const pcapxx::pkthdr* h)
00370     {
00371       using boost::gregorian::date;
00372       using boost::gregorian::Jan;
00373       using boost::posix_time::seconds;
00374       using boost::posix_time::microseconds;
00375 
00376       const ptime       toa (date(1970, Jan, 01),
00377                              seconds (h->ts.tv_sec) +
00378                              microseconds (h->ts.tv_usec));
00379 
00380       if (first.is_not_a_date_time())
00381         first = toa;
00382       last = toa;
00383       frame_count++;
00384       total_len += h->len;
00385       total_caplen += h->caplen;
00386 
00387       return toa;
00388     }
00389 
00390   } // End of namespace wifi::stats.
00391 
00392 } // End of namespace wifi.
00393 
00394 #endif // ! WIFI_STATS_HXX_

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