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(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
00073
00074
00075
00076
00077
00078
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
00094
00095
00096
00097
00098
00099
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
00115
00116
00117
00118
00119
00120
00121
00122 static VALUE
00123 sockopt_optname_m(VALUE self)
00124 {
00125 return INT2NUM(sockopt_optname(self));
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_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
00168
00169
00170
00171
00172
00173
00174
00175
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
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
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
00216
00217
00218
00219
00220
00221
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
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
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
00266
00267
00268
00269
00270
00271
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)
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)
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
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
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
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)
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)
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)
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)
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)
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)
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)
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)
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
00657
00658
00659
00660
00661
00662
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)
00734 case SO_DEBUG: inspected = inspect_int(level, optname, data, ret); break;
00735 # endif
00736 # if defined(SO_ERROR)
00737 case SO_ERROR: inspected = inspect_errno(level, optname, data, ret); break;
00738 # endif
00739 # if defined(SO_TYPE)
00740 case SO_TYPE: inspected = inspect_socktype(level, optname, data, ret); break;
00741 # endif
00742 # if defined(SO_ACCEPTCONN)
00743 case SO_ACCEPTCONN: inspected = inspect_int(level, optname, data, ret); break;
00744 # endif
00745 # if defined(SO_BROADCAST)
00746 case SO_BROADCAST: inspected = inspect_int(level, optname, data, ret); break;
00747 # endif
00748 # if defined(SO_REUSEADDR)
00749 case SO_REUSEADDR: inspected = inspect_int(level, optname, data, ret); break;
00750 # endif
00751 # if defined(SO_KEEPALIVE)
00752 case SO_KEEPALIVE: inspected = inspect_int(level, optname, data, ret); break;
00753 # endif
00754 # if defined(SO_OOBINLINE)
00755 case SO_OOBINLINE: inspected = inspect_int(level, optname, data, ret); break;
00756 # endif
00757 # if defined(SO_SNDBUF)
00758 case SO_SNDBUF: inspected = inspect_int(level, optname, data, ret); break;
00759 # endif
00760 # if defined(SO_RCVBUF)
00761 case SO_RCVBUF: inspected = inspect_int(level, optname, data, ret); break;
00762 # endif
00763 # if defined(SO_DONTROUTE)
00764 case SO_DONTROUTE: inspected = inspect_int(level, optname, data, ret); break;
00765 # endif
00766 # if defined(SO_RCVLOWAT)
00767 case SO_RCVLOWAT: inspected = inspect_int(level, optname, data, ret); break;
00768 # endif
00769 # if defined(SO_SNDLOWAT)
00770 case SO_SNDLOWAT: inspected = inspect_int(level, optname, data, ret); break;
00771 # endif
00772 # if defined(SO_LINGER)
00773 case SO_LINGER: inspected = inspect_linger(level, optname, data, ret); break;
00774 # endif
00775 # if defined(SO_RCVTIMEO)
00776 case SO_RCVTIMEO: inspected = inspect_timeval_as_interval(level, optname, data, ret); break;
00777 # endif
00778 # if defined(SO_SNDTIMEO)
00779 case SO_SNDTIMEO: inspected = inspect_timeval_as_interval(level, optname, data, ret); break;
00780 # endif
00781 # if defined(SO_PEERCRED)
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)
00798 case IP_MULTICAST_IF: inspected = inspect_ipv4_multicast_if(level, optname, data, ret); break;
00799 # endif
00800 # if defined(IP_ADD_MEMBERSHIP)
00801 case IP_ADD_MEMBERSHIP: inspected = inspect_ipv4_add_drop_membership(level, optname, data, ret); break;
00802 # endif
00803 # if defined(IP_DROP_MEMBERSHIP)
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)
00814 case IPV6_MULTICAST_HOPS: inspected = inspect_int(level, optname, data, ret); break;
00815 # endif
00816 # if defined(IPV6_MULTICAST_IF)
00817 case IPV6_MULTICAST_IF: inspected = inspect_ipv6_multicast_if(level, optname, data, ret); break;
00818 # endif
00819 # if defined(IPV6_MULTICAST_LOOP)
00820 case IPV6_MULTICAST_LOOP: inspected = inspect_uint(level, optname, data, ret); break;
00821 # endif
00822 # if defined(IPV6_JOIN_GROUP)
00823 case IPV6_JOIN_GROUP: inspected = inspect_ipv6_mreq(level, optname, data, ret); break;
00824 # endif
00825 # if defined(IPV6_LEAVE_GROUP)
00826 case IPV6_LEAVE_GROUP: inspected = inspect_ipv6_mreq(level, optname, data, ret); break;
00827 # endif
00828 # if defined(IPV6_UNICAST_HOPS)
00829 case IPV6_UNICAST_HOPS: inspected = inspect_int(level, optname, data, ret); break;
00830 # endif
00831 # if defined(IPV6_V6ONLY)
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)
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
00877
00878
00879
00880
00881
00882
00883
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
00896
00897
00898
00899
00900
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);
00922 }
00923
00924