Ruby 1.9.3p327(2012-11-10revision37606)
|
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_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 /* 00400 * socket option for IPv4 multicast is bit confusing. 00401 * 00402 * IP Multicast is implemented by Steve Deering at first: 00403 * IP Multicast Extensions for 4.3BSD UNIX and related systems 00404 * (MULTICAST 1.2 Release) 00405 * http://www.kohala.com/start/mcast.api.txt 00406 * 00407 * There are 3 socket options which takes a struct. 00408 * 00409 * IP_MULTICAST_IF: struct in_addr 00410 * IP_ADD_MEMBERSHIP: struct ip_mreq 00411 * IP_DROP_MEMBERSHIP: struct ip_mreq 00412 * 00413 * But they uses an IP address to specify an interface. 00414 * This means the API cannot specify an unnumbered interface. 00415 * 00416 * Linux 2.4 introduces struct ip_mreqn to fix this problem. 00417 * struct ip_mreqn has imr_ifindex field to specify interface index. 00418 * 00419 * IP_MULTICAST_IF: struct ip_mreqn 00420 * IP_ADD_MEMBERSHIP: struct ip_mreqn 00421 * IP_DROP_MEMBERSHIP: struct ip_mreqn 00422 * 00423 * FreeBSD 7 obtained struct ip_mreqn for IP_MULTICAST_IF. 00424 * http://www.FreeBSD.org/cgi/cvsweb.cgi/src/sys/netinet/in.h.diff?r1=1.99;r2=1.100 00425 * 00426 * Another hackish workaround is "RFC 1724 hack". 00427 * RFC 1724 section 3.3 suggests unnumbered interfaces 00428 * specified by pseudo address 0.0.0.0/8. 00429 * NetBSD 4 and FreeBSD 5 documented it. 00430 * http://cvsweb.netbsd.org/cgi-bin/cvsweb.cgi/src/share/man/man4/ip.4.diff?r1=1.16&r2=1.17 00431 * http://www.FreeBSD.org/cgi/cvsweb.cgi/src/share/man/man4/ip.4.diff?r1=1.37;r2=1.38 00432 * FreeBSD 7.0 removed it. 00433 * http://www.FreeBSD.org/cgi/cvsweb.cgi/src/share/man/man4/ip.4.diff?r1=1.49;r2=1.50 00434 * 00435 * RFC 1724 hack is not supported by Socket::Option#inspect because 00436 * it is not distinguishable by the size. 00437 */ 00438 00439 #ifndef HAVE_INET_NTOP 00440 static char * 00441 inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len) 00442 { 00443 #ifdef HAVE_INET_NTOA 00444 struct in_addr in; 00445 memcpy(&in.s_addr, addr, sizeof(in.s_addr)); 00446 snprintf(numaddr, numaddr_len, "%s", inet_ntoa(in)); 00447 #else 00448 unsigned long x = ntohl(*(unsigned long*)addr); 00449 snprintf(numaddr, numaddr_len, "%d.%d.%d.%d", 00450 (int) (x>>24) & 0xff, (int) (x>>16) & 0xff, 00451 (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff); 00452 #endif 00453 return numaddr; 00454 } 00455 #endif 00456 00457 /* Although the buffer size needed depends on the prefixes, "%u" may generate "4294967295". */ 00458 static int 00459 rb_if_indextoname(const char *succ_prefix, const char *fail_prefix, unsigned int ifindex, char *buf, size_t len) 00460 { 00461 #if defined(HAVE_IF_INDEXTONAME) 00462 char ifbuf[IFNAMSIZ]; 00463 if (if_indextoname(ifindex, ifbuf) == NULL) 00464 return snprintf(buf, len, "%s%u", fail_prefix, ifindex); 00465 else 00466 return snprintf(buf, len, "%s%s", succ_prefix, ifbuf); 00467 #else 00468 # ifndef IFNAMSIZ 00469 # define IFNAMSIZ (sizeof(unsigned int)*3+1) 00470 # endif 00471 return snprintf(buf, len, "%s%u", fail_prefix, ifindex); 00472 #endif 00473 } 00474 00475 #if defined(IPPROTO_IP) && defined(HAVE_TYPE_STRUCT_IP_MREQ) /* 4.4BSD, GNU/Linux */ 00476 static int 00477 inspect_ipv4_mreq(int level, int optname, VALUE data, VALUE ret) 00478 { 00479 if (RSTRING_LEN(data) == sizeof(struct ip_mreq)) { 00480 struct ip_mreq s; 00481 char addrbuf[INET_ADDRSTRLEN]; 00482 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s)); 00483 if (inet_ntop(AF_INET, &s.imr_multiaddr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL) 00484 rb_str_cat2(ret, " invalid-address"); 00485 else 00486 rb_str_catf(ret, " %s", addrbuf); 00487 if (inet_ntop(AF_INET, &s.imr_interface, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL) 00488 rb_str_catf(ret, " invalid-address"); 00489 else 00490 rb_str_catf(ret, " %s", addrbuf); 00491 return 1; 00492 } 00493 else { 00494 return 0; 00495 } 00496 } 00497 #endif 00498 00499 #if defined(IPPROTO_IP) && defined(HAVE_TYPE_STRUCT_IP_MREQN) /* GNU/Linux, FreeBSD 7 */ 00500 static int 00501 inspect_ipv4_mreqn(int level, int optname, VALUE data, VALUE ret) 00502 { 00503 if (RSTRING_LEN(data) == sizeof(struct ip_mreqn)) { 00504 struct ip_mreqn s; 00505 char addrbuf[INET_ADDRSTRLEN], ifbuf[32+IFNAMSIZ]; 00506 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s)); 00507 if (inet_ntop(AF_INET, &s.imr_multiaddr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL) 00508 rb_str_cat2(ret, " invalid-address"); 00509 else 00510 rb_str_catf(ret, " %s", addrbuf); 00511 if (inet_ntop(AF_INET, &s.imr_address, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL) 00512 rb_str_catf(ret, " invalid-address"); 00513 else 00514 rb_str_catf(ret, " %s", addrbuf); 00515 rb_if_indextoname(" ", " ifindex:", s.imr_ifindex, ifbuf, sizeof(ifbuf)); 00516 rb_str_cat2(ret, ifbuf); 00517 return 1; 00518 } 00519 else { 00520 return 0; 00521 } 00522 } 00523 #endif 00524 00525 #if defined(IPPROTO_IP) && defined(HAVE_TYPE_STRUCT_IP_MREQ) /* 4.4BSD, GNU/Linux */ 00526 static int 00527 inspect_ipv4_add_drop_membership(int level, int optname, VALUE data, VALUE ret) 00528 { 00529 if (RSTRING_LEN(data) == sizeof(struct ip_mreq)) 00530 return inspect_ipv4_mreq(level, optname, data, ret); 00531 # if defined(HAVE_TYPE_STRUCT_IP_MREQN) 00532 else if (RSTRING_LEN(data) == sizeof(struct ip_mreqn)) 00533 return inspect_ipv4_mreqn(level, optname, data, ret); 00534 # endif 00535 else 00536 return 0; 00537 } 00538 #endif 00539 00540 #if defined(IPPROTO_IP) && defined(IP_MULTICAST_IF) && defined(HAVE_TYPE_STRUCT_IP_MREQN) /* 4.4BSD, GNU/Linux */ 00541 static int 00542 inspect_ipv4_multicast_if(int level, int optname, VALUE data, VALUE ret) 00543 { 00544 if (RSTRING_LEN(data) == sizeof(struct in_addr)) { 00545 struct in_addr s; 00546 char addrbuf[INET_ADDRSTRLEN]; 00547 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s)); 00548 if (inet_ntop(AF_INET, &s, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL) 00549 rb_str_cat2(ret, " invalid-address"); 00550 else 00551 rb_str_catf(ret, " %s", addrbuf); 00552 return 1; 00553 } 00554 else if (RSTRING_LEN(data) == sizeof(struct ip_mreqn)) { 00555 return inspect_ipv4_mreqn(level, optname, data, ret); 00556 } 00557 else { 00558 return 0; 00559 } 00560 } 00561 #endif 00562 00563 #if defined(IPV6_MULTICAST_IF) /* POSIX, RFC 3493 */ 00564 static int 00565 inspect_ipv6_multicast_if(int level, int optname, VALUE data, VALUE ret) 00566 { 00567 if (RSTRING_LEN(data) == sizeof(int)) { 00568 char ifbuf[32+IFNAMSIZ]; 00569 unsigned int ifindex; 00570 memcpy((char*)&ifindex, RSTRING_PTR(data), sizeof(unsigned int)); 00571 rb_if_indextoname(" ", " ", ifindex, ifbuf, sizeof(ifbuf)); 00572 rb_str_cat2(ret, ifbuf); 00573 return 1; 00574 } 00575 else { 00576 return 0; 00577 } 00578 } 00579 #endif 00580 00581 #if defined(IPPROTO_IPV6) && defined(HAVE_TYPE_STRUCT_IPV6_MREQ) /* POSIX, RFC 3493 */ 00582 static int 00583 inspect_ipv6_mreq(int level, int optname, VALUE data, VALUE ret) 00584 { 00585 if (RSTRING_LEN(data) == sizeof(struct ipv6_mreq)) { 00586 struct ipv6_mreq s; 00587 char addrbuf[INET6_ADDRSTRLEN], ifbuf[32+IFNAMSIZ]; 00588 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s)); 00589 if (inet_ntop(AF_INET6, &s.ipv6mr_multiaddr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL) 00590 rb_str_cat2(ret, " invalid-address"); 00591 else 00592 rb_str_catf(ret, " %s", addrbuf); 00593 rb_if_indextoname(" ", " interface:", s.ipv6mr_interface, ifbuf, sizeof(ifbuf)); 00594 rb_str_cat2(ret, ifbuf); 00595 return 1; 00596 } 00597 else { 00598 return 0; 00599 } 00600 } 00601 #endif 00602 00603 #if defined(SOL_SOCKET) && defined(SO_PEERCRED) /* GNU/Linux, OpenBSD */ 00604 #if defined(__OpenBSD__) 00605 #define RUBY_SOCK_PEERCRED struct sockpeercred 00606 #else 00607 #define RUBY_SOCK_PEERCRED struct ucred 00608 #endif 00609 static int 00610 inspect_peercred(int level, int optname, VALUE data, VALUE ret) 00611 { 00612 if (RSTRING_LEN(data) == sizeof(RUBY_SOCK_PEERCRED)) { 00613 RUBY_SOCK_PEERCRED cred; 00614 memcpy(&cred, RSTRING_PTR(data), sizeof(RUBY_SOCK_PEERCRED)); 00615 rb_str_catf(ret, " pid=%u euid=%u egid=%u", 00616 (unsigned)cred.pid, (unsigned)cred.uid, (unsigned)cred.gid); 00617 rb_str_cat2(ret, " (ucred)"); 00618 return 1; 00619 } 00620 else { 00621 return 0; 00622 } 00623 } 00624 #endif 00625 00626 #if defined(LOCAL_PEERCRED) /* FreeBSD, MacOS X */ 00627 static int 00628 inspect_local_peercred(int level, int optname, VALUE data, VALUE ret) 00629 { 00630 if (RSTRING_LEN(data) == sizeof(struct xucred)) { 00631 struct xucred cred; 00632 memcpy(&cred, RSTRING_PTR(data), sizeof(struct xucred)); 00633 if (cred.cr_version != XUCRED_VERSION) 00634 return 0; 00635 rb_str_catf(ret, " version=%u", cred.cr_version); 00636 rb_str_catf(ret, " euid=%u", cred.cr_uid); 00637 if (cred.cr_ngroups) { 00638 int i; 00639 const char *sep = " groups="; 00640 for (i = 0; i < cred.cr_ngroups; i++) { 00641 rb_str_catf(ret, "%s%u", sep, cred.cr_groups[i]); 00642 sep = ","; 00643 } 00644 } 00645 rb_str_cat2(ret, " (xucred)"); 00646 return 1; 00647 } 00648 else { 00649 return 0; 00650 } 00651 } 00652 #endif 00653 00654 00655 /* 00656 * call-seq: 00657 * sockopt.inspect => string 00658 * 00659 * Returns a string which shows sockopt in human-readable form. 00660 * 00661 * p Socket::Option.new(:INET, :SOCKET, :KEEPALIVE, [1].pack("i")).inspect 00662 * #=> "#<Socket::Option: INET SOCKET KEEPALIVE 1>" 00663 * 00664 */ 00665 static VALUE 00666 sockopt_inspect(VALUE self) 00667 { 00668 int family = NUM2INT(sockopt_family_m(self)); 00669 int level = NUM2INT(sockopt_level_m(self)); 00670 int optname = NUM2INT(sockopt_optname_m(self)); 00671 VALUE data = sockopt_data(self); 00672 VALUE v, ret; 00673 ID family_id, level_id, optname_id; 00674 int inspected; 00675 00676 StringValue(data); 00677 00678 ret = rb_sprintf("#<%s:", rb_obj_classname(self)); 00679 00680 family_id = rsock_intern_family_noprefix(family); 00681 if (family_id) 00682 rb_str_catf(ret, " %s", rb_id2name(family_id)); 00683 else 00684 rb_str_catf(ret, " family:%d", family); 00685 00686 if (level == SOL_SOCKET) { 00687 rb_str_cat2(ret, " SOCKET"); 00688 00689 optname_id = rsock_intern_so_optname(optname); 00690 if (optname_id) 00691 rb_str_catf(ret, " %s", rb_id2name(optname_id)); 00692 else 00693 rb_str_catf(ret, " optname:%d", optname); 00694 } 00695 #ifdef HAVE_SYS_UN_H 00696 else if (family == AF_UNIX) { 00697 rb_str_catf(ret, " level:%d", level); 00698 00699 optname_id = rsock_intern_local_optname(optname); 00700 if (optname_id) 00701 rb_str_catf(ret, " %s", rb_id2name(optname_id)); 00702 else 00703 rb_str_catf(ret, " optname:%d", optname); 00704 } 00705 #endif 00706 else if (IS_IP_FAMILY(family)) { 00707 level_id = rsock_intern_iplevel(level); 00708 if (level_id) 00709 rb_str_catf(ret, " %s", rb_id2name(level_id)); 00710 else 00711 rb_str_catf(ret, " level:%d", level); 00712 00713 v = optname_to_sym(level, optname); 00714 if (SYMBOL_P(v)) 00715 rb_str_catf(ret, " %s", rb_id2name(SYM2ID(v))); 00716 else 00717 rb_str_catf(ret, " optname:%d", optname); 00718 } 00719 else { 00720 rb_str_catf(ret, " level:%d", level); 00721 rb_str_catf(ret, " optname:%d", optname); 00722 } 00723 00724 inspected = 0; 00725 00726 if (level == SOL_SOCKET) 00727 family = AF_UNSPEC; 00728 switch (family) { 00729 case AF_UNSPEC: 00730 switch (level) { 00731 case SOL_SOCKET: 00732 switch (optname) { 00733 # if defined(SO_DEBUG) /* POSIX */ 00734 case SO_DEBUG: inspected = inspect_int(level, optname, data, ret); break; 00735 # endif 00736 # if defined(SO_ERROR) /* POSIX */ 00737 case SO_ERROR: inspected = inspect_errno(level, optname, data, ret); break; 00738 # endif 00739 # if defined(SO_TYPE) /* POSIX */ 00740 case SO_TYPE: inspected = inspect_socktype(level, optname, data, ret); break; 00741 # endif 00742 # if defined(SO_ACCEPTCONN) /* POSIX */ 00743 case SO_ACCEPTCONN: inspected = inspect_int(level, optname, data, ret); break; 00744 # endif 00745 # if defined(SO_BROADCAST) /* POSIX */ 00746 case SO_BROADCAST: inspected = inspect_int(level, optname, data, ret); break; 00747 # endif 00748 # if defined(SO_REUSEADDR) /* POSIX */ 00749 case SO_REUSEADDR: inspected = inspect_int(level, optname, data, ret); break; 00750 # endif 00751 # if defined(SO_KEEPALIVE) /* POSIX */ 00752 case SO_KEEPALIVE: inspected = inspect_int(level, optname, data, ret); break; 00753 # endif 00754 # if defined(SO_OOBINLINE) /* POSIX */ 00755 case SO_OOBINLINE: inspected = inspect_int(level, optname, data, ret); break; 00756 # endif 00757 # if defined(SO_SNDBUF) /* POSIX */ 00758 case SO_SNDBUF: inspected = inspect_int(level, optname, data, ret); break; 00759 # endif 00760 # if defined(SO_RCVBUF) /* POSIX */ 00761 case SO_RCVBUF: inspected = inspect_int(level, optname, data, ret); break; 00762 # endif 00763 # if defined(SO_DONTROUTE) /* POSIX */ 00764 case SO_DONTROUTE: inspected = inspect_int(level, optname, data, ret); break; 00765 # endif 00766 # if defined(SO_RCVLOWAT) /* POSIX */ 00767 case SO_RCVLOWAT: inspected = inspect_int(level, optname, data, ret); break; 00768 # endif 00769 # if defined(SO_SNDLOWAT) /* POSIX */ 00770 case SO_SNDLOWAT: inspected = inspect_int(level, optname, data, ret); break; 00771 # endif 00772 # if defined(SO_LINGER) /* POSIX */ 00773 case SO_LINGER: inspected = inspect_linger(level, optname, data, ret); break; 00774 # endif 00775 # if defined(SO_RCVTIMEO) /* POSIX */ 00776 case SO_RCVTIMEO: inspected = inspect_timeval_as_interval(level, optname, data, ret); break; 00777 # endif 00778 # if defined(SO_SNDTIMEO) /* POSIX */ 00779 case SO_SNDTIMEO: inspected = inspect_timeval_as_interval(level, optname, data, ret); break; 00780 # endif 00781 # if defined(SO_PEERCRED) /* GNU/Linux, OpenBSD */ 00782 case SO_PEERCRED: inspected = inspect_peercred(level, optname, data, ret); break; 00783 # endif 00784 } 00785 break; 00786 } 00787 break; 00788 00789 case AF_INET: 00790 #ifdef INET6 00791 case AF_INET6: 00792 #endif 00793 switch (level) { 00794 # if defined(IPPROTO_IP) 00795 case IPPROTO_IP: 00796 switch (optname) { 00797 # if defined(IP_MULTICAST_IF) && defined(HAVE_TYPE_STRUCT_IP_MREQN) /* 4.4BSD, GNU/Linux */ 00798 case IP_MULTICAST_IF: inspected = inspect_ipv4_multicast_if(level, optname, data, ret); break; 00799 # endif 00800 # if defined(IP_ADD_MEMBERSHIP) /* 4.4BSD, GNU/Linux */ 00801 case IP_ADD_MEMBERSHIP: inspected = inspect_ipv4_add_drop_membership(level, optname, data, ret); break; 00802 # endif 00803 # if defined(IP_DROP_MEMBERSHIP) /* 4.4BSD, GNU/Linux */ 00804 case IP_DROP_MEMBERSHIP: inspected = inspect_ipv4_add_drop_membership(level, optname, data, ret); break; 00805 # endif 00806 } 00807 break; 00808 # endif 00809 00810 # if defined(IPPROTO_IPV6) 00811 case IPPROTO_IPV6: 00812 switch (optname) { 00813 # if defined(IPV6_MULTICAST_HOPS) /* POSIX */ 00814 case IPV6_MULTICAST_HOPS: inspected = inspect_int(level, optname, data, ret); break; 00815 # endif 00816 # if defined(IPV6_MULTICAST_IF) /* POSIX */ 00817 case IPV6_MULTICAST_IF: inspected = inspect_ipv6_multicast_if(level, optname, data, ret); break; 00818 # endif 00819 # if defined(IPV6_MULTICAST_LOOP) /* POSIX */ 00820 case IPV6_MULTICAST_LOOP: inspected = inspect_uint(level, optname, data, ret); break; 00821 # endif 00822 # if defined(IPV6_JOIN_GROUP) /* POSIX */ 00823 case IPV6_JOIN_GROUP: inspected = inspect_ipv6_mreq(level, optname, data, ret); break; 00824 # endif 00825 # if defined(IPV6_LEAVE_GROUP) /* POSIX */ 00826 case IPV6_LEAVE_GROUP: inspected = inspect_ipv6_mreq(level, optname, data, ret); break; 00827 # endif 00828 # if defined(IPV6_UNICAST_HOPS) /* POSIX */ 00829 case IPV6_UNICAST_HOPS: inspected = inspect_int(level, optname, data, ret); break; 00830 # endif 00831 # if defined(IPV6_V6ONLY) /* POSIX */ 00832 case IPV6_V6ONLY: inspected = inspect_int(level, optname, data, ret); break; 00833 # endif 00834 } 00835 break; 00836 # endif 00837 00838 # if defined(IPPROTO_TCP) 00839 case IPPROTO_TCP: 00840 switch (optname) { 00841 # if defined(TCP_NODELAY) /* POSIX */ 00842 case TCP_NODELAY: inspected = inspect_int(level, optname, data, ret); break; 00843 # endif 00844 } 00845 break; 00846 # endif 00847 } 00848 break; 00849 00850 #ifdef HAVE_SYS_UN_H 00851 case AF_UNIX: 00852 switch (level) { 00853 case 0: 00854 switch (optname) { 00855 # if defined(LOCAL_PEERCRED) 00856 case LOCAL_PEERCRED: inspected = inspect_local_peercred(level, optname, data, ret); break; 00857 # endif 00858 } 00859 break; 00860 } 00861 break; 00862 #endif 00863 } 00864 00865 if (!inspected) { 00866 rb_str_cat2(ret, " "); 00867 rb_str_append(ret, rb_str_dump(data)); 00868 } 00869 00870 rb_str_cat2(ret, ">"); 00871 00872 return ret; 00873 } 00874 00875 /* 00876 * call-seq: 00877 * sockopt.unpack(template) => array 00878 * 00879 * Calls String#unpack on sockopt.data. 00880 * 00881 * sockopt = Socket::Option.new(:INET, :SOCKET, :KEEPALIVE, [1].pack("i")) 00882 * p sockopt.unpack("i") #=> [1] 00883 * p sockopt.data.unpack("i") #=> [1] 00884 */ 00885 static VALUE 00886 sockopt_unpack(VALUE self, VALUE template) 00887 { 00888 return rb_funcall(sockopt_data(self), rb_intern("unpack"), 1, template); 00889 } 00890 00891 void 00892 rsock_init_sockopt(void) 00893 { 00894 /* 00895 * Document-class: Socket::Option 00896 * 00897 * Socket::Option represents a socket option used by 00898 * BasicSocket#getsockopt and BasicSocket#setsockopt. A socket option 00899 * contains the socket #family, protocol #level, option name #optname and 00900 * option value #data. 00901 */ 00902 rb_cSockOpt = rb_define_class_under(rb_cSocket, "Option", rb_cObject); 00903 rb_define_method(rb_cSockOpt, "initialize", sockopt_initialize, 4); 00904 rb_define_method(rb_cSockOpt, "family", sockopt_family_m, 0); 00905 rb_define_method(rb_cSockOpt, "level", sockopt_level_m, 0); 00906 rb_define_method(rb_cSockOpt, "optname", sockopt_optname_m, 0); 00907 rb_define_method(rb_cSockOpt, "data", sockopt_data, 0); 00908 rb_define_method(rb_cSockOpt, "inspect", sockopt_inspect, 0); 00909 00910 rb_define_singleton_method(rb_cSockOpt, "int", sockopt_s_int, 4); 00911 rb_define_method(rb_cSockOpt, "int", sockopt_int, 0); 00912 00913 rb_define_singleton_method(rb_cSockOpt, "bool", sockopt_s_bool, 4); 00914 rb_define_method(rb_cSockOpt, "bool", sockopt_bool, 0); 00915 00916 rb_define_singleton_method(rb_cSockOpt, "linger", sockopt_s_linger, 2); 00917 rb_define_method(rb_cSockOpt, "linger", sockopt_linger, 0); 00918 00919 rb_define_method(rb_cSockOpt, "unpack", sockopt_unpack, 1); 00920 00921 rb_define_method(rb_cSockOpt, "to_s", sockopt_data, 0); /* compatibility for ruby before 1.9.2 */ 00922 } 00923 00924