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