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 

Generated on Wed Aug 10 09:17:04 2011 for Ruby by  doxygen 1.4.7