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(h.version_major, swap_) != internals::version_major)
00231 throw std::invalid_argument ("Invalid PCAP major version");
00232 if (tool::extract_short(h.version_minor, swap_) != internals::version_minor)
00233 throw std::invalid_argument ("Invalid PCAP minor version");
00234
00235 zone_ = tool::extract_long_s(h.thiszone, swap_);
00236 snaplen_ = tool::extract_long_u(h.snaplen, swap_);
00237 type_ = link_type (tool::extract_long_u(h.linktype, swap_));
00238
00239 pkt_count_ = 0;
00240 if (build_index)
00241 setup_marks(f, pi_setup, pi_update);
00242 }
00243
00244 template <class Bottom>
00245 void
00246 descriptor<Bottom>::warn(const std::streampos& p, const std::string& msg)
00247 {
00248 std::cerr << file_name_ << ':' << p << ": WARNING: " << msg << '.'
00249 << std::endl;
00250 }
00251
00252 template <class Bottom>
00253 void
00254 descriptor<Bottom>::handle_truncation(const std::string& msg)
00255 {
00256 warn(file_size_, "corrupted file (" + msg + ')');
00257 if (not pkt_count_)
00258 throw std::invalid_argument ("Empty PCAP file");
00259 --pkt_count_;
00260 }
00261
00262 template <class Bottom>
00263 template <typename ProgressInfoSetupType,
00264 typename ProgressInfoUpdateType>
00265 void
00266 descriptor<Bottom>::setup_marks(std::istream& f,
00267 ProgressInfoSetupType& pi_setup,
00268 ProgressInfoUpdateType& pi_update)
00269 {
00270 # ifdef TIME_FILE_LOADING
00271 using namespace boost::posix_time;
00272
00273 const ptime start = microsec_clock::universal_time();
00274 # endif // TIME_FILE_LOADING
00275
00276 {
00277 const std::streampos first_packet_offset = f.tellg();
00278
00279 marks_.push_back(first_packet_offset);
00280 pi_setup(first_packet_offset, file_size_);
00281 }
00282
00283 internals::file_frame_header h;
00284
00285 while (f.read(reinterpret_cast<char*> (&h), sizeof (h)))
00286 {
00287 if (f.gcount() != sizeof (h))
00288 {
00289 handle_truncation("truncated packet header");
00290 break;
00291 }
00292
00293 char junk[junk_len];
00294
00295 h.caplen = tool::extract_long_u(h.caplen, swap_);
00296 while(h.caplen)
00297 {
00298 size_t to_read = std::min(sizeof (junk),
00299 size_t (h.caplen));
00300
00301 if (not f.read(junk, to_read))
00302 {
00303 handle_truncation("truncated packet data");
00304 break;
00305 }
00306 h.caplen -= to_read;
00307 }
00308
00309 if (++pkt_count_ % mark_step == 0)
00310 {
00311 const std::streampos current_offset = f.tellg();
00312
00313 marks_.push_back(current_offset);
00314 if (const std::string* e = pi_update(current_offset))
00315 throw tool::user_interruption (*e);
00316 }
00317 }
00318 pi_update(file_size_);
00319 if (f.bad())
00320 throw tool::file_error ("Unrecoverable corruption in PCAP file");
00321 f.clear();
00322
00323 # ifdef TIME_FILE_LOADING
00324 std::cerr << (microsec_clock::universal_time() - start) << std::endl;
00325 # endif // TIME_FILE_LOADING
00326 }
00327
00328 inline
00329 void
00330 dumper::operator () (const pkthdr* h, const void* f)
00331 {
00332
00333 {
00334 internals::file_frame_header h_;
00335
00336 h_.ts = h->ts;
00337 h_.caplen = h->caplen;
00338 h_.len = h->len;
00339
00340 if (not output_->write(reinterpret_cast<char*> (&h_), sizeof (h_)))
00341 throw tool::write_error("Could not write PCAP packet header");
00342 }
00343
00344
00345 if (not output_->write(static_cast<const char*> (f), h->caplen))
00346 throw tool::write_error("Could not write packet data");
00347
00348 if (++pkt_count_ % pcapxx::descriptor<tool::bottom>::mark_step == 0)
00349 marks_.push_back(output_->tellp());
00350 }
00351
00352 inline
00353 descriptor<tool::bottom>
00354 dumper::descriptor() const
00355 {
00356 return pcapxx::descriptor<tool::bottom> (file_name_, marks_, pkt_count_);
00357 }
00358
00359
00360 }
00361
00362 #endif // ! PCAP_DESCRIPTOR_HXX_