summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog13
-rw-r--r--ext/socket/extconf.rb3
-rw-r--r--ext/socket/mkconstants.rb1
-rw-r--r--ext/socket/option.c67
-rw-r--r--ext/socket/rubysocket.h7
-rw-r--r--test/socket/test_unix.rb14
6 files changed, 93 insertions, 12 deletions
diff --git a/ChangeLog b/ChangeLog
index 1c41672266..b24ed5d196 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+Mon Feb 9 00:30:56 2009 Tanaka Akira <akr@fsij.org>
+
+ * ext/socket/extconf.rb: check sys/param.h and sys/ucred.h.
+
+ * ext/socket/rubysocket.h: include sys/param.h and sys/ucred.h.
+
+ * ext/socket/option.c (inspect_local_peercred): new function to show
+ LOCAL_PEERCRED socket option on FreeBSD.
+ (sockopt_inspect): show as LOCAL_* socket option if AF_UNIX and level
+ is 0.
+
Mon Feb 9 00:01:47 2009 Tanaka Akira <akr@fsij.org>
* ext/socket/rubysocket.h (sockopt_new): add family argument.
@@ -25,7 +36,7 @@ Sun Feb 8 23:28:05 2009 Yusuke Endoh <mame@tsg.ne.jp>
Sun Feb 8 23:22:35 2009 Tanaka Akira <akr@fsij.org>
* ext/socket/option.c (inspect_peercred): new function to show
- SO_PEERCRED socket option.
+ SO_PEERCRED socket option on GNU/Linux.
Sun Feb 8 22:44:20 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
diff --git a/ext/socket/extconf.rb b/ext/socket/extconf.rb
index c7d07d0a4d..f3f4529902 100644
--- a/ext/socket/extconf.rb
+++ b/ext/socket/extconf.rb
@@ -293,6 +293,9 @@ have_header("sys/ioctl.h")
have_header("sys/sockio.h")
have_header("net/if.h", headers)
+have_header("sys/param.h", headers)
+have_header("sys/ucred.h", headers)
+
unless have_type("socklen_t", headers)
$defs << "-Dsocklen_t=int"
end
diff --git a/ext/socket/mkconstants.rb b/ext/socket/mkconstants.rb
index 37079ba8f9..d30c4bbf0d 100644
--- a/ext/socket/mkconstants.rb
+++ b/ext/socket/mkconstants.rb
@@ -262,6 +262,7 @@ def_intern('intern_ipv6_optname', /\AIPV6_/, "IPV6_")
def_intern('intern_tcp_optname', /\ATCP_/, "TCP_")
def_intern('intern_udp_optname', /\AUDP_/, "UDP_")
def_intern('intern_scm_optname', /\ASCM_/, "SCM_")
+def_intern('intern_local_optname', /\ALOCAL_/, "LOCAL_")
result = ERB.new(<<'EOS', nil, '%').result(binding)
/* autogenerated file */
diff --git a/ext/socket/option.c b/ext/socket/option.c
index c07779e796..c79c1f529f 100644
--- a/ext/socket/option.c
+++ b/ext/socket/option.c
@@ -256,6 +256,32 @@ inspect_peercred(int level, int optname, VALUE data, VALUE ret)
}
#endif
+#if defined(LOCAL_PEERCRED) /* FreeBSD */
+static int
+inspect_local_peercred(int level, int optname, VALUE data, VALUE ret)
+{
+ if (RSTRING_LEN(data) == sizeof(struct xucred)) {
+ struct xucred cred;
+ memcpy(&cred, RSTRING_PTR(data), sizeof(struct xucred));
+ rb_str_catf(ret, " version=%u", cred.cr_version);
+ rb_str_catf(ret, " uid=%u", cred.cr_uid);
+ if (cred.cr_ngroups) {
+ int i;
+ char *sep = " groups=";
+ for (i = 0; i < cred.cr_ngroups; i++) {
+ rb_str_catf(ret, "%s%u", sep, cred.cr_groups[i]);
+ sep = ",";
+ }
+ }
+ rb_str_cat2(ret, " (xucred)");
+ return 0;
+ }
+ else {
+ return -1;
+ }
+}
+#endif
+
static VALUE
sockopt_inspect(VALUE self)
{
@@ -264,7 +290,7 @@ sockopt_inspect(VALUE self)
int optname = NUM2INT(sockopt_optname(self));
VALUE data = sockopt_data(self);
VALUE v, ret;
- ID family_id, level_id;
+ ID family_id, level_id, optname_id;
StringValue(data);
@@ -276,17 +302,35 @@ sockopt_inspect(VALUE self)
else
rb_str_catf(ret, "family:%d", family);
- level_id = intern_level(level);
- if (level_id)
- rb_str_catf(ret, " %s", rb_id2name(level_id));
- else
- rb_str_catf(ret, " level:%d", level);
+ if (family == AF_UNIX && level == 0) {
+ rb_str_catf(ret, " level:%d", level);
- v = optname_to_sym(level, optname);
- if (SYMBOL_P(v))
- rb_str_catf(ret, " %s", rb_id2name(SYM2ID(v)));
- else
- rb_str_catf(ret, " optname:%d", optname);
+ optname_id = intern_local_optname(optname);
+ if (optname_id)
+ rb_str_catf(ret, " %s", rb_id2name(optname_id));
+ else
+ rb_str_catf(ret, " optname:%d", optname);
+ }
+ else {
+ level_id = intern_level(level);
+ if (level_id)
+ rb_str_catf(ret, " %s", rb_id2name(level_id));
+ else
+ rb_str_catf(ret, " level:%d", level);
+
+ v = optname_to_sym(level, optname);
+ if (SYMBOL_P(v))
+ rb_str_catf(ret, " %s", rb_id2name(SYM2ID(v)));
+ else
+ rb_str_catf(ret, " optname:%d", optname);
+ }
+
+ if (family == AF_UNIX && level == 0) {
+ if (optname == LOCAL_PEERCRED) {
+ if (inspect_local_peercred(level, optname, data, ret) == -1) goto dump;
+ goto finish;
+ }
+ }
switch (level) {
# if defined(SOL_SOCKET)
@@ -391,6 +435,7 @@ sockopt_inspect(VALUE self)
rb_str_catf(ret, " %s", StringValueCStr(data));
}
+ finish:
rb_str_cat2(ret, ">");
return ret;
diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h
index 99028443e9..9e3692f7f1 100644
--- a/ext/socket/rubysocket.h
+++ b/ext/socket/rubysocket.h
@@ -73,6 +73,13 @@
#include <net/if.h>
#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_UCRED_H
+#include <sys/ucred.h>
+#endif
+
#ifndef EWOULDBLOCK
#define EWOULDBLOCK EAGAIN
#endif
diff --git a/test/socket/test_unix.rb b/test/socket/test_unix.rb
index d05fd15a95..6799e52fd1 100644
--- a/test/socket/test_unix.rb
+++ b/test/socket/test_unix.rb
@@ -312,6 +312,20 @@ class TestUNIXSocket < Test::Unit::TestCase
}
end
+ def test_getcred_xucred
+ return if /freebsd/ !~ RUBY_PLATFORM
+ Dir.mktmpdir {|d|
+ sockpath = "#{d}/sock"
+ serv = Socket.unix_server_socket(sockpath)
+ c = Socket.unix(sockpath)
+ s, = serv.accept
+ cred = s.getsockopt(0, Socket::LOCAL_PEERCRED)
+ inspect = cred.inspect
+ assert_match(/ uid=#{Process.uid} /, inspect)
+ assert_match(/ \(xucred\)/, inspect)
+ }
+ end
+
def test_sendcred_ucred
return if /linux/ !~ RUBY_PLATFORM
Dir.mktmpdir {|d|