Skip to content

Loading…

Supporting multiple pcap sessions #27

Open
wants to merge 6 commits into from

4 participants

@rgulewich
Collaborator

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
@mranney
Owner

Hi there. Thanks for the contribution. I've added you as a collaborator on this project. Feel free to merge as you see fit.

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 committed
    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 committed
    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.