|
Ruby 1.9.2p290(2011-07-09revision32553)
|
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
1.7.3