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
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 static VALUE
00137 sockopt_data(VALUE self)
00138 {
00139 VALUE v = rb_attr_get(self, rb_intern("data"));
00140 StringValue(v);
00141 return v;
00142 }
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155 static VALUE
00156 sockopt_s_int(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE vint)
00157 {
00158 int family = rsock_family_arg(vfamily);
00159 int level = rsock_level_arg(family, vlevel);
00160 int optname = rsock_optname_arg(family, level, voptname);
00161 int i = NUM2INT(vint);
00162 return rsock_sockopt_new(family, level, optname, rb_str_new((char*)&i, sizeof(i)));
00163 }
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176 static VALUE
00177 sockopt_int(VALUE self)
00178 {
00179 int i;
00180 VALUE data = sockopt_data(self);
00181 StringValue(data);
00182 if (RSTRING_LEN(data) != sizeof(int))
00183 rb_raise(rb_eTypeError, "size differ. expected as sizeof(int)=%d but %ld",
00184 (int)sizeof(int), (long)RSTRING_LEN(data));
00185 memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
00186 return INT2NUM(i);
00187 }
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203 static VALUE
00204 sockopt_s_bool(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE voptname, VALUE vbool)
00205 {
00206 int family = rsock_family_arg(vfamily);
00207 int level = rsock_level_arg(family, vlevel);
00208 int optname = rsock_optname_arg(family, level, voptname);
00209 int i = RTEST(vbool) ? 1 : 0;
00210 return rsock_sockopt_new(family, level, optname, rb_str_new((char*)&i, sizeof(i)));
00211 }
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222 static VALUE
00223 sockopt_bool(VALUE self)
00224 {
00225 int i;
00226 VALUE data = sockopt_data(self);
00227 StringValue(data);
00228 if (RSTRING_LEN(data) != sizeof(int))
00229 rb_raise(rb_eTypeError, "size differ. expected as sizeof(int)=%d but %ld",
00230 (int)sizeof(int), (long)RSTRING_LEN(data));
00231 memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
00232 return i == 0 ? Qfalse : Qtrue;
00233 }
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249 static VALUE
00250 sockopt_s_linger(VALUE klass, VALUE vonoff, VALUE vsecs)
00251 {
00252 VALUE tmp;
00253 struct linger l;
00254 memset(&l, 0, sizeof(l));
00255 if (!NIL_P(tmp = rb_check_to_integer(vonoff, "to_int")))
00256 l.l_onoff = NUM2INT(tmp);
00257 else
00258 l.l_onoff = RTEST(vonoff) ? 1 : 0;
00259 l.l_linger = NUM2INT(vsecs);
00260 return rsock_sockopt_new(AF_UNSPEC, SOL_SOCKET, SO_LINGER, rb_str_new((char*)&l, sizeof(l)));
00261 }
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272 static VALUE
00273 sockopt_linger(VALUE self)
00274 {
00275 int level = sockopt_level(self);
00276 int optname = sockopt_optname(self);
00277 VALUE data = sockopt_data(self);
00278 struct linger l;
00279 VALUE vonoff, vsecs;
00280
00281 if (level != SOL_SOCKET || optname != SO_LINGER)
00282 rb_raise(rb_eTypeError, "linger socket option expected");
00283 if (RSTRING_LEN(data) != sizeof(l))
00284 rb_raise(rb_eTypeError, "size differ. expected as sizeof(struct linger)=%d but %ld",
00285 (int)sizeof(struct linger), (long)RSTRING_LEN(data));
00286 memcpy((char*)&l, RSTRING_PTR(data), sizeof(struct linger));
00287 switch (l.l_onoff) {
00288 case 0: vonoff = Qfalse; break;
00289 case 1: vonoff = Qtrue; break;
00290 default: vonoff = INT2NUM(l.l_onoff); break;
00291 }
00292 vsecs = INT2NUM(l.l_linger);
00293 return rb_assoc_new(vonoff, vsecs);
00294 }
00295
00296 static int
00297 inspect_int(int level, int optname, VALUE data, VALUE ret)
00298 {
00299 if (RSTRING_LEN(data) == sizeof(int)) {
00300 int i;
00301 memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
00302 rb_str_catf(ret, " %d", i);
00303 return 1;
00304 }
00305 else {
00306 return 0;
00307 }
00308 }
00309
00310 static int
00311 inspect_errno(int level, int optname, VALUE data, VALUE ret)
00312 {
00313 if (RSTRING_LEN(data) == sizeof(int)) {
00314 int i;
00315 char *err;
00316 memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
00317 err = strerror(i);
00318 rb_str_catf(ret, " %s (%d)", err, i);
00319 return 1;
00320 }
00321 else {
00322 return 0;
00323 }
00324 }
00325
00326 #if defined(IPV6_MULTICAST_LOOP)
00327 static int
00328 inspect_uint(int level, int optname, VALUE data, VALUE ret)
00329 {
00330 if (RSTRING_LEN(data) == sizeof(int)) {
00331 unsigned int i;
00332 memcpy((char*)&i, RSTRING_PTR(data), sizeof(unsigned int));
00333 rb_str_catf(ret, " %u", i);
00334 return 1;
00335 }
00336 else {
00337 return 0;
00338 }
00339 }
00340 #endif
00341
00342 #if defined(SOL_SOCKET) && defined(SO_LINGER)
00343 static int
00344 inspect_linger(int level, int optname, VALUE data, VALUE ret)
00345 {
00346 if (RSTRING_LEN(data) == sizeof(struct linger)) {
00347 struct linger s;
00348 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
00349 switch (s.l_onoff) {
00350 case 0: rb_str_cat2(ret, " off"); break;
00351 case 1: rb_str_cat2(ret, " on"); break;
00352 default: rb_str_catf(ret, " on(%d)", s.l_onoff); break;
00353 }
00354 rb_str_catf(ret, " %dsec", s.l_linger);
00355 return 1;
00356 }
00357 else {
00358 return 0;
00359 }
00360 }
00361 #endif
00362
00363 #if defined(SOL_SOCKET) && defined(SO_TYPE)
00364 static int
00365 inspect_socktype(int level, int optname, VALUE data, VALUE ret)
00366 {
00367 if (RSTRING_LEN(data) == sizeof(int)) {
00368 int i;
00369 ID id;
00370 memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
00371 id = rsock_intern_socktype(i);
00372 if (id)
00373 rb_str_catf(ret, " %s", rb_id2name(id));
00374 else
00375 rb_str_catf(ret, " %d", i);
00376 return 1;
00377 }
00378 else {
00379 return 0;
00380 }
00381 }
00382 #endif
00383
00384 static int
00385 inspect_timeval_as_interval(int level, int optname, VALUE data, VALUE ret)
00386 {
00387 if (RSTRING_LEN(data) == sizeof(struct timeval)) {
00388 struct timeval s;
00389 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
00390 rb_str_catf(ret, " %ld.%06ldsec", (long)s.tv_sec, (long)s.tv_usec);
00391 return 1;
00392 }
00393 else {
00394 return 0;
00395 }
00396 }
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438 #ifndef HAVE_INET_NTOP
00439 static const char *
00440 inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
00441 {
00442 #ifdef HAVE_INET_NTOA
00443 struct in_addr in;
00444 memcpy(&in.s_addr, addr, sizeof(in.s_addr));
00445 snprintf(numaddr, numaddr_len, "%s", inet_ntoa(in));
00446 #else
00447 unsigned long x = ntohl(*(unsigned long*)addr);
00448 snprintf(numaddr, numaddr_len, "%d.%d.%d.%d",
00449 (int) (x>>24) & 0xff, (int) (x>>16) & 0xff,
00450 (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff);
00451 #endif
00452 return numaddr;
00453 }
00454 #elif defined __MINGW64__
00455 # define inet_ntop(f,a,n,l) rb_w32_inet_ntop(f,a,n,l)
00456 #endif
00457
00458
00459 static int
00460 rb_if_indextoname(const char *succ_prefix, const char *fail_prefix, unsigned int ifindex, char *buf, size_t len)
00461 {
00462 #if defined(HAVE_IF_INDEXTONAME)
00463 char ifbuf[IFNAMSIZ];
00464 if (if_indextoname(ifindex, ifbuf) == NULL)
00465 return snprintf(buf, len, "%s%u", fail_prefix, ifindex);
00466 else
00467 return snprintf(buf, len, "%s%s", succ_prefix, ifbuf);
00468 #else
00469 # ifndef IFNAMSIZ
00470 # define IFNAMSIZ (sizeof(unsigned int)*3+1)
00471 # endif
00472 return snprintf(buf, len, "%s%u", fail_prefix, ifindex);
00473 #endif
00474 }
00475
00476 #if defined(IPPROTO_IP) && defined(HAVE_TYPE_STRUCT_IP_MREQ)
00477 static int
00478 inspect_ipv4_mreq(int level, int optname, VALUE data, VALUE ret)
00479 {
00480 if (RSTRING_LEN(data) == sizeof(struct ip_mreq)) {
00481 struct ip_mreq s;
00482 char addrbuf[INET_ADDRSTRLEN];
00483 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
00484 if (inet_ntop(AF_INET, &s.imr_multiaddr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
00485 rb_str_cat2(ret, " invalid-address");
00486 else
00487 rb_str_catf(ret, " %s", addrbuf);
00488 if (inet_ntop(AF_INET, &s.imr_interface, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
00489 rb_str_catf(ret, " invalid-address");
00490 else
00491 rb_str_catf(ret, " %s", addrbuf);
00492 return 1;
00493 }
00494 else {
00495 return 0;
00496 }
00497 }
00498 #endif
00499
00500 #if defined(IPPROTO_IP) && defined(HAVE_TYPE_STRUCT_IP_MREQN)
00501 static int
00502 inspect_ipv4_mreqn(int level, int optname, VALUE data, VALUE ret)
00503 {
00504 if (RSTRING_LEN(data) == sizeof(struct ip_mreqn)) {
00505 struct ip_mreqn s;
00506 char addrbuf[INET_ADDRSTRLEN], ifbuf[32+IFNAMSIZ];
00507 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
00508 if (inet_ntop(AF_INET, &s.imr_multiaddr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
00509 rb_str_cat2(ret, " invalid-address");
00510 else
00511 rb_str_catf(ret, " %s", addrbuf);
00512 if (inet_ntop(AF_INET, &s.imr_address, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
00513 rb_str_catf(ret, " invalid-address");
00514 else
00515 rb_str_catf(ret, " %s", addrbuf);
00516 rb_if_indextoname(" ", " ifindex:", s.imr_ifindex, ifbuf, sizeof(ifbuf));
00517 rb_str_cat2(ret, ifbuf);
00518 return 1;
00519 }
00520 else {
00521 return 0;
00522 }
00523 }
00524 #endif
00525
00526 #if defined(IPPROTO_IP) && defined(HAVE_TYPE_STRUCT_IP_MREQ)
00527 static int
00528 inspect_ipv4_add_drop_membership(int level, int optname, VALUE data, VALUE ret)
00529 {
00530 if (RSTRING_LEN(data) == sizeof(struct ip_mreq))
00531 return inspect_ipv4_mreq(level, optname, data, ret);
00532 # if defined(HAVE_TYPE_STRUCT_IP_MREQN)
00533 else if (RSTRING_LEN(data) == sizeof(struct ip_mreqn))
00534 return inspect_ipv4_mreqn(level, optname, data, ret);
00535 # endif
00536 else
00537 return 0;
00538 }
00539 #endif
00540
00541 #if defined(IPPROTO_IP) && defined(IP_MULTICAST_IF) && defined(HAVE_TYPE_STRUCT_IP_MREQN)
00542 static int
00543 inspect_ipv4_multicast_if(int level, int optname, VALUE data, VALUE ret)
00544 {
00545 if (RSTRING_LEN(data) == sizeof(struct in_addr)) {
00546 struct in_addr s;
00547 char addrbuf[INET_ADDRSTRLEN];
00548 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
00549 if (inet_ntop(AF_INET, &s, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
00550 rb_str_cat2(ret, " invalid-address");
00551 else
00552 rb_str_catf(ret, " %s", addrbuf);
00553 return 1;
00554 }
00555 else if (RSTRING_LEN(data) == sizeof(struct ip_mreqn)) {
00556 return inspect_ipv4_mreqn(level, optname, data, ret);
00557 }
00558 else {
00559 return 0;
00560 }
00561 }
00562 #endif
00563
00564 #if defined(IPV6_MULTICAST_IF)
00565 static int
00566 inspect_ipv6_multicast_if(int level, int optname, VALUE data, VALUE ret)
00567 {
00568 if (RSTRING_LEN(data) == sizeof(int)) {
00569 char ifbuf[32+IFNAMSIZ];
00570 unsigned int ifindex;
00571 memcpy((char*)&ifindex, RSTRING_PTR(data), sizeof(unsigned int));
00572 rb_if_indextoname(" ", " ", ifindex, ifbuf, sizeof(ifbuf));
00573 rb_str_cat2(ret, ifbuf);
00574 return 1;
00575 }
00576 else {
00577 return 0;
00578 }
00579 }
00580 #endif
00581
00582 #if defined(IPPROTO_IPV6) && defined(HAVE_TYPE_STRUCT_IPV6_MREQ)
00583 static int
00584 inspect_ipv6_mreq(int level, int optname, VALUE data, VALUE ret)
00585 {
00586 if (RSTRING_LEN(data) == sizeof(struct ipv6_mreq)) {
00587 struct ipv6_mreq s;
00588 char addrbuf[INET6_ADDRSTRLEN], ifbuf[32+IFNAMSIZ];
00589 memcpy((char*)&s, RSTRING_PTR(data), sizeof(s));
00590 if (inet_ntop(AF_INET6, &s.ipv6mr_multiaddr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
00591 rb_str_cat2(ret, " invalid-address");
00592 else
00593 rb_str_catf(ret, " %s", addrbuf);
00594 rb_if_indextoname(" ", " interface:", s.ipv6mr_interface, ifbuf, sizeof(ifbuf));
00595 rb_str_cat2(ret, ifbuf);
00596 return 1;
00597 }
00598 else {
00599 return 0;
00600 }
00601 }
00602 #endif
00603
00604 #if defined(SOL_SOCKET) && defined(SO_PEERCRED)
00605 #if defined(__OpenBSD__)
00606 #define RUBY_SOCK_PEERCRED struct sockpeercred
00607 #else
00608 #define RUBY_SOCK_PEERCRED struct ucred
00609 #endif
00610 static int
00611 inspect_peercred(int level, int optname, VALUE data, VALUE ret)
00612 {
00613 if (RSTRING_LEN(data) == sizeof(RUBY_SOCK_PEERCRED)) {
00614 RUBY_SOCK_PEERCRED cred;
00615 memcpy(&cred, RSTRING_PTR(data), sizeof(RUBY_SOCK_PEERCRED));
00616 rb_str_catf(ret, " pid=%u euid=%u egid=%u",
00617 (unsigned)cred.pid, (unsigned)cred.uid, (unsigned)cred.gid);
00618 rb_str_cat2(ret, " (ucred)");
00619 return 1;
00620 }
00621 else {
00622 return 0;
00623 }
00624 }
00625 #endif
00626
00627 #if defined(LOCAL_PEERCRED)
00628 static int
00629 inspect_local_peercred(int level, int optname, VALUE data, VALUE ret)
00630 {
00631 if (RSTRING_LEN(data) == sizeof(struct xucred)) {
00632 struct xucred cred;
00633 memcpy(&cred, RSTRING_PTR(data), sizeof(struct xucred));
00634 if (cred.cr_version != XUCRED_VERSION)
00635 return 0;
00636 rb_str_catf(ret, " version=%u", cred.cr_version);
00637 rb_str_catf(ret, " euid=%u", cred.cr_uid);
00638 if (cred.cr_ngroups) {
00639 int i;
00640 const char *sep = " groups=";
00641 for (i = 0; i < cred.cr_ngroups; i++) {
00642 rb_str_catf(ret, "%s%u", sep, cred.cr_groups[i]);
00643 sep = ",";
00644 }
00645 }
00646 rb_str_cat2(ret, " (xucred)");
00647 return 1;
00648 }
00649 else {
00650 return 0;
00651 }
00652 }
00653 #endif
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666 static VALUE
00667 sockopt_inspect(VALUE self)
00668 {
00669 int family = NUM2INT(sockopt_family_m(self));
00670 int level = NUM2INT(sockopt_level_m(self));
00671 int optname = NUM2INT(sockopt_optname_m(self));
00672 VALUE data = sockopt_data(self);
00673 VALUE v, ret;
00674 ID family_id, level_id, optname_id;
00675 int inspected;
00676
00677 StringValue(data);
00678
00679 ret = rb_sprintf("#<%s:", rb_obj_classname(self));
00680
00681 family_id = rsock_intern_family_noprefix(family);
00682 if (family_id)
00683 rb_str_catf(ret, " %s", rb_id2name(family_id));
00684 else
00685 rb_str_catf(ret, " family:%d", family);
00686
00687 if (level == SOL_SOCKET) {
00688 rb_str_cat2(ret, " SOCKET");
00689
00690 optname_id = rsock_intern_so_optname(optname);
00691 if (optname_id)
00692 rb_str_catf(ret, " %s", rb_id2name(optname_id));
00693 else
00694 rb_str_catf(ret, " optname:%d", optname);
00695 }
00696 #ifdef HAVE_SYS_UN_H
00697 else if (family == AF_UNIX) {
00698 rb_str_catf(ret, " level:%d", level);
00699
00700 optname_id = rsock_intern_local_optname(optname);
00701 if (optname_id)
00702 rb_str_catf(ret, " %s", rb_id2name(optname_id));
00703 else
00704 rb_str_catf(ret, " optname:%d", optname);
00705 }
00706 #endif
00707 else if (IS_IP_FAMILY(family)) {
00708 level_id = rsock_intern_iplevel(level);
00709 if (level_id)
00710 rb_str_catf(ret, " %s", rb_id2name(level_id));
00711 else
00712 rb_str_catf(ret, " level:%d", level);
00713
00714 v = optname_to_sym(level, optname);
00715 if (SYMBOL_P(v))
00716 rb_str_catf(ret, " %s", rb_id2name(SYM2ID(v)));
00717 else
00718 rb_str_catf(ret, " optname:%d", optname);
00719 }
00720 else {
00721 rb_str_catf(ret, " level:%d", level);
00722 rb_str_catf(ret, " optname:%d", optname);
00723 }
00724
00725 inspected = 0;
00726
00727 if (level == SOL_SOCKET)
00728 family = AF_UNSPEC;
00729 switch (family) {
00730 case AF_UNSPEC:
00731 switch (level) {
00732 case SOL_SOCKET:
00733 switch (optname) {
00734 # if defined(SO_DEBUG)
00735 case SO_DEBUG: inspected = inspect_int(level, optname, data, ret); break;
00736 # endif
00737 # if defined(SO_ERROR)
00738 case SO_ERROR: inspected = inspect_errno(level, optname, data, ret); break;
00739 # endif
00740 # if defined(SO_TYPE)
00741 case SO_TYPE: inspected = inspect_socktype(level, optname, data, ret); break;
00742 # endif
00743 # if defined(SO_ACCEPTCONN)
00744 case SO_ACCEPTCONN: inspected = inspect_int(level, optname, data, ret); break;
00745 # endif
00746 # if defined(SO_BROADCAST)
00747 case SO_BROADCAST: inspected = inspect_int(level, optname, data, ret); break;
00748 # endif
00749 # if defined(SO_REUSEADDR)
00750 case SO_REUSEADDR: inspected = inspect_int(level, optname, data, ret); break;
00751 # endif
00752 # if defined(SO_KEEPALIVE)
00753 case SO_KEEPALIVE: inspected = inspect_int(level, optname, data, ret); break;
00754 # endif
00755 # if defined(SO_OOBINLINE)
00756 case SO_OOBINLINE: inspected = inspect_int(level, optname, data, ret); break;
00757 # endif
00758 # if defined(SO_SNDBUF)
00759 case SO_SNDBUF: inspected = inspect_int(level, optname, data, ret); break;
00760 # endif
00761 # if defined(SO_RCVBUF)
00762 case SO_RCVBUF: inspected = inspect_int(level, optname, data, ret); break;
00763 # endif
00764 # if defined(SO_DONTROUTE)
00765 case SO_DONTROUTE: inspected = inspect_int(level, optname, data, ret); break;
00766 # endif
00767 # if defined(SO_RCVLOWAT)
00768 case SO_RCVLOWAT: inspected = inspect_int(level, optname, data, ret); break;
00769 # endif
00770 # if defined(SO_SNDLOWAT)
00771 case SO_SNDLOWAT: inspected = inspect_int(level, optname, data, ret); break;
00772 # endif
00773 # if defined(SO_LINGER)
00774 case SO_LINGER: inspected = inspect_linger(level, optname, data, ret); break;
00775 # endif
00776 # if defined(SO_RCVTIMEO)
00777 case SO_RCVTIMEO: inspected = inspect_timeval_as_interval(level, optname, data, ret); break;
00778 # endif
00779 # if defined(SO_SNDTIMEO)
00780 case SO_SNDTIMEO: inspected = inspect_timeval_as_interval(level, optname, data, ret); break;
00781 # endif
00782 # if defined(SO_PEERCRED)
00783 case SO_PEERCRED: inspected = inspect_peercred(level, optname, data, ret); break;
00784 # endif
00785 }
00786 break;
00787 }
00788 break;
00789
00790 case AF_INET:
00791 #ifdef INET6
00792 case AF_INET6:
00793 #endif
00794 switch (level) {
00795 # if defined(IPPROTO_IP)
00796 case IPPROTO_IP:
00797 switch (optname) {
00798 # if defined(IP_MULTICAST_IF) && defined(HAVE_TYPE_STRUCT_IP_MREQN)
00799 case IP_MULTICAST_IF: inspected = inspect_ipv4_multicast_if(level, optname, data, ret); break;
00800 # endif
00801 # if defined(IP_ADD_MEMBERSHIP)
00802 case IP_ADD_MEMBERSHIP: inspected = inspect_ipv4_add_drop_membership(level, optname, data, ret); break;
00803 # endif
00804 # if defined(IP_DROP_MEMBERSHIP)
00805 case IP_DROP_MEMBERSHIP: inspected = inspect_ipv4_add_drop_membership(level, optname, data, ret); break;
00806 # endif
00807 }
00808 break;
00809 # endif
00810
00811 # if defined(IPPROTO_IPV6)
00812 case IPPROTO_IPV6:
00813 switch (optname) {
00814 # if defined(IPV6_MULTICAST_HOPS)
00815 case IPV6_MULTICAST_HOPS: inspected = inspect_int(level, optname, data, ret); break;
00816 # endif
00817 # if defined(IPV6_MULTICAST_IF)
00818 case IPV6_MULTICAST_IF: inspected = inspect_ipv6_multicast_if(level, optname, data, ret); break;
00819 # endif
00820 # if defined(IPV6_MULTICAST_LOOP)
00821 case IPV6_MULTICAST_LOOP: inspected = inspect_uint(level, optname, data, ret); break;
00822 # endif
00823 # if defined(IPV6_JOIN_GROUP)
00824 case IPV6_JOIN_GROUP: inspected = inspect_ipv6_mreq(level, optname, data, ret); break;
00825 # endif
00826 # if defined(IPV6_LEAVE_GROUP)
00827 case IPV6_LEAVE_GROUP: inspected = inspect_ipv6_mreq(level, optname, data, ret); break;
00828 # endif
00829 # if defined(IPV6_UNICAST_HOPS)
00830 case IPV6_UNICAST_HOPS: inspected = inspect_int(level, optname, data, ret); break;
00831 # endif
00832 # if defined(IPV6_V6ONLY)
00833 case IPV6_V6ONLY: inspected = inspect_int(level, optname, data, ret); break;
00834 # endif
00835 }
00836 break;
00837 # endif
00838
00839 # if defined(IPPROTO_TCP)
00840 case IPPROTO_TCP:
00841 switch (optname) {
00842 # if defined(TCP_NODELAY)
00843 case TCP_NODELAY: inspected = inspect_int(level, optname, data, ret); break;
00844 # endif
00845 }
00846 break;
00847 # endif
00848 }
00849 break;
00850
00851 #ifdef HAVE_SYS_UN_H
00852 case AF_UNIX:
00853 switch (level) {
00854 case 0:
00855 switch (optname) {
00856 # if defined(LOCAL_PEERCRED)
00857 case LOCAL_PEERCRED: inspected = inspect_local_peercred(level, optname, data, ret); break;
00858 # endif
00859 }
00860 break;
00861 }
00862 break;
00863 #endif
00864 }
00865
00866 if (!inspected) {
00867 rb_str_cat2(ret, " ");
00868 rb_str_append(ret, rb_str_dump(data));
00869 }
00870
00871 rb_str_cat2(ret, ">");
00872
00873 return ret;
00874 }
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886 static VALUE
00887 sockopt_unpack(VALUE self, VALUE template)
00888 {
00889 return rb_funcall(sockopt_data(self), rb_intern("unpack"), 1, template);
00890 }
00891
00892 void
00893 rsock_init_sockopt(void)
00894 {
00895
00896
00897
00898
00899
00900
00901
00902
00903 rb_cSockOpt = rb_define_class_under(rb_cSocket, "Option", rb_cObject);
00904 rb_define_method(rb_cSockOpt, "initialize", sockopt_initialize, 4);
00905 rb_define_method(rb_cSockOpt, "family", sockopt_family_m, 0);
00906 rb_define_method(rb_cSockOpt, "level", sockopt_level_m, 0);
00907 rb_define_method(rb_cSockOpt, "optname", sockopt_optname_m, 0);
00908 rb_define_method(rb_cSockOpt, "data", sockopt_data, 0);
00909 rb_define_method(rb_cSockOpt, "inspect", sockopt_inspect, 0);
00910
00911 rb_define_singleton_method(rb_cSockOpt, "int", sockopt_s_int, 4);
00912 rb_define_method(rb_cSockOpt, "int", sockopt_int, 0);
00913
00914 rb_define_singleton_method(rb_cSockOpt, "bool", sockopt_s_bool, 4);
00915 rb_define_method(rb_cSockOpt, "bool", sockopt_bool, 0);
00916
00917 rb_define_singleton_method(rb_cSockOpt, "linger", sockopt_s_linger, 2);
00918 rb_define_method(rb_cSockOpt, "linger", sockopt_linger, 0);
00919
00920 rb_define_method(rb_cSockOpt, "unpack", sockopt_unpack, 1);
00921
00922 rb_define_method(rb_cSockOpt, "to_s", sockopt_data, 0);
00923 }
00924
00925