00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef PCAP_DESCRIPTOR_HXX_
00023 # define PCAP_DESCRIPTOR_HXX_
00024
00025 # include <stdexcept>
00026 # include <fstream>
00027
00028 # include <boost/lexical_cast.hpp>
00029
00030 # include "descriptor.hh"
00031
00032 # include <wipal/tool/endianness.hh>
00033 # include <wipal/tool/exceptions.hh>
00034
00035 namespace pcapxx
00036 {
00037
00038 namespace internals
00039 {
00040
00042 struct DummySetup
00043 {
00044 inline
00045 void
00046 operator () (std::streampos, std::streampos)
00047 {
00048 }
00049 };
00050
00052 struct DummyUpdate
00053 {
00054 inline
00055 const std::string*
00056 operator () (std::streampos)
00057 {
00058 return 0;
00059 }
00060 };
00061
00062 }
00063
00064 template <class Bottom>
00065 descriptor<Bottom>::descriptor(const std::string& filename,
00066 bool build_index):
00067 super_type ()
00068 {
00069 internals::DummySetup pi_setup;
00070 internals::DummyUpdate pi_update;
00071
00072 setup(filename, build_index, pi_setup, pi_update);
00073 }
00074
00075 template <class Bottom>
00076 descriptor<Bottom>::descriptor(const std::string& filename,
00077 const index_type& marks,
00078 unsigned pkt_count):
00079 super_type (),
00080 marks_ (marks),
00081 pkt_count_ (pkt_count)
00082 {
00083 internals::DummySetup pi_setup;
00084 internals::DummyUpdate pi_update;
00085
00086 setup(filename, false, pi_setup, pi_update);
00087 }
00088
00089 template <class Bottom>
00090 template <typename ProgressInfoSetupType,
00091 typename ProgressInfoUpdateType>
00092 descriptor<Bottom>::descriptor(const std::string& filename,
00093 ProgressInfoSetupType& pi_setup,
00094 ProgressInfoUpdateType& pi_update):
00095 super_type ()
00096 {
00097 setup(filename, true, pi_setup, pi_update);
00098 }
00099
00100 template <class Bottom>
00101 typename descriptor<Bottom>::iterator
00102 descriptor<Bottom>::operator [] (size_t i)
00103 {
00104 assert(marks_.size() and "Cannot use operator [] without index.");
00105
00106 const size_t near_mark = i / mark_step;
00107 const size_t extra_steps = i % mark_step;
00108
00109 assert(i < pkt_count_);
00110 assert(near_mark < marks_.size());
00111
00112 iterator r (*this, marks_[near_mark], i - extra_steps);
00113
00114 for (unsigned j = 0; j < extra_steps; ++j)
00115 {
00116 ++r;
00117 assert(r != this->end());
00118 }
00119 return r;
00120 }
00121
00122 template <class Bottom>
00123 size_t
00124 descriptor<Bottom>::size() const
00125 {
00126 assert(marks_.size() and "Cannot use size() without index.");
00127
00128 return pkt_count_;
00129 }
00130
00131 template <class Bottom>
00132 bool
00133 descriptor<Bottom>::swapped() const
00134 {
00135 return swap_;
00136 }
00137
00138 template <class Bottom>
00139 int32_t
00140 descriptor<Bottom>::zone() const
00141 {
00142 return zone_;
00143 }
00144
00145 template <class Bottom>
00146 int32_t
00147 descriptor<Bottom>::snaplen() const
00148 {
00149 return snaplen_;
00150 }
00151
00152 template <class Bottom>
00153 typename descriptor<Bottom>::link_type
00154 descriptor<Bottom>::linktype() const
00155 {
00156 return type_;
00157 }
00158
00159 template <class Bottom>
00160 void
00161 descriptor<Bottom>::expect(link_type l) const
00162 {
00163 using boost::lexical_cast;
00164
00165 if (linktype() != l)
00166 throw std::invalid_argument (file_name() + ": Expected link type " +
00167 lexical_cast<std::string>(l) +
00168 ", got " +
00169 lexical_cast<std::string> (linktype()));
00170 }
00171
00172 template <class Bottom>
00173 std::streampos
00174 descriptor<Bottom>::file_size() const
00175 {
00176 return file_size_;
00177 }
00178
00179 template <class Bottom>
00180 const std::string&
00181 descriptor<Bottom>::file_name() const
00182 {
00183 return file_name_;
00184 }
00185
00186 template <class Bottom>
00187 dumper
00188 descriptor<Bottom>::dumper(const std::string& filename) const
00189 {
00190 return pcapxx::dumper (filename, int32_t (linktype()), snaplen());
00191 }
00192
00193 template <class Bottom>
00194 template <typename ProgressInfoSetupType,
00195 typename ProgressInfoUpdateType>
00196 void
00197 descriptor<Bottom>::setup(const std::string& filename,
00198 bool build_index,
00199 ProgressInfoSetupType& pi_setup,
00200 ProgressInfoUpdateType& pi_update)
00201 {
00202 internals::file_header h;
00203 std::ifstream f (filename.c_str(), (std::ios::in |
00204 std::ios::binary));
00205
00206 if (not f)
00207 throw tool::file_error ("Open failed");
00208 file_name_ = filename;
00209 if (not f.seekg(0, std::ios::end))
00210 throw tool::seek_error ("Seek operation failed");
00211 file_size_ = f.tellg();
00212 if (not f.seekg(0, std::ios::beg))
00213 throw tool::seek_error ("Seek operation failed");
00214
00215 if (not f.read(reinterpret_cast<char*> (&h), sizeof (h)) or
00216 f.gcount() != sizeof (h))
00217 throw tool::read_error ("Unreadable PCAP file header");
00218 switch (h.magic)
00219 {
00220 case 0xa1b2c3d4:
00221 swap_ = false;
00222 break;
00223 case 0xd4c3b2a1:
00224 swap_ = true;
00225 break;
00226 default:
00227 throw std::invalid_argument ("Not a PCAP trace");
00228 }
00229
00230 if (tool::extract_short_u(h.version_major, swap_) !=
00231 internals::version_major)
00232 throw std::invalid_argument ("Invalid PCAP major version");
00233 if (tool::extract_short_u(h.version_minor, swap_) !=
00234 internals::version_minor)
00235 throw std::invalid_argument ("Invalid PCAP minor version");
00236
00237 zone_ = tool::extract_long_s(h.thiszone, swap_);
00238 snaplen_ = tool::extract_long_u(h.snaplen, swap_);
00239 type_ = link_type (tool::extract_long_u(h.linktype, swap_));
00240
00241
00242
00243
00244 if (type_ == PRISM_HEADER)
00245 {
00246 const const_iterator b = this->begin();
00247
00248 if (b != this->end())
00249 {
00250 const unsigned magic =
00251 tool::extract_big_endian_long_u(b->bytes().get());
00252
00253 if ((magic & 0xFFFFFF00) == 0x80211000)
00254 type_ = IEEE802_11_RADIO_AVS;
00255 }
00256 }
00257
00258 pkt_count_ = 0;
00259 if (build_index)
00260 setup_marks(f, pi_setup, pi_update);
00261 }
00262
00263 template <class Bottom>
00264 void
00265 descriptor<Bottom>::warn(const std::streampos& p, const std::string& msg)
00266 {
00267 std::cerr << file_name_ << ':' << p << ": WARNING: " << msg << '.'
00268 << std::endl;
00269 }
00270
00271 template <class Bottom>
00272 void
00273 descriptor<Bottom>::handle_truncation(const std::string& msg)
00274 {
00275 warn(file_size_, "corrupted file (" + msg + ')');
00276 if (not pkt_count_)
00277 throw std::invalid_argument ("Empty PCAP file");
00278 --pkt_count_;
00279 }
00280
00281 template <class Bottom>
00282 template <typename ProgressInfoSetupType,
00283 typename ProgressInfoUpdateType>
00284 void
00285 descriptor<Bottom>::setup_marks(std::istream& f,
00286 ProgressInfoSetupType& pi_setup,
00287 ProgressInfoUpdateType& pi_update)
00288 {
00289 # ifdef WP_TIME_PCAP_LOADING
00290 using namespace boost::posix_time;
00291
00292 const ptime start = microsec_clock::universal_time();
00293 # endif // WP_TIME_PCAP_LOADING
00294
00295 {
00296 const std::streampos first_packet_offset = f.tellg();
00297
00298 marks_.push_back(first_packet_offset);
00299 pi_setup(first_packet_offset, file_size_);
00300 }
00301
00302 internals::file_frame_header h;
00303
00304 while (f.read(reinterpret_cast<char*> (&h), sizeof (h)))
00305 {
00306 if (f.gcount() != sizeof (h))
00307 {
00308 handle_truncation("truncated packet header");
00309 break;
00310 }
00311
00312 char junk[junk_len];
00313
00314 h.caplen = tool::extract_long_u(h.caplen, swap_);
00315 while(h.caplen)
00316 {
00317 size_t to_read = std::min(sizeof (junk),
00318 size_t (h.caplen));
00319
00320 if (not f.read(junk, to_read))
00321 {
00322 handle_truncation("truncated packet data");
00323 break;
00324 }
00325 h.caplen -= to_read;
00326 }
00327
00328 if (++pkt_count_ % mark_step == 0)
00329 {
00330 const std::streampos current_offset = f.tellg();
00331
00332 marks_.push_back(current_offset);
00333 if (const std::string* e = pi_update(current_offset))
00334 throw tool::user_interruption (*e);
00335 }
00336 }
00337 pi_update(file_size_);
00338 if (f.bad())
00339 throw tool::file_error ("Unrecoverable corruption in PCAP file");
00340 f.clear();
00341
00342 # ifdef WP_TIME_PCAP_LOADING
00343 std::cerr << (microsec_clock::universal_time() - start) << std::endl;
00344 # endif // WP_TIME_PCAP_LOADING
00345 }
00346
00347 inline
00348 void
00349 dumper::operator () (const pkthdr* h, const void* f)
00350 {
00351
00352 {
00353 internals::file_frame_header h_;
00354
00355 h_.ts = h->ts;
00356 h_.caplen = h->caplen;
00357 h_.len = h->len;
00358
00359 if (not output_->write(reinterpret_cast<char*> (&h_), sizeof (h_)))
00360 throw tool::write_error("Could not write PCAP packet header");
00361 }
00362
00363
00364 if (not output_->write(static_cast<const char*> (f), h->caplen))
00365 throw tool::write_error("Could not write packet data");
00366
00367 if (++pkt_count_ % pcapxx::descriptor<tool::bottom>::mark_step == 0)
00368 marks_.push_back(output_->tellp());
00369 }
00370
00371 inline
00372 descriptor<tool::bottom>
00373 dumper::desc() const
00374 {
00375 return pcapxx::descriptor<tool::bottom> (file_name_, marks_, pkt_count_);
00376 }
00377
00378
00379 }
00380
00381 #endif // ! PCAP_DESCRIPTOR_HXX_