Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# ext/socket/option.c

Go to the documentation of this file.

    00001 #include "rubysocket.h"
    00002
    00003 VALUE rb_cSockOpt;
    00004
    00005 static VALUE
    00006 constant_to_sym(int constant, ID (*intern_const)(int))
    00007 {
    00008     ID name = intern_const(constant);
    00009     if (name) {
    00010         return ID2SYM(name);
    00011     }
    00012
    00013     return INT2NUM(constant);
    00014 }
    00015
    00016 static VALUE
    00017 optname_to_sym(int level, int optname)
    00018 {
    00019     switch (level) {
    00020       case SOL_SOCKET:
    00021         return constant_to_sym(optname, rsock_intern_so_optname);
    00022       case IPPROTO_IP:
    00023         return constant_to_sym(optname, rsock_intern_ip_optname);
    00024 #ifdef INET6
    00025       case IPPROTO_IPV6:
    00026         return constant_to_sym(optname, rsock_intern_ipv6_optname);
    00027 #endif
    00028       case IPPROTO_TCP:
    00029         return constant_to_sym(optname, rsock_intern_tcp_optname);
    00030       case IPPROTO_UDP:
    00031         return constant_to_sym(optname, rsock_intern_udp_optname);
    00032       default:
    00033         return INT2NUM(optname);
    00034     }
    00035 }
    00036
    00037 /*
    00038  * call-seq:
    00039  *   Socket::Option.new(family, level, optname, data) => sockopt
    00040  *
    00041  * Returns a new Socket::Option object.
    00042  *
    00043  *   sockopt = Socket::Option.new(:INET, :SOCKET, :KEEPALIVE, [1].pack("i"))
    00044  *   p sockopt #=> #<Socket::Option: INET SOCKET KEEPALIVE 1>
    00045  *
    00046  */
    00047 static VALUE
    00048 sockopt_initialize(VALUE self, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE data)
    00049 {
    00050     int family = rsock_family_arg(vfamily);
    00051     int level = rsock_level_arg(family, vlevel);
    00052     int optname = rsock_optname_arg(family, level, voptname);
    00053     StringValue(data);
    00054     rb_ivar_set(self, rb_intern("family"), INT2NUM(family));
    00055     rb_ivar_set(self, rb_intern("level"), INT2NUM(level));
    00056     rb_ivar_set(self, rb_intern("optname"), INT2NUM(optname));
    00057     rb_ivar_set(self, rb_intern("data"), data);
    00058     return self;
    00059 }
    00060
    00061 VALUE
    00062 rsock_sockopt_new(int family, int level, int optname, VALUE data)
    00063 {
    00064     NEWOBJ(obj, struct RObject);
    00065     OBJSETUP(obj, rb_cSockOpt, T_OBJECT);
    00066     StringValue(data);
    00067     sockopt_initialize((VALUE)obj, INT2NUM(family), INT2NUM(level), INT2NUM(optname), data);
    00068     return (VALUE)obj;
    00069 }
    00070
    00071 /*
    00072  * call-seq:
    00073  *   sockopt.family => integer
    00074  *
    00075  * returns the socket family as an integer.
    00076  *
    00077  *   p Socket::Option.new(:INET6, :IPV6, :RECVPKTINFO, [1].pack("i!")).family
    00078  *   #=> 10
    00079  */
    00080 static VALUE
    00081 sockopt_family_m(VALUE self)
    00082 {
    00083     return rb_attr_get(self, rb_intern("family"));
    00084 }
    00085
    00086 static int
    00087 sockopt_level(VALUE self)
    00088 {
    00089     return NUM2INT(rb_attr_get(self, rb_intern("level")));
    00090 }
    00091
    00092 /*
    00093  * call-seq:
    00094  *   sockopt.level => integer
    00095  *
    00096  * returns the socket level as an integer.
    00097  *
    00098  *   p Socket::Option.new(:INET6, :IPV6, :RECVPKTINFO, [1].pack("i!")).level
    00099  *   #=> 41
    00100  */
    00101 static VALUE
    00102 sockopt_level_m(VALUE self)
    00103 {
    00104     return INT2NUM(sockopt_level(self));
    00105 }
    00106
    00107 static int
    00108 sockopt_optname(VALUE self)
    00109 {
    00110     return NUM2INT(rb_attr_get(self, rb_intern("optname")));
    00111 }
    00112
    00113 /*
    00114  * call-seq:
    00115  *   sockopt.optname => integer
    00116  *
    00117  * returns the socket option name as an integer.
    00118  *
    00119  *   p Socket::Option.new(:INET6, :IPV6, :RECVPKTINFO, [1].pack("i!")).optname
    00120  *   #=> 2
    00121  */
    00122 static VALUE
    00123 sockopt_optname_m(VALUE self)
    00124 {
    00125     return INT2NUM(sockopt_optname(self));
    00126 }
    00127
    00128 /*
    00129  * call-seq:
    00130  *   sockopt.data => string
    00131  *
    00132  * returns the socket option data as a string.
    00133  *
    00134  *   p Socket::Option.new(:INET6, :IPV6, :RECVPKTINFO, [1].pack("i!")).data
    00135  *   #=> "\x01\x00\x00\x00"
    00136  */
    00137 static VALUE
    00138 sockopt_data(VALUE self)
    00139 {
    00140     VALUE v = rb_attr_get(self, rb_intern("data"));
    00141     StringValue(v);
    00142     return v;
    00143 }
    00144
    00145 /*
    00146  * call-seq:
    00147  *   Socket::Option.int(family, level, optname, integer) => sockopt
    00148  *
    00149  * Creates a new Socket::Option object which contains an int as data.
    00150  *
    00151  * The size and endian is dependent on the platform.
    00152  *
    00153  *   p Socket::Option.int(:INET, :SOCKET, :KEEPALIVE, 1)
    00154  *   #=> #<Socket::Option: INET SOCKET KEEPALIVE 1>
    00155  */
    00156 static VALUE
    00157 sockopt_s_int(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE vint)
    00158 {
    00159     int family = rsock_family_arg(vfamily);
    00160     int level = rsock_level_arg(family, vlevel);
    00161     int optname = rsock_optname_arg(family, level, voptname);
    00162     int i = NUM2INT(vint);
    00163     return rsock_sockopt_new(family, level, optname, rb_str_new((char*)&i, sizeof(i)));
    00164 }
    00165
    00166 /*
    00167  * call-seq:
    00168  *   sockopt.int => integer
    00169  *
    00170  * Returns the data in _sockopt_ as an int.
    00171  *
    00172  * The size and endian is dependent on the platform.
    00173  *
    00174  *   sockopt = Socket::Option.int(:INET, :SOCKET, :KEEPALIVE, 1)
    00175  *   p sockopt.int => 1
    00176  */
    00177 static VALUE
    00178 sockopt_int(VALUE self)
    00179 {
    00180     int i;
    00181     VALUE data = sockopt_data(self);
    00182     StringValue(data);
    00183     if (RSTRING_LEN(data) != sizeof(int))
    00184         rb_raise(rb_eTypeError, "size differ.  expected as sizeof(int)=%d but %ld",
    00185                  (int)sizeof(int), (long)RSTRING_LEN(data));
    00186     memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
    00187     return INT2NUM(i);
    00188 }
    00189
    00190 /*
    00191  * call-seq:
    00192  *   Socket::Option.bool(family, level, optname, bool) => sockopt
    00193  *
    00194  * Creates a new Socket::Option object which contains boolean as data.
    00195  * Actually 0 or 1 as int is used.
    00196  *
    00197  *   p Socket::Option.bool(:INET, :SOCKET, :KEEPALIVE, true)
    00198  *   #=> #<Socket::Option: INET SOCKET KEEPALIVE 1>
    00199  *
    00200  *   p Socket::Option.bool(:INET, :SOCKET, :KEEPALIVE, false)
    00201  *   #=> #<Socket::Option: AF_INET SOCKET KEEPALIVE 0>
    00202  *
    00203  */
    00204 static VALUE
    00205 sockopt_s_bool(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE vbool)
    00206 {
    00207     int family = rsock_family_arg(vfamily);
    00208     int level = rsock_level_arg(family, vlevel);
    00209     int optname = rsock_optname_arg(family, level, voptname);
    00210     int i = RTEST(vbool) ? 1 : 0;
    00211     return rsock_sockopt_new(family, level, optname, rb_str_new((char*)&i, sizeof(i)));
    00212 }
    00213
    00214 /*
    00215  * call-seq:
    00216  *   sockopt.bool => true or false
    00217  *
    00218  * Returns the data in _sockopt_ as an boolean value.
    00219  *
    00220  *   sockopt = Socket::Option.int(:INET, :SOCKET, :KEEPALIVE, 1)
    00221  *   p sockopt.bool => true
    00222  */
    00223 static VALUE
    00224 sockopt_bool(VALUE self)
    00225 {
    00226     int i;
    00227     VALUE data = sockopt_data(self);
    00228     StringValue(data);
    00229     if (RSTRING_LEN(data) != sizeof(int))
    00230         rb_raise(rb_eTypeError, "size differ.  expected as sizeof(int)=%d but %ld",
    00231                  (int)sizeof(int), (long)RSTRING_LEN(data));
    00232     memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
    00233     return i == 0 ? Qfalse : Qtrue;
    00234 }
    00235
    00236 /*
    00237  * call-seq:
    00238  *   Socket::Option.linger(onoff, secs) => sockopt
    00239  *
    00240  * Creates a new Socket::Option object for SOL_SOCKET/SO_LINGER.
    00241  *
    00242  * _onoff_ should be an integer or a boolean.
    00243  *
    00244  * _secs_ should be the number of seconds.
    00245  *
    00246  *   p Socket::Option.linger(true, 10)
    00247  *   #=> #<Socket::Option: UNSPEC SOCKET LINGER on 10sec>
    00248  *
    00249  */
    00250 static VALUE
    00251 sockopt_s_linger(VALUE klass, VALUE vonoff, VALUE vsecs)
    00252 {
    00253     VALUE tmp;
    00254     struct linger l;
    00255     memset(&l, 0, sizeof(l));
    00256     if (!NIL_P(tmp = rb_check_to_integer(vonoff, "to_int")))
    00257         l.l_onoff = NUM2INT(tmp);
    00258     else
    00259         l.l_onoff = RTEST(vonoff) ? 1 : 0;
    00260     l.l_linger = NUM2INT(vsecs);
    00261     return rsock_sockopt_new(AF_UNSPEC, SOL_SOCKET, SO_LINGER, rb_str_new((char*)&l, sizeof(l)));
    00262 }
    00263
    00264 /*
    00265  * call-seq:
    00266  *   sockopt.linger => [bool, seconds]
    00267  *
    00268  * Returns the linger data in _sockopt_ as a pair of boolean and integer.
    00269  *
    00270  *   sockopt = Socket::Option.linger(true, 10)
    00271  *   p sockopt.linger => [true, 10]
    00272  */
    00273 static VALUE
    00274 sockopt_linger(VALUE self)
    00275 {
    00276     int level = sockopt_level(self);
    00277     int optname = sockopt_optname(self);
    00278     VALUE data = sockopt_data(self);
    00279     struct linger l;
    00280     VALUE vonoff, vsecs;
    00281
    00282     if (level != SOL_SOCKET || optname != SO_LINGER)
    00283         rb_raise(rb_eTypeError, "linger socket option expected");
    00284     if (RSTRING_LEN(data) != sizeof(l))
    00285         rb_raise(rb_eTypeError, "size differ.  expected as sizeof(struct linger)=%d but %ld",
    00286                  (int)sizeof(struct linger), (long)RSTRING_LEN(data));
    00287     memcpy((char*)&l, RSTRING_PTR(data), sizeof(struct linger));
    00288     switch (l.l_onoff) {
    00289       case 0: vonoff = Qfalse; break;
    00290       case 1: vonoff = Qtrue; break;
    00291       default: vonoff = INT2NUM(l.l_onoff); break;
    00292     }
    00293     vsecs = INT2NUM(l.l_linger);
    00294     return rb_assoc_new(vonoff, vsecs);
    00295 }
    00296
    00297 static int
    00298 inspect_int(int level, int optname, VALUE data, VALUE ret)
    00299 {
    00300     if (RSTRING_LEN(data) == sizeof(int)) {
    00301         int i;
    00302         memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
    00303         rb_str_catf(ret, " %d", i);
    00304         return 1;
    00305     }
    00306     else {
    00307         return 0;
    00308     }
    00309 }
    00310
    00311 static int
    00312 inspect_errno(int level, int optname, VALUE data, VALUE ret)
    00313 {
    00314     if (RSTRING_LEN(data) == sizeof(int)) {
    00315         int i;
    00316         char *err;
    00317         memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
    00318         err = strerror(i);
    00319         rb_str_catf(ret, " %s (%d)", err, i);
    00320         return 1;
    00321     }
    00322     else {
    00323         return 0;
    00324     }
    00325 }
    00326
    00327 #if defined(IPV6_MULTICAST_IF) || defined(IPV6_MULTICAST_LOOP)
    00328 static int
    00329 inspect_uint(int level, int optname, VALUE data, VALUE ret)
    00330 {
    00331     if (RSTRING_LEN(data) == sizeof(int)) {
    00332         unsigned int i;
    00333         memcpy((char*)&i, RSTRING_PTR(data), sizeof(unsigned int));
    00334         rb_str_catf(ret, " %u", i);
    00335         return 1;
    00336     }
    00337     else {
    00338         return 0;
    00339     }
    00340 }
    00341 #endif
    00342
    00343 #if defined(SOL_SOCKET) && defined(SO_LINGER) /* POSIX */
    00344 static int
    00345 inspect_linger(int level, int optname, VALUE data, VALUE ret)
    00346 {
    00347     if (RSTRING_LEN(data) == sizeof(struct linger)) {
    00348         struct linger s;
    00349         memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
    00350         switch (s.l_onoff) {
    00351           case 0: rb_str_cat2(ret, " off"); break;
    00352           case 1: rb_str_cat2(ret, " on"); break;
    00353           default: rb_str_catf(ret, " on(%d)", s.l_onoff); break;
    00354         }
    00355         rb_str_catf(ret, " %dsec", s.l_linger);
    00356         return 1;
    00357     }
    00358     else {
    00359         return 0;
    00360     }
    00361 }
    00362 #endif
    00363
    00364 #if defined(SOL_SOCKET) && defined(SO_TYPE) /* POSIX */
    00365 static int
    00366 inspect_socktype(int level, int optname, VALUE data, VALUE ret)
    00367 {
    00368     if (RSTRING_LEN(data) == sizeof(int)) {
    00369         int i;
    00370         ID id;
    00371         memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
    00372         id = rsock_intern_socktype(i);
    00373         if (id)
    00374             rb_str_catf(ret, " %s", rb_id2name(id));
    00375         else
    00376             rb_str_catf(ret, " %d", i);
    00377         return 1;
    00378     }
    00379     else {
    00380         return 0;
    00381     }
    00382 }
    00383 #endif
    00384
    00385 static int
    00386 inspect_timeval_as_interval(int level, int optname, VALUE data, VALUE ret)
    00387 {
    00388     if (RSTRING_LEN(data) == sizeof(struct timeval)) {
    00389         struct timeval s;
    00390         memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
    00391         rb_str_catf(ret, " %ld.%06ldsec", (long)s.tv_sec, (long)s.tv_usec);
    00392         return 1;
    00393     }
    00394     else {
    00395         return 0;
    00396     }
    00397 }
    00398
    00399 #if defined(SOL_SOCKET) && defined(SO_PEERCRED) /* GNU/Linux */
    00400 static int
    00401 inspect_peercred(int level, int optname, VALUE data, VALUE ret)
    00402 {
    00403     if (RSTRING_LEN(data) == sizeof(struct ucred)) {
    00404         struct ucred cred;
    00405         memcpy(&cred, RSTRING_PTR(data), sizeof(struct ucred));
    00406         rb_str_catf(ret, " pid=%u euid=%u egid=%u",
    00407                     (unsigned)cred.pid, (unsigned)cred.uid, (unsigned)cred.gid);
    00408         rb_str_cat2(ret, " (ucred)");
    00409         return 1;
    00410     }
    00411     else {
    00412         return 0;
    00413     }
    00414 }
    00415 #endif
    00416
    00417 #if defined(LOCAL_PEERCRED) /* FreeBSD, MacOS X */
    00418 static int
    00419 inspect_local_peercred(int level, int optname, VALUE data, VALUE ret)
    00420 {
    00421     if (RSTRING_LEN(data) == sizeof(struct xucred)) {
    00422         struct xucred cred;
    00423         memcpy(&cred, RSTRING_PTR(data), sizeof(struct xucred));
    00424         if (cred.cr_version != XUCRED_VERSION)
    00425             return 0;
    00426         rb_str_catf(ret, " version=%u", cred.cr_version);
    00427         rb_str_catf(ret, " euid=%u", cred.cr_uid);
    00428         if (cred.cr_ngroups) {
    00429             int i;
    00430             const char *sep = " groups=";
    00431             for (i = 0; i < cred.cr_ngroups; i++) {
    00432                 rb_str_catf(ret, "%s%u", sep, cred.cr_groups[i]);
    00433                 sep = ",";
    00434             }
    00435         }
    00436         rb_str_cat2(ret, " (xucred)");
    00437         return 1;
    00438     }
    00439     else {
    00440         return 0;
    00441     }
    00442 }
    00443 #endif
    00444
    00445
    00446 /*
    00447  * call-seq:
    00448  *   sockopt.inspect => string
    00449  *
    00450  * Returns a string which shows sockopt in human-readable form.
    00451  *
    00452  *   p Socket::Option.new(:INET, :SOCKET, :KEEPALIVE, [1].pack("i")).inspect
    00453  *   #=> "#<Socket::Option: INET SOCKET KEEPALIVE 1>"
    00454  *
    00455  */
    00456 static VALUE
    00457 sockopt_inspect(VALUE self)
    00458 {
    00459     int family = NUM2INT(sockopt_family_m(self));
    00460     int level = NUM2INT(sockopt_level_m(self));
    00461     int optname = NUM2INT(sockopt_optname_m(self));
    00462     VALUE data = sockopt_data(self);
    00463     VALUE v, ret;
    00464     ID family_id, level_id, optname_id;
    00465     int inspected;
    00466
    00467     StringValue(data);
    00468
    00469     ret = rb_sprintf("#<%s:", rb_obj_classname(self));
    00470
    00471     family_id = rsock_intern_family_noprefix(family);
    00472     if (family_id)
    00473         rb_str_catf(ret, " %s", rb_id2name(family_id));
    00474     else
    00475         rb_str_catf(ret, " family:%d", family);
    00476
    00477     if (level == SOL_SOCKET) {
    00478         rb_str_cat2(ret, " SOCKET");
    00479
    00480         optname_id = rsock_intern_so_optname(optname);
    00481         if (optname_id)
    00482             rb_str_catf(ret, " %s", rb_id2name(optname_id));
    00483         else
    00484             rb_str_catf(ret, " optname:%d", optname);
    00485     }
    00486 #ifdef HAVE_SYS_UN_H
    00487     else if (family == AF_UNIX) {
    00488         rb_str_catf(ret, " level:%d", level);
    00489
    00490         optname_id = rsock_intern_local_optname(optname);
    00491         if (optname_id)
    00492             rb_str_catf(ret, " %s", rb_id2name(optname_id));
    00493         else
    00494             rb_str_catf(ret, " optname:%d", optname);
    00495     }
    00496 #endif
    00497     else if (IS_IP_FAMILY(family)) {
    00498         level_id = rsock_intern_iplevel(level);
    00499         if (level_id)
    00500             rb_str_catf(ret, " %s", rb_id2name(level_id));
    00501         else
    00502             rb_str_catf(ret, " level:%d", level);
    00503
    00504         v = optname_to_sym(level, optname);
    00505         if (SYMBOL_P(v))
    00506             rb_str_catf(ret, " %s", rb_id2name(SYM2ID(v)));
    00507         else
    00508             rb_str_catf(ret, " optname:%d", optname);
    00509     }
    00510     else {
    00511         rb_str_catf(ret, " level:%d", level);
    00512         rb_str_catf(ret, " optname:%d", optname);
    00513     }
    00514
    00515     inspected = 0;
    00516
    00517     if (level == SOL_SOCKET)
    00518         family = AF_UNSPEC;
    00519     switch (family) {
    00520       case AF_UNSPEC:
    00521         switch (level) {
    00522           case SOL_SOCKET:
    00523             switch (optname) {
    00524 #            if defined(SO_DEBUG) /* POSIX */
    00525               case SO_DEBUG: inspected = inspect_int(level, optname, data, ret); break;
    00526 #            endif
    00527 #            if defined(SO_ERROR) /* POSIX */
    00528               case SO_ERROR: inspected = inspect_errno(level, optname, data, ret); break;
    00529 #            endif
    00530 #            if defined(SO_TYPE) /* POSIX */
    00531               case SO_TYPE: inspected = inspect_socktype(level, optname, data, ret); break;
    00532 #            endif
    00533 #            if defined(SO_ACCEPTCONN) /* POSIX */
    00534               case SO_ACCEPTCONN: inspected = inspect_int(level, optname, data, ret); break;
    00535 #            endif
    00536 #            if defined(SO_BROADCAST) /* POSIX */
    00537               case SO_BROADCAST: inspected = inspect_int(level, optname, data, ret); break;
    00538 #            endif
    00539 #            if defined(SO_REUSEADDR) /* POSIX */
    00540               case SO_REUSEADDR: inspected = inspect_int(level, optname, data, ret); break;
    00541 #            endif
    00542 #            if defined(SO_KEEPALIVE) /* POSIX */
    00543               case SO_KEEPALIVE: inspected = inspect_int(level, optname, data, ret); break;
    00544 #            endif
    00545 #            if defined(SO_OOBINLINE) /* POSIX */
    00546               case SO_OOBINLINE: inspected = inspect_int(level, optname, data, ret); break;
    00547 #            endif
    00548 #            if defined(SO_SNDBUF) /* POSIX */
    00549               case SO_SNDBUF: inspected = inspect_int(level, optname, data, ret); break;
    00550 #            endif
    00551 #            if defined(SO_RCVBUF) /* POSIX */
    00552               case SO_RCVBUF: inspected = inspect_int(level, optname, data, ret); break;
    00553 #            endif
    00554 #            if defined(SO_DONTROUTE) /* POSIX */
    00555               case SO_DONTROUTE: inspected = inspect_int(level, optname, data, ret); break;
    00556 #            endif
    00557 #            if defined(SO_RCVLOWAT) /* POSIX */
    00558               case SO_RCVLOWAT: inspected = inspect_int(level, optname, data, ret); break;
    00559 #            endif
    00560 #            if defined(SO_SNDLOWAT) /* POSIX */
    00561               case SO_SNDLOWAT: inspected = inspect_int(level, optname, data, ret); break;
    00562 #            endif
    00563 #            if defined(SO_LINGER) /* POSIX */
    00564               case SO_LINGER: inspected = inspect_linger(level, optname, data, ret); break;
    00565 #            endif
    00566 #            if defined(SO_RCVTIMEO) /* POSIX */
    00567               case SO_RCVTIMEO: inspected = inspect_timeval_as_interval(level, optname, data, ret); break;
    00568 #            endif
    00569 #            if defined(SO_SNDTIMEO) /* POSIX */
    00570               case SO_SNDTIMEO: inspected = inspect_timeval_as_interval(level, optname, data, ret); break;
    00571 #            endif
    00572 #            if defined(SO_PEERCRED) /* GNU/Linux */
    00573               case SO_PEERCRED: inspected = inspect_peercred(level, optname, data, ret); break;
    00574 #            endif
    00575             }
    00576             break;
    00577         }
    00578         break;
    00579
    00580       case AF_INET:
    00581 #ifdef INET6
    00582       case AF_INET6:
    00583 #endif
    00584         switch (level) {
    00585 #        if defined(IPPROTO_IPV6)
    00586           case IPPROTO_IPV6:
    00587             switch (optname) {
    00588               /* IPV6_JOIN_GROUP ipv6_mreq, IPV6_LEAVE_GROUP ipv6_mreq */
    00589 #            if defined(IPV6_MULTICAST_HOPS) /* POSIX */
    00590               case IPV6_MULTICAST_HOPS: inspected = inspect_int(level, optname, data, ret); break;
    00591 #            endif
    00592 #            if defined(IPV6_MULTICAST_IF) /* POSIX */
    00593               case IPV6_MULTICAST_IF: inspected = inspect_uint(level, optname, data, ret); break;
    00594 #            endif
    00595 #            if defined(IPV6_MULTICAST_LOOP) /* POSIX */
    00596               case IPV6_MULTICAST_LOOP: inspected = inspect_uint(level, optname, data, ret); break;
    00597 #            endif
    00598 #            if defined(IPV6_UNICAST_HOPS) /* POSIX */
    00599               case IPV6_UNICAST_HOPS: inspected = inspect_int(level, optname, data, ret); break;
    00600 #            endif
    00601 #            if defined(IPV6_V6ONLY) /* POSIX */
    00602               case IPV6_V6ONLY: inspected = inspect_int(level, optname, data, ret); break;
    00603 #            endif
    00604             }
    00605             break;
    00606 #        endif
    00607
    00608 #        if defined(IPPROTO_TCP)
    00609           case IPPROTO_TCP:
    00610             switch (optname) {
    00611 #            if defined(TCP_NODELAY) /* POSIX */
    00612               case TCP_NODELAY: inspected = inspect_int(level, optname, data, ret); break;
    00613 #            endif
    00614             }
    00615             break;
    00616 #        endif
    00617         }
    00618         break;
    00619
    00620 #ifdef HAVE_SYS_UN_H
    00621       case AF_UNIX:
    00622         switch (level) {
    00623           case 0:
    00624             switch (optname) {
    00625 #            if defined(LOCAL_PEERCRED)
    00626               case LOCAL_PEERCRED: inspected = inspect_local_peercred(level, optname, data, ret); break;
    00627 #            endif
    00628             }
    00629             break;
    00630         }
    00631         break;
    00632 #endif
    00633     }
    00634
    00635     if (!inspected) {
    00636         rb_str_cat2(ret, " ");
    00637         rb_str_append(ret, rb_str_dump(data));
    00638     }
    00639
    00640     rb_str_cat2(ret, ">");
    00641
    00642     return ret;
    00643 }
    00644
    00645 /*
    00646  * call-seq:
    00647  *   sockopt.unpack(template) => array
    00648  *
    00649  * Calls String#unpack on sockopt.data.
    00650  *
    00651  *   sockopt = Socket::Option.new(:INET, :SOCKET, :KEEPALIVE, [1].pack("i"))
    00652  *   p sockopt.unpack("i")      #=> [1]
    00653  *   p sockopt.data.unpack("i") #=> [1]
    00654  */
    00655 static VALUE
    00656 sockopt_unpack(VALUE self, VALUE template)
    00657 {
    00658     return rb_funcall(sockopt_data(self), rb_intern("unpack"), 1, template);
    00659 }
    00660
    00661 /*
    00662  * Document-class: ::Socket::Option
    00663  *
    00664  * Socket::Option represents a socket option used by getsockopt and setsockopt
    00665  * system call.
    00666  * It contains socket family, protocol level, option name and option value.
    00667  */
    00668 void
    00669 rsock_init_sockopt(void)
    00670 {
    00671     rb_cSockOpt = rb_define_class_under(rb_cSocket, "Option", rb_cObject);
    00672     rb_define_method(rb_cSockOpt, "initialize", sockopt_initialize, 4);
    00673     rb_define_method(rb_cSockOpt, "family", sockopt_family_m, 0);
    00674     rb_define_method(rb_cSockOpt, "level", sockopt_level_m, 0);
    00675     rb_define_method(rb_cSockOpt, "optname", sockopt_optname_m, 0);
    00676     rb_define_method(rb_cSockOpt, "data", sockopt_data, 0);
    00677     rb_define_method(rb_cSockOpt, "inspect", sockopt_inspect, 0);
    00678
    00679     rb_define_singleton_method(rb_cSockOpt, "int", sockopt_s_int, 4);
    00680     rb_define_method(rb_cSockOpt, "int", sockopt_int, 0);
    00681
    00682     rb_define_singleton_method(rb_cSockOpt, "bool", sockopt_s_bool, 4);
    00683     rb_define_method(rb_cSockOpt, "bool", sockopt_bool, 0);
    00684
    00685     rb_define_singleton_method(rb_cSockOpt, "linger", sockopt_s_linger, 2);
    00686     rb_define_method(rb_cSockOpt, "linger", sockopt_linger, 0);
    00687
    00688     rb_define_method(rb_cSockOpt, "unpack", sockopt_unpack, 1);
    00689
    00690     rb_define_method(rb_cSockOpt, "to_s", sockopt_data, 0); /* compatibility for ruby before 1.9.2 */
    00691 }
    00692
    00693