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 IPPROTO_IPV6
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
00039
00040
00041
00042
00043
00044
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_OF(obj, struct RObject, rb_cSockOpt, T_OBJECT);
00065 StringValue(data);
00066 sockopt_initialize((VALUE)obj, INT2NUM(family), INT2NUM(level), INT2NUM(optname), data);
00067 return (VALUE)obj;
00068 }
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079 static VALUE
00080 sockopt_family_m(VALUE self)
00081 {
00082 return rb_attr_get(self, rb_intern("family"));
00083 }
00084
00085 static int
00086 sockopt_level(VALUE self)
00087 {
00088 return NUM2INT(rb_attr_get(self, rb_intern("level")));
00089 }
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100 static VALUE
00101 sockopt_level_m(VALUE self)
00102 {
00103 return INT2NUM(sockopt_level(self));
00104 }
00105
00106 static int
00107 sockopt_optname(VALUE self)
00108 {
00109 return NUM2INT(rb_attr_get(self, rb_intern("optname")));
00110 }
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121 static VALUE
00122 sockopt_optname_m(VALUE self)
00123 {
00124 return INT2NUM(sockopt_optname(self));
00125 }
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
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
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156 static VALUE
00157 sockopt_s_byte(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 unsigned char i = (unsigned char)NUM2CHR(vint);
00163 return rsock_sockopt_new(family, level, optname, rb_str_new((char*)&i, sizeof(i)));
00164 }
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177 static VALUE
00178 sockopt_byte(VALUE self)
00179 {
00180 unsigned char i;
00181 VALUE data = sockopt_data(self);
00182 StringValue(data);
00183 if (RSTRING_LEN(data) != sizeof(i))
00184 rb_raise(rb_eTypeError, "size differ. expected as sizeof(int)=%d but %ld",
00185 (int)sizeof(i), (long)RSTRING_LEN(data));
00186 return CHR2FIX(*RSTRING_PTR(data));
00187 }
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200 static VALUE
00201 sockopt_s_int(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE vint)
00202 {
00203 int family = rsock_family_arg(vfamily);
00204 int level = rsock_level_arg(family, vlevel);
00205 int optname = rsock_optname_arg(family, level, voptname);
00206 int i = NUM2INT(vint);
00207 return rsock_sockopt_new(family, level, optname, rb_str_new((char*)&i, sizeof(i)));
00208 }
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221 static VALUE
00222 sockopt_int(VALUE self)
00223 {
00224 int i;
00225 VALUE data = sockopt_data(self);
00226 StringValue(data);
00227 if (RSTRING_LEN(data) != sizeof(int))
00228 rb_raise(rb_eTypeError, "size differ. expected as sizeof(int)=%d but %ld",
00229 (int)sizeof(int), (long)RSTRING_LEN(data));
00230 memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
00231 return INT2NUM(i);
00232 }
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248 static VALUE
00249 sockopt_s_bool(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE vbool)
00250 {
00251 int family = rsock_family_arg(vfamily);
00252 int level = rsock_level_arg(family, vlevel);
00253 int optname = rsock_optname_arg(family, level, voptname);
00254 int i = RTEST(vbool) ? 1 : 0;
00255 return rsock_sockopt_new(family, level, optname, rb_str_new((char*)&i, sizeof(i)));
00256 }
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267 static VALUE
00268 sockopt_bool(VALUE self)
00269 {
00270 int i;
00271 long len;
00272 VALUE data = sockopt_data(self);
00273 StringValue(data);
00274 len = RSTRING_LEN(data);
00275 if (len == 1) {
00276 return *RSTRING_PTR(data) == 0 ? Qfalse : Qtrue;
00277 }
00278 if (len != sizeof(int))
00279 rb_raise(rb_eTypeError, "size differ. expected as sizeof(int)=%d but %ld",
00280 (int)sizeof(int), (long)len);
00281 memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
00282 return i == 0 ? Qfalse : Qtrue;
00283 }
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299 static VALUE
00300 sockopt_s_linger(VALUE klass, VALUE vonoff, VALUE vsecs)
00301 {
00302 VALUE tmp;
00303 struct linger l;
00304 memset(&l, 0, sizeof(l));
00305 if (!NIL_P(tmp = rb_check_to_integer(vonoff, "to_int")))
00306 l.l_onoff = NUM2INT(tmp);
00307 else
00308 l.l_onoff = RTEST(vonoff) ? 1 : 0;
00309 l.l_linger = NUM2INT(vsecs);
00310 return rsock_sockopt_new(AF_UNSPEC, SOL_SOCKET, SO_LINGER, rb_str_new((char*)&l, sizeof(l)));
00311 }
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322 static VALUE
00323 sockopt_linger(VALUE self)
00324 {
00325 int level = sockopt_level(self);
00326 int optname = sockopt_optname(self);
00327 VALUE data = sockopt_data(self);
00328 struct linger l;
00329 VALUE vonoff, vsecs;
00330
00331 if (level != SOL_SOCKET || optname != SO_LINGER)
00332 rb_raise(rb_eTypeError, "linger socket option expected");
00333 if (RSTRING_LEN(data) != sizeof(l))
00334 rb_raise(rb_eTypeError, "size differ. expected as sizeof(struct linger)=%d but %ld",
00335 (int)sizeof(struct linger), (long)RSTRING_LEN(data));
00336 memcpy((char*)&l, RSTRING_PTR(data), sizeof(struct linger));
00337 switch (l.l_onoff) {
00338 case 0: vonoff = Qfalse; break;
00339 case 1: vonoff = Qtrue; break;
00340 default: vonoff = INT2NUM(l.l_onoff); break;
00341 }
00342 vsecs = INT2NUM(l.l_linger);
00343 return rb_assoc_new(vonoff, vsecs);
00344 }
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361 static VALUE
00362 sockopt_s_ipv4_multicast_loop(VALUE klass, VALUE value)
00363 {
00364 #if defined(IPPROTO_IP) && defined(IP_MULTICAST_LOOP)
00365 # if defined(__NetBSD__) || defined(__OpenBSD__)
00366 unsigned char i = NUM2CHR(rb_to_int(value));
00367 # else
00368 int i = NUM2INT(rb_to_int(value));
00369 # endif
00370 return rsock_sockopt_new(AF_INET, IPPROTO_IP, IP_MULTICAST_LOOP,
00371 rb_str_new((char*)&i, sizeof(i)));
00372 #else
00373 # error IPPROTO_IP or IP_MULTICAST_LOOP is not implemented
00374 #endif
00375 }
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386 static VALUE
00387 sockopt_ipv4_multicast_loop(VALUE self)
00388 {
00389 int family = NUM2INT(sockopt_family_m(self));
00390 int level = sockopt_level(self);
00391 int optname = sockopt_optname(self);
00392
00393 #if defined(IPPROTO_IP) && defined(IP_MULTICAST_LOOP)
00394 if (family == AF_INET && level == IPPROTO_IP && optname == IP_MULTICAST_LOOP) {
00395 # if defined(__NetBSD__) || defined(__OpenBSD__)
00396 return sockopt_byte(self);
00397 # else
00398 return sockopt_int(self);
00399 # endif
00400 }
00401 #endif
00402 rb_raise(rb_eTypeError, "ipv4_multicast_loop socket option expected");
00403 UNREACHABLE;
00404 }
00405
00406 #if defined(__NetBSD__) || defined(__OpenBSD__)
00407 # define inspect_ipv4_multicast_loop(a,b,c,d) inspect_byte(a,b,c,d)
00408 #else
00409 # define inspect_ipv4_multicast_loop(a,b,c,d) inspect_int(a,b,c,d)
00410 #endif
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424 static VALUE
00425 sockopt_s_ipv4_multicast_ttl(VALUE klass, VALUE value)
00426 {
00427 #if defined(IPPROTO_IP) && defined(IP_MULTICAST_TTL)
00428 # if defined(__NetBSD__) || defined(__OpenBSD__)
00429 unsigned char i = NUM2CHR(rb_to_int(value));
00430 # else
00431 int i = NUM2INT(rb_to_int(value));
00432 # endif
00433 return rsock_sockopt_new(AF_INET, IPPROTO_IP, IP_MULTICAST_TTL,
00434 rb_str_new((char*)&i, sizeof(i)));
00435 #else
00436 # error IPPROTO_IP or IP_MULTICAST_TTL is not implemented
00437 #endif
00438 }
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449 static VALUE
00450 sockopt_ipv4_multicast_ttl(VALUE self)
00451 {
00452 int family = NUM2INT(sockopt_family_m(self));
00453 int level = sockopt_level(self);
00454 int optname = sockopt_optname(self);
00455
00456 #if defined(IPPROTO_IP) && defined(IP_MULTICAST_TTL)
00457 if (family == AF_INET && level == IPPROTO_IP && optname == IP_MULTICAST_TTL) {
00458 # if defined(__NetBSD__) || defined(__OpenBSD__)
00459 return sockopt_byte(self);
00460 # else
00461 return sockopt_int(self);
00462 # endif
00463 }
00464 #endif
00465 rb_raise(rb_eTypeError, "ipv4_multicast_ttl socket option expected");
00466 UNREACHABLE;
00467 }
00468
00469 #if defined(__NetBSD__) || defined(__OpenBSD__)
00470 # define inspect_ipv4_multicast_ttl(a,b,c,d) inspect_byte(a,b,c,d)
00471 #else
00472 # define inspect_ipv4_multicast_ttl(a,b,c,d) inspect_int(a,b,c,d)
00473 #endif
00474
00475 static int
00476 inspect_int(int level, int optname, VALUE data, VALUE ret)
00477 {
00478 if (RSTRING_LEN(data) == sizeof(int)) {
00479 int i;
00480 memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
00481 rb_str_catf(ret, " %d", i);
00482 return 1;
00483 }
00484 else {
00485 return 0;
00486 }
00487 }
00488
00489 #if defined(__NetBSD__) || defined(__OpenBSD__)
00490 static int
00491 inspect_byte(int level, int optname, VALUE data, VALUE ret)
00492 {
00493 if (RSTRING_LEN(data) == sizeof(unsigned char)) {
00494 rb_str_catf(ret, " %d", (unsigned char)*RSTRING_PTR(data));
00495 return 1;
00496 }
00497 else {
00498 return 0;
00499 }
00500 }
00501 #endif
00502
00503 static int
00504 inspect_errno(int level, int optname, VALUE data, VALUE ret)
00505 {
00506 if (RSTRING_LEN(data) == sizeof(int)) {
00507 int i;
00508 char *err;
00509 memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
00510 err = strerror(i);
00511 rb_str_catf(ret, " %s (%d)", err, i);
00512 return 1;
00513 }
00514 else {
00515 return 0;
00516 }
00517 }
00518
00519 #if defined(IPV6_MULTICAST_LOOP)
00520 static int
00521 inspect_uint(int level, int optname, VALUE data, VALUE ret)
00522 {
00523 if (RSTRING_LEN(data) == sizeof(int)) {
00524 unsigned int i;
00525 memcpy((char*)&i, RSTRING_PTR(data), sizeof(unsigned int));
00526 rb_str_catf(ret, " %u", i);
00527 return 1;
00528 }
00529 else {
00530 return 0;
00531 }
00532 }
00533 #endif
00534
00535 #if defined(SOL_SOCKET) && defined(SO_LINGER)
00536 static int
00537 inspect_linger(int level, int optname, VALUE data, VALUE ret)
00538 {
00539 if (RSTRING_LEN(data) == sizeof(struct linger)) {
00540 struct linger s;
00541 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
00542 switch (s.l_onoff) {
00543 case 0: rb_str_cat2(ret, " off"); break;
00544 case 1: rb_str_cat2(ret, " on"); break;
00545 default: rb_str_catf(ret, " on(%d)", s.l_onoff); break;
00546 }
00547 rb_str_catf(ret, " %dsec", s.l_linger);
00548 return 1;
00549 }
00550 else {
00551 return 0;
00552 }
00553 }
00554 #endif
00555
00556 #if defined(SOL_SOCKET) && defined(SO_TYPE)
00557 static int
00558 inspect_socktype(int level, int optname, VALUE data, VALUE ret)
00559 {
00560 if (RSTRING_LEN(data) == sizeof(int)) {
00561 int i;
00562 ID id;
00563 memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
00564 id = rsock_intern_socktype(i);
00565 if (id)
00566 rb_str_catf(ret, " %s", rb_id2name(id));
00567 else
00568 rb_str_catf(ret, " %d", i);
00569 return 1;
00570 }
00571 else {
00572 return 0;
00573 }
00574 }
00575 #endif
00576
00577 static int
00578 inspect_timeval_as_interval(int level, int optname, VALUE data, VALUE ret)
00579 {
00580 if (RSTRING_LEN(data) == sizeof(struct timeval)) {
00581 struct timeval s;
00582 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
00583 rb_str_catf(ret, " %ld.%06ldsec", (long)s.tv_sec, (long)s.tv_usec);
00584 return 1;
00585 }
00586 else {
00587 return 0;
00588 }
00589 }
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631 #ifndef HAVE_INET_NTOP
00632 static const char *
00633 inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
00634 {
00635 #ifdef HAVE_INET_NTOA
00636 struct in_addr in;
00637 memcpy(&in.s_addr, addr, sizeof(in.s_addr));
00638 snprintf(numaddr, numaddr_len, "%s", inet_ntoa(in));
00639 #else
00640 unsigned long x = ntohl(*(unsigned long*)addr);
00641 snprintf(numaddr, numaddr_len, "%d.%d.%d.%d",
00642 (int) (x>>24) & 0xff, (int) (x>>16) & 0xff,
00643 (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff);
00644 #endif
00645 return numaddr;
00646 }
00647 #elif defined __MINGW64__
00648 # define inet_ntop(f,a,n,l) rb_w32_inet_ntop(f,a,n,l)
00649 #endif
00650
00651
00652 static int
00653 rb_if_indextoname(const char *succ_prefix, const char *fail_prefix, unsigned int ifindex, char *buf, size_t len)
00654 {
00655 #if defined(HAVE_IF_INDEXTONAME)
00656 char ifbuf[IFNAMSIZ];
00657 if (if_indextoname(ifindex, ifbuf) == NULL)
00658 return snprintf(buf, len, "%s%u", fail_prefix, ifindex);
00659 else
00660 return snprintf(buf, len, "%s%s", succ_prefix, ifbuf);
00661 #else
00662 # ifndef IFNAMSIZ
00663 # define IFNAMSIZ (sizeof(unsigned int)*3+1)
00664 # endif
00665 return snprintf(buf, len, "%s%u", fail_prefix, ifindex);
00666 #endif
00667 }
00668
00669 #if defined(IPPROTO_IP) && defined(HAVE_TYPE_STRUCT_IP_MREQ)
00670 static int
00671 inspect_ipv4_mreq(int level, int optname, VALUE data, VALUE ret)
00672 {
00673 if (RSTRING_LEN(data) == sizeof(struct ip_mreq)) {
00674 struct ip_mreq s;
00675 char addrbuf[INET_ADDRSTRLEN];
00676 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
00677 if (inet_ntop(AF_INET, &s.imr_multiaddr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
00678 rb_str_cat2(ret, " invalid-address");
00679 else
00680 rb_str_catf(ret, " %s", addrbuf);
00681 if (inet_ntop(AF_INET, &s.imr_interface, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
00682 rb_str_catf(ret, " invalid-address");
00683 else
00684 rb_str_catf(ret, " %s", addrbuf);
00685 return 1;
00686 }
00687 else {
00688 return 0;
00689 }
00690 }
00691 #endif
00692
00693 #if defined(IPPROTO_IP) && defined(HAVE_TYPE_STRUCT_IP_MREQN)
00694 static int
00695 inspect_ipv4_mreqn(int level, int optname, VALUE data, VALUE ret)
00696 {
00697 if (RSTRING_LEN(data) == sizeof(struct ip_mreqn)) {
00698 struct ip_mreqn s;
00699 char addrbuf[INET_ADDRSTRLEN], ifbuf[32+IFNAMSIZ];
00700 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
00701 if (inet_ntop(AF_INET, &s.imr_multiaddr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
00702 rb_str_cat2(ret, " invalid-address");
00703 else
00704 rb_str_catf(ret, " %s", addrbuf);
00705 if (inet_ntop(AF_INET, &s.imr_address, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
00706 rb_str_catf(ret, " invalid-address");
00707 else
00708 rb_str_catf(ret, " %s", addrbuf);
00709 rb_if_indextoname(" ", " ifindex:", s.imr_ifindex, ifbuf, sizeof(ifbuf));
00710 rb_str_cat2(ret, ifbuf);
00711 return 1;
00712 }
00713 else {
00714 return 0;
00715 }
00716 }
00717 #endif
00718
00719 #if defined(IPPROTO_IP) && defined(HAVE_TYPE_STRUCT_IP_MREQ)
00720 static int
00721 inspect_ipv4_add_drop_membership(int level, int optname, VALUE data, VALUE ret)
00722 {
00723 if (RSTRING_LEN(data) == sizeof(struct ip_mreq))
00724 return inspect_ipv4_mreq(level, optname, data, ret);
00725 # if defined(HAVE_TYPE_STRUCT_IP_MREQN)
00726 else if (RSTRING_LEN(data) == sizeof(struct ip_mreqn))
00727 return inspect_ipv4_mreqn(level, optname, data, ret);
00728 # endif
00729 else
00730 return 0;
00731 }
00732 #endif
00733
00734 #if defined(IPPROTO_IP) && defined(IP_MULTICAST_IF) && defined(HAVE_TYPE_STRUCT_IP_MREQN)
00735 static int
00736 inspect_ipv4_multicast_if(int level, int optname, VALUE data, VALUE ret)
00737 {
00738 if (RSTRING_LEN(data) == sizeof(struct in_addr)) {
00739 struct in_addr s;
00740 char addrbuf[INET_ADDRSTRLEN];
00741 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
00742 if (inet_ntop(AF_INET, &s, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
00743 rb_str_cat2(ret, " invalid-address");
00744 else
00745 rb_str_catf(ret, " %s", addrbuf);
00746 return 1;
00747 }
00748 else if (RSTRING_LEN(data) == sizeof(struct ip_mreqn)) {
00749 return inspect_ipv4_mreqn(level, optname, data, ret);
00750 }
00751 else {
00752 return 0;
00753 }
00754 }
00755 #endif
00756
00757 #if defined(IPV6_MULTICAST_IF)
00758 static int
00759 inspect_ipv6_multicast_if(int level, int optname, VALUE data, VALUE ret)
00760 {
00761 if (RSTRING_LEN(data) == sizeof(int)) {
00762 char ifbuf[32+IFNAMSIZ];
00763 unsigned int ifindex;
00764 memcpy((char*)&ifindex, RSTRING_PTR(data), sizeof(unsigned int));
00765 rb_if_indextoname(" ", " ", ifindex, ifbuf, sizeof(ifbuf));
00766 rb_str_cat2(ret, ifbuf);
00767 return 1;
00768 }
00769 else {
00770 return 0;
00771 }
00772 }
00773 #endif
00774
00775 #if defined(IPPROTO_IPV6) && defined(HAVE_TYPE_STRUCT_IPV6_MREQ)
00776 static int
00777 inspect_ipv6_mreq(int level, int optname, VALUE data, VALUE ret)
00778 {
00779 if (RSTRING_LEN(data) == sizeof(struct ipv6_mreq)) {
00780 struct ipv6_mreq s;
00781 char addrbuf[INET6_ADDRSTRLEN], ifbuf[32+IFNAMSIZ];
00782 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
00783 if (inet_ntop(AF_INET6, &s.ipv6mr_multiaddr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
00784 rb_str_cat2(ret, " invalid-address");
00785 else
00786 rb_str_catf(ret, " %s", addrbuf);
00787 rb_if_indextoname(" ", " interface:", s.ipv6mr_interface, ifbuf, sizeof(ifbuf));
00788 rb_str_cat2(ret, ifbuf);
00789 return 1;
00790 }
00791 else {
00792 return 0;
00793 }
00794 }
00795 #endif
00796
00797 #if defined(SOL_SOCKET) && defined(SO_PEERCRED)
00798 #if defined(__OpenBSD__)
00799 #define RUBY_SOCK_PEERCRED struct sockpeercred
00800 #else
00801 #define RUBY_SOCK_PEERCRED struct ucred
00802 #endif
00803 static int
00804 inspect_peercred(int level, int optname, VALUE data, VALUE ret)
00805 {
00806 if (RSTRING_LEN(data) == sizeof(RUBY_SOCK_PEERCRED)) {
00807 RUBY_SOCK_PEERCRED cred;
00808 memcpy(&cred, RSTRING_PTR(data), sizeof(RUBY_SOCK_PEERCRED));
00809 rb_str_catf(ret, " pid=%u euid=%u egid=%u",
00810 (unsigned)cred.pid, (unsigned)cred.uid, (unsigned)cred.gid);
00811 rb_str_cat2(ret, " (ucred)");
00812 return 1;
00813 }
00814 else {
00815 return 0;
00816 }
00817 }
00818 #endif
00819
00820 #if defined(LOCAL_PEERCRED)
00821 static int
00822 inspect_local_peercred(int level, int optname, VALUE data, VALUE ret)
00823 {
00824 if (RSTRING_LEN(data) == sizeof(struct xucred)) {
00825 struct xucred cred;
00826 memcpy(&cred, RSTRING_PTR(data), sizeof(struct xucred));
00827 if (cred.cr_version != XUCRED_VERSION)
00828 return 0;
00829 rb_str_catf(ret, " version=%u", cred.cr_version);
00830 rb_str_catf(ret, " euid=%u", cred.cr_uid);
00831 if (cred.cr_ngroups) {
00832 int i;
00833 const char *sep = " groups=";
00834 for (i = 0; i < cred.cr_ngroups; i++) {
00835 rb_str_catf(ret, "%s%u", sep, cred.cr_groups[i]);
00836 sep = ",";
00837 }
00838 }
00839 rb_str_cat2(ret, " (xucred)");
00840 return 1;
00841 }
00842 else {
00843 return 0;
00844 }
00845 }
00846 #endif
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859 static VALUE
00860 sockopt_inspect(VALUE self)
00861 {
00862 int family = NUM2INT(sockopt_family_m(self));
00863 int level = NUM2INT(sockopt_level_m(self));
00864 int optname = NUM2INT(sockopt_optname_m(self));
00865 VALUE data = sockopt_data(self);
00866 VALUE v, ret;
00867 ID family_id, level_id, optname_id;
00868 int inspected;
00869
00870 StringValue(data);
00871
00872 ret = rb_sprintf("#<%s:", rb_obj_classname(self));
00873
00874 family_id = rsock_intern_family_noprefix(family);
00875 if (family_id)
00876 rb_str_catf(ret, " %s", rb_id2name(family_id));
00877 else
00878 rb_str_catf(ret, " family:%d", family);
00879
00880 if (level == SOL_SOCKET) {
00881 rb_str_cat2(ret, " SOCKET");
00882
00883 optname_id = rsock_intern_so_optname(optname);
00884 if (optname_id)
00885 rb_str_catf(ret, " %s", rb_id2name(optname_id));
00886 else
00887 rb_str_catf(ret, " optname:%d", optname);
00888 }
00889 #ifdef HAVE_SYS_UN_H
00890 else if (family == AF_UNIX) {
00891 rb_str_catf(ret, " level:%d", level);
00892
00893 optname_id = rsock_intern_local_optname(optname);
00894 if (optname_id)
00895 rb_str_catf(ret, " %s", rb_id2name(optname_id));
00896 else
00897 rb_str_catf(ret, " optname:%d", optname);
00898 }
00899 #endif
00900 else if (IS_IP_FAMILY(family)) {
00901 level_id = rsock_intern_iplevel(level);
00902 if (level_id)
00903 rb_str_catf(ret, " %s", rb_id2name(level_id));
00904 else
00905 rb_str_catf(ret, " level:%d", level);
00906
00907 v = optname_to_sym(level, optname);
00908 if (SYMBOL_P(v))
00909 rb_str_catf(ret, " %s", rb_id2name(SYM2ID(v)));
00910 else
00911 rb_str_catf(ret, " optname:%d", optname);
00912 }
00913 else {
00914 rb_str_catf(ret, " level:%d", level);
00915 rb_str_catf(ret, " optname:%d", optname);
00916 }
00917
00918 inspected = 0;
00919
00920 if (level == SOL_SOCKET)
00921 family = AF_UNSPEC;
00922 switch (family) {
00923 case AF_UNSPEC:
00924 switch (level) {
00925 case SOL_SOCKET:
00926 switch (optname) {
00927 # if defined(SO_DEBUG)
00928 case SO_DEBUG: inspected = inspect_int(level, optname, data, ret); break;
00929 # endif
00930 # if defined(SO_ERROR)
00931 case SO_ERROR: inspected = inspect_errno(level, optname, data, ret); break;
00932 # endif
00933 # if defined(SO_TYPE)
00934 case SO_TYPE: inspected = inspect_socktype(level, optname, data, ret); break;
00935 # endif
00936 # if defined(SO_ACCEPTCONN)
00937 case SO_ACCEPTCONN: inspected = inspect_int(level, optname, data, ret); break;
00938 # endif
00939 # if defined(SO_BROADCAST)
00940 case SO_BROADCAST: inspected = inspect_int(level, optname, data, ret); break;
00941 # endif
00942 # if defined(SO_REUSEADDR)
00943 case SO_REUSEADDR: inspected = inspect_int(level, optname, data, ret); break;
00944 # endif
00945 # if defined(SO_KEEPALIVE)
00946 case SO_KEEPALIVE: inspected = inspect_int(level, optname, data, ret); break;
00947 # endif
00948 # if defined(SO_OOBINLINE)
00949 case SO_OOBINLINE: inspected = inspect_int(level, optname, data, ret); break;
00950 # endif
00951 # if defined(SO_SNDBUF)
00952 case SO_SNDBUF: inspected = inspect_int(level, optname, data, ret); break;
00953 # endif
00954 # if defined(SO_RCVBUF)
00955 case SO_RCVBUF: inspected = inspect_int(level, optname, data, ret); break;
00956 # endif
00957 # if defined(SO_DONTROUTE)
00958 case SO_DONTROUTE: inspected = inspect_int(level, optname, data, ret); break;
00959 # endif
00960 # if defined(SO_RCVLOWAT)
00961 case SO_RCVLOWAT: inspected = inspect_int(level, optname, data, ret); break;
00962 # endif
00963 # if defined(SO_SNDLOWAT)
00964 case SO_SNDLOWAT: inspected = inspect_int(level, optname, data, ret); break;
00965 # endif
00966 # if defined(SO_LINGER)
00967 case SO_LINGER: inspected = inspect_linger(level, optname, data, ret); break;
00968 # endif
00969 # if defined(SO_RCVTIMEO)
00970 case SO_RCVTIMEO: inspected = inspect_timeval_as_interval(level, optname, data, ret); break;
00971 # endif
00972 # if defined(SO_SNDTIMEO)
00973 case SO_SNDTIMEO: inspected = inspect_timeval_as_interval(level, optname, data, ret); break;
00974 # endif
00975 # if defined(SO_PEERCRED)
00976 case SO_PEERCRED: inspected = inspect_peercred(level, optname, data, ret); break;
00977 # endif
00978 }
00979 break;
00980 }
00981 break;
00982
00983 case AF_INET:
00984 #ifdef INET6
00985 case AF_INET6:
00986 #endif
00987 switch (level) {
00988 # if defined(IPPROTO_IP)
00989 case IPPROTO_IP:
00990 switch (optname) {
00991 # if defined(IP_MULTICAST_IF) && defined(HAVE_TYPE_STRUCT_IP_MREQN)
00992 case IP_MULTICAST_IF: inspected = inspect_ipv4_multicast_if(level, optname, data, ret); break;
00993 # endif
00994 # if defined(IP_ADD_MEMBERSHIP)
00995 case IP_ADD_MEMBERSHIP: inspected = inspect_ipv4_add_drop_membership(level, optname, data, ret); break;
00996 # endif
00997 # if defined(IP_DROP_MEMBERSHIP)
00998 case IP_DROP_MEMBERSHIP: inspected = inspect_ipv4_add_drop_membership(level, optname, data, ret); break;
00999 # endif
01000 # if defined(IP_MULTICAST_LOOP)
01001 case IP_MULTICAST_LOOP: inspected = inspect_ipv4_multicast_loop(level, optname, data, ret); break;
01002 # endif
01003 # if defined(IP_MULTICAST_TTL)
01004 case IP_MULTICAST_TTL: inspected = inspect_ipv4_multicast_ttl(level, optname, data, ret); break;
01005 # endif
01006 }
01007 break;
01008 # endif
01009
01010 # if defined(IPPROTO_IPV6)
01011 case IPPROTO_IPV6:
01012 switch (optname) {
01013 # if defined(IPV6_MULTICAST_HOPS)
01014 case IPV6_MULTICAST_HOPS: inspected = inspect_int(level, optname, data, ret); break;
01015 # endif
01016 # if defined(IPV6_MULTICAST_IF)
01017 case IPV6_MULTICAST_IF: inspected = inspect_ipv6_multicast_if(level, optname, data, ret); break;
01018 # endif
01019 # if defined(IPV6_MULTICAST_LOOP)
01020 case IPV6_MULTICAST_LOOP: inspected = inspect_uint(level, optname, data, ret); break;
01021 # endif
01022 # if defined(IPV6_JOIN_GROUP)
01023 case IPV6_JOIN_GROUP: inspected = inspect_ipv6_mreq(level, optname, data, ret); break;
01024 # endif
01025 # if defined(IPV6_LEAVE_GROUP)
01026 case IPV6_LEAVE_GROUP: inspected = inspect_ipv6_mreq(level, optname, data, ret); break;
01027 # endif
01028 # if defined(IPV6_UNICAST_HOPS)
01029 case IPV6_UNICAST_HOPS: inspected = inspect_int(level, optname, data, ret); break;
01030 # endif
01031 # if defined(IPV6_V6ONLY)
01032 case IPV6_V6ONLY: inspected = inspect_int(level, optname, data, ret); break;
01033 # endif
01034 }
01035 break;
01036 # endif
01037
01038 # if defined(IPPROTO_TCP)
01039 case IPPROTO_TCP:
01040 switch (optname) {
01041 # if defined(TCP_NODELAY)
01042 case TCP_NODELAY: inspected = inspect_int(level, optname, data, ret); break;
01043 # endif
01044 }
01045 break;
01046 # endif
01047 }
01048 break;
01049
01050 #ifdef HAVE_SYS_UN_H
01051 case AF_UNIX:
01052 switch (level) {
01053 case 0:
01054 switch (optname) {
01055 # if defined(LOCAL_PEERCRED)
01056 case LOCAL_PEERCRED: inspected = inspect_local_peercred(level, optname, data, ret); break;
01057 # endif
01058 }
01059 break;
01060 }
01061 break;
01062 #endif
01063 }
01064
01065 if (!inspected) {
01066 rb_str_cat2(ret, " ");
01067 rb_str_append(ret, rb_str_dump(data));
01068 }
01069
01070 rb_str_cat2(ret, ">");
01071
01072 return ret;
01073 }
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085 static VALUE
01086 sockopt_unpack(VALUE self, VALUE template)
01087 {
01088 return rb_funcall(sockopt_data(self), rb_intern("unpack"), 1, template);
01089 }
01090
01091 void
01092 rsock_init_sockopt(void)
01093 {
01094
01095
01096
01097
01098
01099
01100
01101
01102 rb_cSockOpt = rb_define_class_under(rb_cSocket, "Option", rb_cObject);
01103 rb_define_method(rb_cSockOpt, "initialize", sockopt_initialize, 4);
01104 rb_define_method(rb_cSockOpt, "family", sockopt_family_m, 0);
01105 rb_define_method(rb_cSockOpt, "level", sockopt_level_m, 0);
01106 rb_define_method(rb_cSockOpt, "optname", sockopt_optname_m, 0);
01107 rb_define_method(rb_cSockOpt, "data", sockopt_data, 0);
01108 rb_define_method(rb_cSockOpt, "inspect", sockopt_inspect, 0);
01109
01110 rb_define_singleton_method(rb_cSockOpt, "int", sockopt_s_int, 4);
01111 rb_define_method(rb_cSockOpt, "int", sockopt_int, 0);
01112
01113 rb_define_singleton_method(rb_cSockOpt, "byte", sockopt_s_byte, 4);
01114 rb_define_method(rb_cSockOpt, "byte", sockopt_byte, 0);
01115
01116 rb_define_singleton_method(rb_cSockOpt, "bool", sockopt_s_bool, 4);
01117 rb_define_method(rb_cSockOpt, "bool", sockopt_bool, 0);
01118
01119 rb_define_singleton_method(rb_cSockOpt, "linger", sockopt_s_linger, 2);
01120 rb_define_method(rb_cSockOpt, "linger", sockopt_linger, 0);
01121
01122 rb_define_singleton_method(rb_cSockOpt, "ipv4_multicast_ttl", sockopt_s_ipv4_multicast_ttl, 1);
01123 rb_define_method(rb_cSockOpt, "ipv4_multicast_ttl", sockopt_ipv4_multicast_ttl, 0);
01124
01125 rb_define_singleton_method(rb_cSockOpt, "ipv4_multicast_loop", sockopt_s_ipv4_multicast_loop, 1);
01126 rb_define_method(rb_cSockOpt, "ipv4_multicast_loop", sockopt_ipv4_multicast_loop, 0);
01127
01128 rb_define_method(rb_cSockOpt, "unpack", sockopt_unpack, 1);
01129
01130 rb_define_method(rb_cSockOpt, "to_s", sockopt_data, 0);
01131 }
01132
01133