Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Supporting multiple pcap sessions #27

Open
wants to merge 6 commits into from

3 participants

@rgulewich

I refactored the pcap binding to use a class so that it can support multiple sessions (and moved some code from JS to C++ in the process). I also improved some of the error messages.

I tested capturing on both Ubuntu 10.04 and OSX in live and offline modes, and haven't noticed any problems so far.

If you have any feedback or suggestions, let me know - I'd be happy to make any changes required.

rgulewich added some commits
@rgulewich rgulewich Refactor into a class to support multiple pcap sessions
Added error handling for setting BIOCIMMEDIATE on OSX
Only set BIOCIMMEDIATE for live captures. It fails when offline
Use pcap_geterr to get pcap_stats errors
195abbc
@rgulewich rgulewich decode UDP payload into 'data' attribute 69ae171
@rgulewich rgulewich Throw exception if pcap_dispatch returns an error. 318162b
@rgulewich rgulewich Stop the IOWatcher after closing the pcap session. 6c3ff34
@rgulewich rgulewich Emit an 'empty_read' event on empty read.
This can be useful for detecting when an interface has been unplumbed
out from underneath you, which causes the readWatcher to spin non-stop
(since the fd is constantly reporting data as available).
3b709ff
@rgulewich rgulewich Only increase the addresses array index when adding an item to it. 620de3d
@kandsten

This would be pretty damn useful to see pulled - the current limitation of only one interface is neither documented nor friendly.

@ujjwalt ujjwalt closed this
@ujjwalt ujjwalt reopened this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 26, 2011
  1. @rgulewich

    Refactor into a class to support multiple pcap sessions

    rgulewich authored
    Added error handling for setting BIOCIMMEDIATE on OSX
    Only set BIOCIMMEDIATE for live captures. It fails when offline
    Use pcap_geterr to get pcap_stats errors
  2. @rgulewich
Commits on Jun 6, 2011
  1. @rgulewich
  2. @rgulewich
  3. @rgulewich

    Emit an 'empty_read' event on empty read.

    rgulewich authored
    This can be useful for detecting when an interface has been unplumbed
    out from underneath you, which causes the readWatcher to spin non-stop
    (since the fd is constantly reporting data as available).
Commits on Jun 21, 2011
  1. @rgulewich
This page is out of date. Refresh to see the latest.
Showing with 247 additions and 165 deletions.
  1. +22 −24 pcap.js
  2. +225 −141 pcap_binding.cc
View
46 pcap.js
@@ -5,6 +5,7 @@ var util, IOWatcher,
Buffer = require('buffer').Buffer,
events = require('events'),
binding = require('./build/default/pcap_binding'),
+ Pcap = binding.Pcap,
HTTPParser = process.binding('http_parser').HTTPParser,
url = require('url');
@@ -16,20 +17,8 @@ if (process.versions && process.versions.node && process.versions.node.split('.'
IOWatcher = process.IOWatcher;
}
-function Pcap() {
- this.opened = false;
- this.fd = null;
-
- events.EventEmitter.call(this);
-}
-util.inherits(Pcap, events.EventEmitter);
-
exports.lib_version = binding.lib_version();
-Pcap.prototype.findalldevs = function () {
- return binding.findalldevs();
-};
-
Pcap.prototype.open = function (live, device, filter, buffer_size) {
var me = this;
@@ -40,14 +29,16 @@ Pcap.prototype.open = function (live, device, filter, buffer_size) {
}
if (live) {
- this.device_name = device || binding.default_device();
- this.link_type = binding.open_live(this.device_name, filter || "", this.buffer_size);
+ this.device_name = device || this.default_device();
+ this.open_live(this.device_name, filter || "", this.buffer_size);
} else {
this.device_name = device;
- this.link_type = binding.open_offline(this.device_name, filter || "", this.buffer_size);
+ this.open_offline(this.device_name, filter || "", this.buffer_size);
}
- this.fd = binding.fileno();
+ this.link_type = this.link_type();
+
+ this.fd = this.fileno();
this.opened = true;
this.readWatcher = new IOWatcher();
this.empty_reads = 0;
@@ -63,10 +54,11 @@ Pcap.prototype.open = function (live, device, filter, buffer_size) {
// 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 = binding.dispatch(me.buf, packet_ready);
+ var packets_read = me.dispatch(me.buf, packet_ready);
if (packets_read < 1) {
// TODO - figure out what is causing this, and if it is bad.
me.empty_reads += 1;
+ me.emit('empty_read', me.buf);
}
};
this.readWatcher.set(this.fd, true, false);
@@ -74,15 +66,11 @@ Pcap.prototype.open = function (live, device, filter, buffer_size) {
};
Pcap.prototype.close = function () {
- this.opened = false;
- binding.close();
+ this._close();
+ this.readWatcher.stop();
// TODO - remove listeners so program will exit I guess?
};
-Pcap.prototype.stats = function () {
- return binding.stats();
-};
-
exports.Pcap = Pcap;
exports.createSession = function (device, filter, buffer_size) {
@@ -578,7 +566,17 @@ decode.udp = function (raw_packet, offset) {
if (ret.sport === 53 || ret.dport === 53) {
ret.dns = decode.dns(raw_packet, offset + 8);
}
-
+
+ ret.data_offset = offset + 8;
+ ret.data_end = offset + 8 + ret.length;
+ ret.data_bytes = ret.data_end - ret.data_offset;
+ if (ret.data_bytes > 0) {
+ // add a buffer slice pointing to the data area of this UDP packet.
+ // Note that this does not make a copy
+ ret.data = raw_packet.slice(ret.data_offset, ret.data_end);
+ ret.data.length = ret.data_bytes;
+ }
+
return ret;
};
View
366 pcap_binding.cc
@@ -18,20 +18,43 @@
using namespace v8;
using namespace node;
-// These things need to be moved into a class, so each instance can have its own session.
-// Right now, there can only be one pcap session at a time.
-struct bpf_program fp;
-bpf_u_int32 mask;
-bpf_u_int32 net;
-pcap_t *pcap_handle;
+class Pcap: public EventEmitter {
+ public:
+ Pcap();
+ struct bpf_program fp;
+ bpf_u_int32 mask;
+ bpf_u_int32 net;
+ pcap_t *pcap_handle;
+ char *buffer_data;
+ size_t buffer_length;
+ Local<Function> * callback;
+ String * link_type;
+ int fd;
+ bool opened;
+
+
+ // Exposed to v8
+ static Handle<Value> New(const Arguments&);
+ static Handle<Value> Open(bool, const Arguments &);
+ static Handle<Value> OpenLive(const Arguments &);
+ static Handle<Value> OpenOffline(const Arguments &);
+ static Handle<Value> Close(const Arguments &);
+ static Handle<Value> LinkType(const Arguments &);
+ static Handle<Value> FileNo(const Arguments &);
+ static Handle<Value> FindAllDevs(const Arguments &);
+ static Handle<Value> Stats(const Arguments &);
+ static Handle<Value> DefaultDevice(const Arguments &);
+ static void Initialize(Handle<Object>);
+
+ // non-v8
+ void processPacket(const struct pcap_pkthdr*, const u_char*);
+};
-// buffer data and length are global. To support more than one pcap session, we'll need a class container.
-char *buffer_data;
-size_t buffer_length;
// PacketReady is called from within pcap, still on the stack of Dispatch. It should be called
// only one time per Dispatch, but sometimes it gets called 0 times. PacketReady invokes the
-// JS callback associated with the dispatch() call in JS.
+// callback stored in Pcap, which then invokes the JS callback associated with the dispatch()
+// call in JS.
//
// Stack:
// 1. readWatcher.callback (pcap.js)
@@ -39,12 +62,16 @@ size_t buffer_length;
// 3. Dispatch (binding.cc)
// 4. pcap_dispatch (libpcap)
// 5. PacketReady (binding.cc)
-// 6. binding.dispatch callback (pcap.js)
+// 6. pcap->processPacket (binding.cc)
+// 7. binding.dispatch callback (pcap.js)
//
-void PacketReady(u_char *callback_p, const struct pcap_pkthdr* pkthdr, const u_char* packet) {
- HandleScope scope;
+void PacketReady(u_char *pcap_p, const struct pcap_pkthdr* pkthdr, const u_char* packet) {
+ Pcap* pcap = (Pcap*) pcap_p;
+ pcap->processPacket(pkthdr, packet);
+}
- Local<Function> * callback = (Local<Function>*)callback_p;
+void Pcap::processPacket(const struct pcap_pkthdr* pkthdr, const u_char* packet) {
+ HandleScope scope;
size_t copy_len = pkthdr->caplen;
if (copy_len > buffer_length) {
@@ -75,6 +102,8 @@ Dispatch(const Arguments& args)
{
HandleScope scope;
+ Pcap* pcap = ObjectWrap::Unwrap<Pcap>(args.This());
+
if (args.Length() != 2) {
return ThrowException(Exception::TypeError(String::New("Dispatch takes exactly two arguments")));
}
@@ -89,159 +118,166 @@ Dispatch(const Arguments& args)
#if NODE_VERSION_AT_LEAST(0,3,0)
Local<Object> buffer_obj = args[0]->ToObject();
- buffer_data = Buffer::Data(buffer_obj);
- buffer_length = Buffer::Length(buffer_obj);
+ pcap->buffer_data = Buffer::Data(buffer_obj);
+ pcap->buffer_length = Buffer::Length(buffer_obj);
#else
Buffer *buffer_obj = ObjectWrap::Unwrap<Buffer>(args[0]->ToObject());
- buffer_data = buffer_obj->data();
- buffer_length = buffer_obj->length();
+ pcap->buffer_data = buffer_obj->data();
+ pcap->buffer_length = buffer_obj->length();
#endif
Local<Function> callback = Local<Function>::Cast(args[1]);
+ pcap->callback = &callback;
int packet_count, total_packets = 0;
do {
- packet_count = pcap_dispatch(pcap_handle, 1, PacketReady, (u_char *)&callback);
+ packet_count = pcap_dispatch(pcap->pcap_handle, 1, PacketReady, (u_char *)pcap);
+ if (packet_count < 0) {
+ return ThrowException(Exception::Error(String::New(pcap_geterr(pcap->pcap_handle))));
+ }
total_packets += packet_count;
- } while (packet_count > 0);
+ } while (packet_count > 0 && pcap->opened);
return scope.Close(Integer::NewFromUnsigned(total_packets));
}
-Handle<Value>
-Open(bool live, const Arguments& args)
-{
+Pcap::Pcap(): EventEmitter() {
+ opened = false;
+ fd = NULL;
+}
+
+Handle<Value> Pcap::New(const Arguments& args) {
HandleScope scope;
- char errbuf[PCAP_ERRBUF_SIZE];
+ Pcap * pcap = new Pcap();
- if (args.Length() == 3) {
- if (!args[0]->IsString()) {
- return ThrowException(Exception::TypeError(String::New("pcap Open: args[0] must be a String")));
- }
- if (!args[1]->IsString()) {
- return ThrowException(Exception::TypeError(String::New("pcap Open: args[1] must be a String")));
- }
- if (!args[2]->IsInt32()) {
- return ThrowException(Exception::TypeError(String::New("pcap Open: args[2] must be a Number")));
- }
- } else {
- return ThrowException(Exception::TypeError(String::New("pcap Open: expecting 3 arguments")));
+ if (pcap == NULL) {
+ return ThrowException(Exception::TypeError(String::New("pcap New: out of memory")));
}
- String::Utf8Value device(args[0]->ToString());
- String::Utf8Value filter(args[1]->ToString());
- int buffer_size = args[2]->Int32Value();
-
- if (live) {
- if (pcap_lookupnet((char *) *device, &net, &mask, errbuf) == -1) {
- net = 0;
- mask = 0;
- fprintf(stderr, "warning: %s - this may not actually work\n", errbuf);
- }
- pcap_handle = pcap_create((char *) *device, errbuf);
- if (pcap_handle == NULL) {
- return ThrowException(Exception::Error(String::New(errbuf)));
- }
+ pcap->Wrap(args.This());
+ return args.This();
+}
- // 64KB is the max IPv4 packet size
- if (pcap_set_snaplen(pcap_handle, 65535) != 0) {
- return ThrowException(Exception::Error(String::New("error setting snaplen")));
- }
+Handle<Value>
+Pcap::Open(bool live, const Arguments& args)
+{
+ HandleScope scope;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ Pcap* pcap = ObjectWrap::Unwrap<Pcap>(args.This());
- // always use promiscuous mode
- if (pcap_set_promisc(pcap_handle, 1) != 0) {
- return ThrowException(Exception::Error(String::New("error setting promiscuous mode")));
+ if (pcap == NULL) {
+ return ThrowException(Exception::TypeError(String::New("pcap Open: out of memory")));
}
- // Try to set buffer size. Sometimes the OS has a lower limit that it will silently enforce.
- if (pcap_set_buffer_size(pcap_handle, buffer_size) != 0) {
- return ThrowException(Exception::Error(String::New("error setting buffer size")));
+ if (args.Length() == 3) {
+ if (!args[0]->IsString()) {
+ return ThrowException(Exception::TypeError(String::New("pcap Open: args[0] must be a String")));
+ }
+ if (!args[1]->IsString()) {
+ return ThrowException(Exception::TypeError(String::New("pcap Open: args[1] must be a String")));
+ }
+ if (!args[2]->IsInt32()) {
+ return ThrowException(Exception::TypeError(String::New("pcap Open: args[2] must be a Number")));
+ }
+ } else {
+ return ThrowException(Exception::TypeError(String::New("pcap Open: expecting 3 arguments")));
}
+ String::Utf8Value device(args[0]->ToString());
+ String::Utf8Value filter(args[1]->ToString());
+ int buffer_size = args[2]->Int32Value();
+
+ if (live) {
+ if (pcap_lookupnet((char *) *device, &(pcap->net), &(pcap->mask), errbuf) == -1) {
+ pcap->net = 0;
+ pcap->mask = 0;
+ fprintf(stderr, "warning: %s - this may not actually work\n", errbuf);
+ }
- // set "timeout" on read, even though we are also setting nonblock below. On Linux this is required.
- if (pcap_set_timeout(pcap_handle, 1000) != 0) {
- return ThrowException(Exception::Error(String::New("error setting read timeout")));
- }
+ pcap->pcap_handle = pcap_create((char *) *device, errbuf);
+ if (pcap->pcap_handle == NULL) {
+ return ThrowException(Exception::Error(String::New(errbuf)));
+ }
- // TODO - pass in an option to enable rfmon on supported interfaces. Sadly, it can be a disruptive
- // operation, so we can't just always try to turn it on.
- // if (pcap_set_rfmon(pcap_handle, 1) != 0) {
- // return ThrowException(Exception::Error(String::New(pcap_geterr(pcap_handle))));
- // }
+ // 64KB is the max IPv4 packet size
+ if (pcap_set_snaplen(pcap->pcap_handle, 65535) != 0) {
+ return ThrowException(Exception::Error(String::New("error setting snaplen")));
+ }
+
+ // always use promiscuous mode
+ if (pcap_set_promisc(pcap->pcap_handle, 1) != 0) {
+ return ThrowException(Exception::Error(String::New("error setting promiscuous mode")));
+ }
+
+ // Try to set buffer size. Sometimes the OS has a lower limit that it will silently enforce.
+ if (pcap_set_buffer_size(pcap->pcap_handle, buffer_size) != 0) {
+ return ThrowException(Exception::Error(String::New("error setting buffer size")));
+ }
+
+ // set "timeout" on read, even though we are also setting nonblock below. On Linux this is required.
+ if (pcap_set_timeout(pcap->pcap_handle, 1000) != 0) {
+ return ThrowException(Exception::Error(String::New("error setting read timeout")));
+ }
- if (pcap_activate(pcap_handle) != 0) {
- return ThrowException(Exception::Error(String::New(pcap_geterr(pcap_handle))));
+ // TODO - pass in an option to enable rfmon on supported interfaces. Sadly, it can be a disruptive
+ // operation, so we can't just always try to turn it on.
+ // if (pcap_set_rfmon(pcap->pcap_handle, 1) != 0) {
+ // return ThrowException(Exception::Error(String::New(pcap_geterr(pcap->pcap_handle))));
+ // }
+
+ if (pcap_activate(pcap->pcap_handle) != 0) {
+ return ThrowException(Exception::Error(String::New(pcap_geterr(pcap->pcap_handle))));
+ }
+ } else {
+ // Device is the path to the savefile
+ pcap->pcap_handle = pcap_open_offline((char *) *device, errbuf);
+ if (pcap->pcap_handle == NULL) {
+ return ThrowException(Exception::Error(String::New(errbuf)));
+ }
}
- } else {
- // Device is the path to the savefile
- pcap_handle = pcap_open_offline((char *) *device, errbuf);
- if (pcap_handle == NULL) {
+
+ if (pcap_setnonblock(pcap->pcap_handle, 1, errbuf) == -1) {
return ThrowException(Exception::Error(String::New(errbuf)));
}
- }
-
- if (pcap_setnonblock(pcap_handle, 1, errbuf) == -1) {
- return ThrowException(Exception::Error(String::New(errbuf)));
- }
- // TODO - if filter is empty, don't bother with compile or set
- if (pcap_compile(pcap_handle, &fp, (char *) *filter, 1, net) == -1) {
- return ThrowException(Exception::Error(String::New(pcap_geterr(pcap_handle))));
- }
+ // TODO - if filter is empty, don't bother with compile or set
+ if (pcap_compile(pcap->pcap_handle, &(pcap->fp), (char *) *filter, 1, pcap->net) == -1) {
+ return ThrowException(Exception::Error(String::New(pcap_geterr(pcap->pcap_handle))));
+ }
- if (pcap_setfilter(pcap_handle, &fp) == -1) {
- return ThrowException(Exception::Error(String::New(pcap_geterr(pcap_handle))));
- }
+ if (pcap_setfilter(pcap->pcap_handle, &(pcap->fp)) == -1) {
+ return ThrowException(Exception::Error(String::New(pcap_geterr(pcap->pcap_handle))));
+ }
- // Work around buffering bug in BPF on OSX 10.6 as of May 19, 2010
- // This may result in dropped packets under load because it disables the (broken) buffer
- // http://seclists.org/tcpdump/2010/q1/110
+ // Work around buffering bug in BPF on OSX 10.6 as of May 19, 2010
+ // This may result in dropped packets under load because it disables the (broken) buffer
+ // http://seclists.org/tcpdump/2010/q1/110
#if defined(__APPLE_CC__) || defined(__APPLE__)
- #include <net/bpf.h>
- int fd = pcap_get_selectable_fd(pcap_handle);
- int v = 1;
- ioctl(fd, BIOCIMMEDIATE, &v);
- // TODO - check return value
+ #include <net/bpf.h>
+ if (live) {
+ int fd = pcap_get_selectable_fd(pcap->pcap_handle);
+ int v = 1;
+ if (ioctl(fd, BIOCIMMEDIATE, &v) == -1) {
+ return ThrowException(Exception::Error(String::New("error setting BIOCIMMEDIATE")));
+ }
+ }
#endif
-
- int link_type = pcap_datalink(pcap_handle);
-
- Local<Value> ret;
- switch (link_type) {
- case DLT_NULL:
- ret = String::New("LINKTYPE_NULL");
- break;
- case DLT_EN10MB: // most wifi interfaces pretend to be "ethernet"
- ret = String::New("LINKTYPE_ETHERNET");
- break;
- case DLT_IEEE802_11_RADIO: // 802.11 "monitor mode"
- ret = String::New("LINKTYPE_IEEE802_11_RADIO");
- break;
- case DLT_RAW: // "raw IP"
- ret = String::New("LINKTYPE_RAW");
- break;
- default:
- snprintf(errbuf, PCAP_ERRBUF_SIZE, "Unknown linktype %d", link_type);
- ret = String::New(errbuf);
- break;
- }
- return scope.Close(ret);
+ return Undefined();
}
Handle<Value>
-OpenLive(const Arguments& args)
+Pcap::OpenLive(const Arguments& args)
{
return Open(true, args);
}
Handle<Value>
-OpenOffline(const Arguments& args)
+Pcap::OpenOffline(const Arguments& args)
{
return Open(false, args);
}
Handle<Value>
-FindAllDevs(const Arguments& args)
+Pcap::FindAllDevs(const Arguments& args)
{
HandleScope scope;
char errbuf[PCAP_ERRBUF_SIZE];
@@ -263,7 +299,7 @@ FindAllDevs(const Arguments& args)
}
Local<Array> AddrArray = Array::New();
int j = 0;
- for (pcap_addr_t *cur_addr = cur_dev->addresses ; cur_addr != NULL ; cur_addr = cur_addr->next, j++) {
+ for (pcap_addr_t *cur_addr = cur_dev->addresses ; cur_addr != NULL ; cur_addr = cur_addr->next) {
if (cur_addr->addr && cur_addr->addr->sa_family == AF_INET) {
Local<Object> Address = Object::New();
@@ -283,6 +319,7 @@ FindAllDevs(const Arguments& args)
Address->Set(String::New("dstaddr"), String::New(inet_ntoa(sin->sin_addr)));
}
AddrArray->Set(Integer::New(j), Address);
+ j++;
}
// TODO - support AF_INET6
}
@@ -301,35 +338,38 @@ FindAllDevs(const Arguments& args)
}
Handle<Value>
-Close(const Arguments& args)
+Pcap::Close(const Arguments& args)
{
HandleScope scope;
+ Pcap* pcap = ObjectWrap::Unwrap<Pcap>(args.This());
- pcap_close(pcap_handle);
+ pcap_close(pcap->pcap_handle);
+ pcap->opened = false;
return Undefined();
}
Handle<Value>
-Fileno(const Arguments& args)
+Pcap::FileNo(const Arguments& args)
{
HandleScope scope;
+ Pcap* pcap = ObjectWrap::Unwrap<Pcap>(args.This());
- int fd = pcap_get_selectable_fd(pcap_handle);
+ int fd = pcap_get_selectable_fd(pcap->pcap_handle);
return scope.Close(Integer::NewFromUnsigned(fd));
}
Handle<Value>
-Stats(const Arguments& args)
+Pcap::Stats(const Arguments& args)
{
HandleScope scope;
+ Pcap* pcap = ObjectWrap::Unwrap<Pcap>(args.This());
struct pcap_stat ps;
- if (pcap_stats(pcap_handle, &ps) == -1) {
- return ThrowException(Exception::Error(String::New("Error in pcap_stats")));
- // TODO - use pcap_geterr to figure out what the error was
+ if (pcap_stats(pcap->pcap_handle, &ps) == -1) {
+ return ThrowException(Exception::Error(String::New(pcap_geterr(pcap->pcap_handle))));
}
Local<Object> stats_obj = Object::New();
@@ -342,8 +382,40 @@ Stats(const Arguments& args)
return scope.Close(stats_obj);
}
+
Handle<Value>
-DefaultDevice(const Arguments& args)
+Pcap::LinkType(const Arguments& args)
+{
+ HandleScope scope;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ Pcap* pcap = ObjectWrap::Unwrap<Pcap>(args.This());
+
+ int link_type = pcap_datalink(pcap->pcap_handle);
+
+ Local<Value> ret;
+ switch (link_type) {
+ case DLT_NULL:
+ ret = String::New("LINKTYPE_NULL");
+ break;
+ case DLT_EN10MB: // most wifi interfaces pretend to be "ethernet"
+ ret = String::New("LINKTYPE_ETHERNET");
+ break;
+ case DLT_IEEE802_11_RADIO: // 802.11 "monitor mode"
+ ret = String::New("LINKTYPE_IEEE802_11_RADIO");
+ break;
+ case DLT_RAW: // "raw IP"
+ ret = String::New("LINKTYPE_RAW");
+ break;
+ default:
+ snprintf(errbuf, PCAP_ERRBUF_SIZE, "Unknown linktype %d", link_type);
+ ret = String::New(errbuf);
+ break;
+ }
+ return scope.Close(ret);
+}
+
+Handle<Value>
+Pcap::DefaultDevice(const Arguments& args)
{
HandleScope scope;
char errbuf[PCAP_ERRBUF_SIZE];
@@ -388,17 +460,29 @@ LibVersion(const Arguments &args)
return scope.Close(String::New(pcap_lib_version()));
}
+void Pcap::Initialize(Handle<Object> target) {
+ Local<FunctionTemplate> t = FunctionTemplate::New(New);
+ t->Inherit(EventEmitter::constructor_template);
+ t->InstanceTemplate()->SetInternalFieldCount(1);
+
+ // Class methods
+ NODE_SET_PROTOTYPE_METHOD(t, "findalldevs", FindAllDevs);
+ NODE_SET_PROTOTYPE_METHOD(t, "open_live", OpenLive);
+ NODE_SET_PROTOTYPE_METHOD(t, "open_offline", OpenOffline);
+ NODE_SET_PROTOTYPE_METHOD(t, "dispatch", Dispatch);
+ NODE_SET_PROTOTYPE_METHOD(t, "fileno", FileNo);
+ NODE_SET_PROTOTYPE_METHOD(t, "link_type", LinkType);
+ NODE_SET_PROTOTYPE_METHOD(t, "_close", Close);
+ NODE_SET_PROTOTYPE_METHOD(t, "stats", Stats);
+ NODE_SET_PROTOTYPE_METHOD(t, "default_device", DefaultDevice);
+
+ // Static functions
+ target->Set(String::New("lib_version"), FunctionTemplate::New(LibVersion)->GetFunction());
+ target->Set(v8::String::NewSymbol("Pcap"), t->GetFunction());
+}
+
extern "C" void init (Handle<Object> target)
{
HandleScope scope;
-
- target->Set(String::New("findalldevs"), FunctionTemplate::New(FindAllDevs)->GetFunction());
- target->Set(String::New("open_live"), FunctionTemplate::New(OpenLive)->GetFunction());
- target->Set(String::New("open_offline"), FunctionTemplate::New(OpenOffline)->GetFunction());
- target->Set(String::New("dispatch"), FunctionTemplate::New(Dispatch)->GetFunction());
- target->Set(String::New("fileno"), FunctionTemplate::New(Fileno)->GetFunction());
- target->Set(String::New("close"), FunctionTemplate::New(Close)->GetFunction());
- target->Set(String::New("stats"), FunctionTemplate::New(Stats)->GetFunction());
- target->Set(String::New("default_device"), FunctionTemplate::New(DefaultDevice)->GetFunction());
- target->Set(String::New("lib_version"), FunctionTemplate::New(LibVersion)->GetFunction());
+ Pcap::Initialize(target);
}
Something went wrong with that request. Please try again.