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