Skip to content

Commit

Permalink
Fixes to make this gem run with ruby 1.9.2@p180 on Mac OS X 10.6.7.
Browse files Browse the repository at this point in the history
    rubysig.h is deprecated, but afaik, there isn't a better way of writing c extensions that doesn't involve FFI. There does not appear to be any changes to TRAP_BEG or TRAP_END in ruby 1.9, although that is where the problems stem from.

    The problem here is that calling TRAP_END after reading available packets on the file descriptor blocks forever -- sampling the process at this point shows that it's blocking on something that may never return.

    Another, smaller issue is that the wrapper around the c extension would catch any interrupt signals - this is not desirable for most processes. Perhaps there should be an optional flag to do this?
  • Loading branch information
Tim Jarratt committed May 30, 2011
1 parent 8b1ee0b commit 6ad3232
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 27 deletions.
70 changes: 48 additions & 22 deletions ext/Pcap.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,23 +317,35 @@ capture_dispatch(argc, argv, self)
{
VALUE v_cnt;
int cnt;
VALUE v_ignore_trap;
int ignore_trap;
struct capture_object *cap;
int ret;

DEBUG_PRINT("capture_dispatch");
GetCapture(self, cap);


/* scan arg */
if (rb_scan_args(argc, argv, "01", &v_cnt) >= 1) {

if (rb_scan_args(argc, argv, "11", &v_cnt, &v_ignore_trap) >= 2) {
FIXNUM_P(v_cnt);
cnt = FIX2INT(v_cnt);
} else

FIXNUM_P(v_ignore_trap);
ignore_trap = FIX2INT(v_ignore_trap);
} else {
cnt = -1;
ignore_trap = -1;
}

TRAP_BEG;
ret = pcap_dispatch(cap->pcap, cnt, handler, (u_char *)cap);
TRAP_END;
if (ignore_trap == -1) {
TRAP_BEG;
ret = pcap_dispatch(cap->pcap, cnt, handler, (u_char *)cap);
TRAP_END;
}
else {
ret = pcap_dispatch(cap->pcap, cnt, handler, (u_char *)cap);
}
if (ret == -1)
rb_raise(ePcapError, "dispatch: %s", pcap_geterr(cap->pcap));

Expand All @@ -348,30 +360,38 @@ capture_loop(argc, argv, self)
{
VALUE v_cnt;
int cnt;
VALUE v_ignore_trap;
int ignore_trap;
struct capture_object *cap;
int ret;

DEBUG_PRINT("capture_loop");
GetCapture(self, cap);


/* scan arg */
if (rb_scan_args(argc, argv, "01", &v_cnt) >= 1) {
if (rb_scan_args(argc, argv, "11", &v_cnt, &v_ignore_trap) >= 1) {
FIXNUM_P(v_cnt);
cnt = FIX2INT(v_cnt);
} else

FIXNUM_P(v_ignore_trap);
ignore_trap = FIX2INT(v_cnt);
}
else {
cnt = -1;
ignore_trap = -1;
}

#if 0
TRAP_BEG;
ret = pcap_loop(cap->pcap, cnt, handler, (u_char *)cap);
TRAP_END;
#else
if (pcap_file(cap->pcap) != NULL) {
TRAP_BEG;
ret = pcap_loop(cap->pcap, cnt, handler, (u_char *)cap);
TRAP_END;
} else {
if (ignore_trap == -1) {
TRAP_BEG;
ret = pcap_loop(cap->pcap, cnt, handler, (u_char *)cap);
TRAP_END;
}
else {
ret = pcap_loop(cap->pcap, cnt, handler, (u_char *)cap);
}
}
else {
int fd = pcap_fileno(cap->pcap);
fd_set rset;
struct timeval tm;
Expand All @@ -385,10 +405,16 @@ capture_loop(argc, argv, self)
if (select(fd+1, &rset, NULL, NULL, &tm) == 0) {
rb_thread_wait_fd(fd);
}
TRAP_BEG;
ret = pcap_dispatch(cap->pcap, 1, handler, (u_char *)cap);
TRAP_END;
if (ignore_trap == -1) {
TRAP_BEG;
ret = pcap_dispatch(cap->pcap, 1, handler, (u_char *)cap);
TRAP_END;
}
else {
ret = pcap_dispatch(cap->pcap, 1, handler, (u_char *)cap);
}
} while (ret == 0);

if (ret <= 0)
break;
if (cnt > 0) {
Expand All @@ -398,7 +424,7 @@ capture_loop(argc, argv, self)
}
}
}
#endif

return INT2FIX(ret);
}

Expand Down
14 changes: 9 additions & 5 deletions lib/pcaplet.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,20 +86,24 @@ def add_filter(f)
def each_packet(&block)
begin
duplicated = (RUBY_PLATFORM =~ /linux/ && @device == "lo")
is_os_x = RUBY_PLATFORM.match(/.*darwin.*/)
shouldnt_trap = is_os_x && (! RUBY_VERSION.match(/^1\.9.*/).nil?)
shouldnt_trap = shouldnt_trap ? 1 : -1

unless duplicated
@capture.loop(@count, &block)
@capture.loop(@count, shouldnt_trap, &block)
else
flip = true
@capture.loop(@count) do |pkt|
flip = (! flip)
next if flip

block.call pkt
end
end
rescue Interrupt
$stdout.flush
$stderr.puts("Interrupted.")
$stderr.puts $@.join("\n\t") if $DEBUG
rescue Exception => e
$stderr.puts "exception when looping over each packet loop: #{e.inspect}"
raise
ensure
# print statistics if live
if @device
Expand Down

0 comments on commit 6ad3232

Please sign in to comment.