text: var util          = require("util");
  var events        = require("events");
  var binding       = require("./build/Release/pcap_binding");
  var SocketWatcher = require("socketwatcher").SocketWatcher;
  var decode        = require("./decode").decode;
  var tcp_tracker   = require("./tcp_tracker");
  var DNSCache      = require("./dns_cache");
  var timers        = require("timers");
  
  exports.decode = decode;
  exports.TCPTracker = tcp_tracker.TCPTracker;
  exports.TCPSession = tcp_tracker.TCPSession;
  exports.DNSCache = DNSCache;
  
  function PcapSession(is_live, device_name, filter, buffer_size, outfile, is_monitor) {
      this.is_live = is_live;
      this.device_name = device_name;
      this.filter = filter || "";
      this.buffer_size = buffer_size;
      this.outfile = outfile || "";
      this.is_monitor = Boolean(is_monitor);
  
      this.link_type = null;
      this.fd = null;
      this.opened = null;
      this.buf = null;
      this.header = null;
      this.read_watcher = null;
      this.empty_reads = 0;
      this.packets_read = null;
  
      this.session = new binding.PcapSession();
  
      if (typeof this.buffer_size === "number" && !isNaN(this.buffer_size)) {
          this.buffer_size = Math.round(this.buffer_size);
      } else {
          this.buffer_size = 10 * 1024 * 1024; // Default buffer size is 10MB
      }
  
      var self = this;
  
      // called for each packet read by pcap
      function packet_ready() {
          self.on_packet_ready();
      }
  
      if (this.is_live) {
          this.device_name = this.device_name || binding.default_device();
          this.link_type = this.session.open_live(this.device_name, this.filter, this.buffer_size, this.outfile, packet_ready, this.is_monitor);
      } else {
          this.link_type = this.session.open_offline(this.device_name, this.filter, this.buffer_size, this.outfile, packet_ready, this.is_monitor);
      }
  
      this.fd = this.session.fileno();
      this.opened = true;
      this.buf = new Buffer(this.buffer_size || 65535);
      this.header = new Buffer(16);
  
      if (is_live) {
          this.readWatcher = new SocketWatcher();
  
          // readWatcher gets a callback when pcap has data to read. multiple packets may be readable.
          this.readWatcher.callback = function pcap_read_callback() {
              var packets_read = self.session.dispatch(self.buf, self.header);
              if (packets_read < 1) {
                  this.empty_reads += 1;
              }
          };
          this.readWatcher.set(this.fd, true, false);
          this.readWatcher.start();
      } else {
          timers.setImmediate(function() {
              var packets = 0;
              do {
                  packets = self.session.dispatch(self.buf, self.header);
              } while ( packets > 0 );
              self.emit("complete");
          });
      }
  
      events.EventEmitter.call(this);
  }
  util.inherits(PcapSession, events.EventEmitter);
  
  exports.lib_version = binding.lib_version();
  
  PcapSession.prototype.findalldevs = function () {
      return binding.findalldevs();
  };
  
  function PacketWithHeader(buf, header, link_type) {
      this.buf = buf;
      this.header = header;
      this.link_type = link_type;
  }
  
  PcapSession.prototype.on_packet_ready = function () {
      var full_packet = new PacketWithHeader(this.buf, this.header, this.link_type);
      this.emit("packet", full_packet);
  };
  
  PcapSession.prototype.close = function () {
      this.opened = false;
      this.session.close();
      this.readWatcher.stop();
      // TODO - remove listeners so program will exit I guess?
  };
  
  PcapSession.prototype.stats = function () {
      return this.session.stats();
  };
  
  PcapSession.prototype.inject = function (data) {
      return this.session.inject(data);
  };
  
  exports.Pcap = PcapSession;
  exports.PcapSession = PcapSession;
  
  exports.createSession = function (device, filter, buffer_size, monitor) {
      return new PcapSession(true, device, filter, buffer_size, null, monitor);
  };
  
  exports.createOfflineSession = function (path, filter) {
      return new PcapSession(false, path, filter, 0, null, null);
  };
  
  