src/wscout_pcap_trace.hxx

00001 /*
00002  * WScout - Lightweight PCAP visualizer.
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 
00023 #ifndef WSCOUT_PCAP_TRACE_HXX_
00024 # define WSCOUT_PCAP_TRACE_HXX_
00025 
00026 # include <iostream>
00027 
00028 # ifdef TIME_FILE_LOADING
00029 #  include <boost/date_time/posix_time/posix_time.hpp>
00030 # endif // BENCH_FILE_LOADING
00031 
00032 # include "wscout_pcap_trace.hh"
00033 
00034 namespace wscout
00035 {
00036 
00037   namespace pcap
00038   {
00039 
00041     inline
00042     uint32_t
00043     swap_u32(uint32_t i)
00044     {
00045       return (((i & 0xFF)       << 24) |
00046               ((i & 0xFF00)     <<  8) |
00047               ((i & 0xFF0000)   >>  8) |
00048               (i >> 24));
00049     }
00050 
00052     inline
00053     int32_t
00054     swap_s32(int32_t i)
00055     {
00056       return int32_t (swap_u32(uint32_t (i)));
00057     }
00058 
00059     namespace
00060     {
00061 
00062       struct DummySetup
00063       {
00064         inline
00065         void
00066         operator () (std::streampos, std::streampos)
00067         {
00068         }
00069       };
00070 
00071       struct DummyUpdate
00072       {
00073         inline
00074         const std::string*
00075         operator () (std::streampos)
00076         {
00077           return 0;
00078         }
00079       };
00080 
00081     } // End of anonymous namespace.
00082 
00083     inline
00084     Trace::invalid_operation::invalid_operation(const std::string& s):
00085       std::runtime_error (s)
00086     {
00087     }
00088 
00089     inline
00090     Trace::interrupted::interrupted(const std::string& s):
00091       std::runtime_error (s)
00092     {
00093     }
00094 
00095     inline
00096     Trace::Trace(const std::string& filename)
00097     {
00098       DummySetup        pi_setup;
00099       DummyUpdate       pi_update;
00100 
00101       setup(filename, pi_setup, pi_update);
00102     }
00103 
00104     template <typename ProgressInfoSetupType,
00105               typename ProgressInfoUpdateType>
00106     Trace::Trace(const std::string&             filename,
00107                  ProgressInfoSetupType&         pi_setup,
00108                  ProgressInfoUpdateType&        pi_update)
00109     {
00110       setup(filename, pi_setup, pi_update);
00111     }
00112 
00113     template <typename ProgressInfoSetupType,
00114               typename ProgressInfoUpdateType>
00115     void
00116     Trace::setup(const std::string&             filename,
00117                  ProgressInfoSetupType&         pi_setup,
00118                  ProgressInfoUpdateType&        pi_update)
00119     {
00120       pcap_file_header  h;
00121 
00122       file_.open(filename.c_str());
00123       if (not file_)
00124         throw invalid_operation ("Open failed");
00125       file_name_ = filename;
00126       if (not file_.seekg(0, std::ios::end))
00127         throw invalid_operation ("Seek operation failed");
00128       file_size_ = file_.tellg();
00129       if (not file_.seekg(0, std::ios::beg))
00130         throw invalid_operation ("Seek operation failed");
00131 
00132       if (not file_.read(reinterpret_cast<char*> (&h), sizeof (h)) or
00133           file_.gcount() != sizeof (h))
00134         throw invalid_operation ("Unreadable PCAP file header");
00135       switch (h.magic)
00136         {
00137         case 0xa1b2c3d4:
00138           swap_ = false;
00139           break;
00140         case 0xd4c3b2a1:
00141           swap_ = true;
00142           break;
00143         default:
00144           throw std::invalid_argument ("Not a PCAP trace");
00145         }
00146       zone_ = swap_ ? swap_s32(h.thiszone) : h.thiszone;
00147       type_ = link_type (swap_ ? swap_s32(h.linktype) : h.linktype);
00148 
00149       setup_marks(pi_setup, pi_update);
00150     }
00151 
00152     template <typename ProgressInfoSetupType,
00153               typename ProgressInfoUpdateType>
00154     void
00155     Trace::setup_marks(ProgressInfoSetupType&   pi_setup,
00156                        ProgressInfoUpdateType&  pi_update)
00157     {
00158 # ifdef TIME_FILE_LOADING
00159       using namespace boost::posix_time;
00160 
00161       const ptime start = microsec_clock::universal_time();
00162 # endif // TIME_FILE_LOADING
00163 
00164       pkt_count_ = 0;
00165 
00166       {
00167         const std::streampos    first_packet_offset = file_.tellg();
00168 
00169         marks_.push_back(first_packet_offset);
00170         pi_setup(first_packet_offset, file_size_);
00171       }
00172 
00173       pcap_packet_header        h;
00174 
00175       while (file_.read(reinterpret_cast<char*> (&h), sizeof (h)))
00176         {
00177           if (file_.gcount() != sizeof (h))
00178             {
00179               handle_truncation("truncated packet header");
00180               break;
00181             }
00182 
00183           char                  junk[junk_len];
00184 
00185           if (swap_)
00186             h.caplen = swap_u32(h.caplen);
00187           while(h.caplen) // Skip packet data.
00188             {
00189               size_t            to_read = std::min(sizeof (junk),
00190                                                    size_t (h.caplen));
00191 
00192               if (not file_.read(junk, to_read))
00193                 {
00194                   handle_truncation("truncated packet data");
00195                   break;
00196                 }
00197               h.caplen -= to_read;
00198             }
00199 
00200           if (++pkt_count_ % mark_step == 0)
00201             {
00202               const std::streampos      current_offset = file_.tellg();
00203 
00204               marks_.push_back(current_offset);
00205               if (const std::string* e = pi_update(current_offset))
00206                 throw interrupted (*e);
00207             }
00208         }
00209       pi_update(file_size_);
00210       if (file_.bad())
00211         throw invalid_operation ("Unrecoverable corruption in PCAP file");
00212       file_.clear();
00213 
00214 # ifdef TIME_FILE_LOADING
00215       std::cerr << (microsec_clock::universal_time() - start) << std::endl;
00216 # endif // TIME_FILE_LOADING
00217     }
00218 
00219   } // End of namespace pcap.
00220 
00221 } // End of namespace wscout.
00222 
00223 #endif // ! WSCOUT_PCAP_TRACE_HXX_

Generated on Wed Sep 12 16:02:49 2007 for WScout by  doxygen 1.5.3