00001 #include "rubysocket.h"
00002
00003 #include <time.h>
00004
00005 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
00006 static VALUE rb_cAncillaryData;
00007
00008 static VALUE
00009 constant_to_sym(int constant, ID (*intern_const)(int))
00010 {
00011 ID name = intern_const(constant);
00012 if (name) {
00013 return ID2SYM(name);
00014 }
00015
00016 return INT2NUM(constant);
00017 }
00018
00019 static VALUE
00020 ip_cmsg_type_to_sym(int level, int cmsg_type)
00021 {
00022 switch (level) {
00023 case SOL_SOCKET:
00024 return constant_to_sym(cmsg_type, rsock_intern_scm_optname);
00025 case IPPROTO_IP:
00026 return constant_to_sym(cmsg_type, rsock_intern_ip_optname);
00027 #ifdef IPPROTO_IPV6
00028 case IPPROTO_IPV6:
00029 return constant_to_sym(cmsg_type, rsock_intern_ipv6_optname);
00030 #endif
00031 case IPPROTO_TCP:
00032 return constant_to_sym(cmsg_type, rsock_intern_tcp_optname);
00033 case IPPROTO_UDP:
00034 return constant_to_sym(cmsg_type, rsock_intern_udp_optname);
00035 default:
00036 return INT2NUM(cmsg_type);
00037 }
00038 }
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072 static VALUE
00073 ancillary_initialize(VALUE self, VALUE vfamily, VALUE vlevel, VALUE vtype, VALUE data)
00074 {
00075 int family = rsock_family_arg(vfamily);
00076 int level = rsock_level_arg(family, vlevel);
00077 int type = rsock_cmsg_type_arg(family, level, vtype);
00078 StringValue(data);
00079 rb_ivar_set(self, rb_intern("family"), INT2NUM(family));
00080 rb_ivar_set(self, rb_intern("level"), INT2NUM(level));
00081 rb_ivar_set(self, rb_intern("type"), INT2NUM(type));
00082 rb_ivar_set(self, rb_intern("data"), data);
00083 return self;
00084 }
00085
00086 static VALUE
00087 ancdata_new(int family, int level, int type, VALUE data)
00088 {
00089 NEWOBJ_OF(obj, struct RObject, rb_cAncillaryData, T_OBJECT);
00090 StringValue(data);
00091 ancillary_initialize((VALUE)obj, INT2NUM(family), INT2NUM(level), INT2NUM(type), data);
00092 return (VALUE)obj;
00093 }
00094
00095 static int
00096 ancillary_family(VALUE self)
00097 {
00098 VALUE v = rb_attr_get(self, rb_intern("family"));
00099 return NUM2INT(v);
00100 }
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111 static VALUE
00112 ancillary_family_m(VALUE self)
00113 {
00114 return INT2NUM(ancillary_family(self));
00115 }
00116
00117 static int
00118 ancillary_level(VALUE self)
00119 {
00120 VALUE v = rb_attr_get(self, rb_intern("level"));
00121 return NUM2INT(v);
00122 }
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133 static VALUE
00134 ancillary_level_m(VALUE self)
00135 {
00136 return INT2NUM(ancillary_level(self));
00137 }
00138
00139 static int
00140 ancillary_type(VALUE self)
00141 {
00142 VALUE v = rb_attr_get(self, rb_intern("type"));
00143 return NUM2INT(v);
00144 }
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155 static VALUE
00156 ancillary_type_m(VALUE self)
00157 {
00158 return INT2NUM(ancillary_type(self));
00159 }
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170 static VALUE
00171 ancillary_data(VALUE self)
00172 {
00173 VALUE v = rb_attr_get(self, rb_intern("data"));
00174 StringValue(v);
00175 return v;
00176 }
00177
00178 #ifdef SCM_RIGHTS
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188 static VALUE
00189 ancillary_s_unix_rights(int argc, VALUE *argv, VALUE klass)
00190 {
00191 VALUE result, str, ary;
00192 int i;
00193
00194 ary = rb_ary_new();
00195
00196 for (i = 0 ; i < argc; i++) {
00197 VALUE obj = argv[i];
00198 if (!RB_TYPE_P(obj, T_FILE)) {
00199 rb_raise(rb_eTypeError, "IO expected");
00200 }
00201 rb_ary_push(ary, obj);
00202 }
00203
00204 str = rb_str_buf_new(sizeof(int) * argc);
00205
00206 for (i = 0 ; i < argc; i++) {
00207 VALUE obj = RARRAY_PTR(ary)[i];
00208 rb_io_t *fptr;
00209 int fd;
00210 GetOpenFile(obj, fptr);
00211 fd = fptr->fd;
00212 rb_str_buf_cat(str, (char *)&fd, sizeof(int));
00213 }
00214
00215 result = ancdata_new(AF_UNIX, SOL_SOCKET, SCM_RIGHTS, str);
00216 rb_ivar_set(result, rb_intern("unix_rights"), ary);
00217 return result;
00218 }
00219 #else
00220 #define ancillary_s_unix_rights rb_f_notimplement
00221 #endif
00222
00223 #ifdef SCM_RIGHTS
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254 static VALUE
00255 ancillary_unix_rights(VALUE self)
00256 {
00257 int level, type;
00258
00259 level = ancillary_level(self);
00260 type = ancillary_type(self);
00261
00262 if (level != SOL_SOCKET || type != SCM_RIGHTS)
00263 rb_raise(rb_eTypeError, "SCM_RIGHTS ancillary data expected");
00264
00265 return rb_attr_get(self, rb_intern("unix_rights"));
00266 }
00267 #else
00268 #define ancillary_unix_rights rb_f_notimplement
00269 #endif
00270
00271 #if defined(SCM_TIMESTAMP) || defined(SCM_TIMESTAMPNS) || defined(SCM_BINTIME)
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297 static VALUE
00298 ancillary_timestamp(VALUE self)
00299 {
00300 int level, type;
00301 VALUE data;
00302 VALUE result = Qnil;
00303
00304 level = ancillary_level(self);
00305 type = ancillary_type(self);
00306 data = ancillary_data(self);
00307
00308 # ifdef SCM_TIMESTAMP
00309 if (level == SOL_SOCKET && type == SCM_TIMESTAMP &&
00310 RSTRING_LEN(data) == sizeof(struct timeval)) {
00311 struct timeval tv;
00312 memcpy((char*)&tv, RSTRING_PTR(data), sizeof(tv));
00313 result = rb_time_new(tv.tv_sec, tv.tv_usec);
00314 }
00315 # endif
00316
00317 # ifdef SCM_TIMESTAMPNS
00318 if (level == SOL_SOCKET && type == SCM_TIMESTAMPNS &&
00319 RSTRING_LEN(data) == sizeof(struct timespec)) {
00320 struct timespec ts;
00321 memcpy((char*)&ts, RSTRING_PTR(data), sizeof(ts));
00322 result = rb_time_nano_new(ts.tv_sec, ts.tv_nsec);
00323 }
00324 # endif
00325
00326 #define add(x,y) (rb_funcall((x), '+', 1, (y)))
00327 #define mul(x,y) (rb_funcall((x), '*', 1, (y)))
00328 #define quo(x,y) (rb_funcall((x), rb_intern("quo"), 1, (y)))
00329
00330 # ifdef SCM_BINTIME
00331 if (level == SOL_SOCKET && type == SCM_BINTIME &&
00332 RSTRING_LEN(data) == sizeof(struct bintime)) {
00333 struct bintime bt;
00334 VALUE d, timev;
00335 memcpy((char*)&bt, RSTRING_PTR(data), sizeof(bt));
00336 d = ULL2NUM(0x100000000ULL);
00337 d = mul(d,d);
00338 timev = add(TIMET2NUM(bt.sec), quo(ULL2NUM(bt.frac), d));
00339 result = rb_time_num_new(timev, Qnil);
00340 }
00341 # endif
00342
00343 if (result == Qnil)
00344 rb_raise(rb_eTypeError, "timestamp ancillary data expected");
00345
00346 return result;
00347 }
00348 #else
00349 #define ancillary_timestamp rb_f_notimplement
00350 #endif
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363 static VALUE
00364 ancillary_s_int(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE vtype, VALUE integer)
00365 {
00366 int family = rsock_family_arg(vfamily);
00367 int level = rsock_level_arg(family, vlevel);
00368 int type = rsock_cmsg_type_arg(family, level, vtype);
00369 int i = NUM2INT(integer);
00370 return ancdata_new(family, level, type, rb_str_new((char*)&i, sizeof(i)));
00371 }
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384 static VALUE
00385 ancillary_int(VALUE self)
00386 {
00387 VALUE data;
00388 int i;
00389 data = ancillary_data(self);
00390 if (RSTRING_LEN(data) != sizeof(int))
00391 rb_raise(rb_eTypeError, "size differ. expected as sizeof(int)=%d but %ld", (int)sizeof(int), (long)RSTRING_LEN(data));
00392 memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
00393 return INT2NUM(i);
00394 }
00395
00396 #if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST)
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417 static VALUE
00418 ancillary_s_ip_pktinfo(int argc, VALUE *argv, VALUE self)
00419 {
00420 VALUE v_addr, v_ifindex, v_spec_dst;
00421 unsigned int ifindex;
00422 struct sockaddr_in sa;
00423 struct in_pktinfo pktinfo;
00424
00425 rb_scan_args(argc, argv, "21", &v_addr, &v_ifindex, &v_spec_dst);
00426
00427 SockAddrStringValue(v_addr);
00428 ifindex = NUM2UINT(v_ifindex);
00429 if (NIL_P(v_spec_dst))
00430 v_spec_dst = v_addr;
00431 else
00432 SockAddrStringValue(v_spec_dst);
00433
00434 memset(&pktinfo, 0, sizeof(pktinfo));
00435
00436 memset(&sa, 0, sizeof(sa));
00437 if (RSTRING_LEN(v_addr) != sizeof(sa))
00438 rb_raise(rb_eArgError, "addr size different to AF_INET sockaddr");
00439 memcpy(&sa, RSTRING_PTR(v_addr), sizeof(sa));
00440 if (sa.sin_family != AF_INET)
00441 rb_raise(rb_eArgError, "addr is not AF_INET sockaddr");
00442 memcpy(&pktinfo.ipi_addr, &sa.sin_addr, sizeof(pktinfo.ipi_addr));
00443
00444 pktinfo.ipi_ifindex = ifindex;
00445
00446 memset(&sa, 0, sizeof(sa));
00447 if (RSTRING_LEN(v_spec_dst) != sizeof(sa))
00448 rb_raise(rb_eArgError, "spec_dat size different to AF_INET sockaddr");
00449 memcpy(&sa, RSTRING_PTR(v_spec_dst), sizeof(sa));
00450 if (sa.sin_family != AF_INET)
00451 rb_raise(rb_eArgError, "spec_dst is not AF_INET sockaddr");
00452 memcpy(&pktinfo.ipi_spec_dst, &sa.sin_addr, sizeof(pktinfo.ipi_spec_dst));
00453
00454 return ancdata_new(AF_INET, IPPROTO_IP, IP_PKTINFO, rb_str_new((char *)&pktinfo, sizeof(pktinfo)));
00455 }
00456 #else
00457 #define ancillary_s_ip_pktinfo rb_f_notimplement
00458 #endif
00459
00460 #if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST)
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480 static VALUE
00481 ancillary_ip_pktinfo(VALUE self)
00482 {
00483 int level, type;
00484 VALUE data;
00485 struct in_pktinfo pktinfo;
00486 struct sockaddr_in sa;
00487 VALUE v_spec_dst, v_addr;
00488
00489 level = ancillary_level(self);
00490 type = ancillary_type(self);
00491 data = ancillary_data(self);
00492
00493 if (level != IPPROTO_IP || type != IP_PKTINFO ||
00494 RSTRING_LEN(data) != sizeof(struct in_pktinfo)) {
00495 rb_raise(rb_eTypeError, "IP_PKTINFO ancillary data expected");
00496 }
00497
00498 memcpy(&pktinfo, RSTRING_PTR(data), sizeof(struct in_pktinfo));
00499 memset(&sa, 0, sizeof(sa));
00500
00501 sa.sin_family = AF_INET;
00502 memcpy(&sa.sin_addr, &pktinfo.ipi_addr, sizeof(sa.sin_addr));
00503 v_addr = rsock_addrinfo_new((struct sockaddr *)&sa, sizeof(sa), PF_INET, 0, 0, Qnil, Qnil);
00504
00505 sa.sin_family = AF_INET;
00506 memcpy(&sa.sin_addr, &pktinfo.ipi_spec_dst, sizeof(sa.sin_addr));
00507 v_spec_dst = rsock_addrinfo_new((struct sockaddr *)&sa, sizeof(sa), PF_INET, 0, 0, Qnil, Qnil);
00508
00509 return rb_ary_new3(3, v_addr, UINT2NUM(pktinfo.ipi_ifindex), v_spec_dst);
00510 }
00511 #else
00512 #define ancillary_ip_pktinfo rb_f_notimplement
00513 #endif
00514
00515 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530 static VALUE
00531 ancillary_s_ipv6_pktinfo(VALUE self, VALUE v_addr, VALUE v_ifindex)
00532 {
00533 unsigned int ifindex;
00534 struct sockaddr_in6 sa;
00535 struct in6_pktinfo pktinfo;
00536
00537 SockAddrStringValue(v_addr);
00538 ifindex = NUM2UINT(v_ifindex);
00539
00540 memset(&pktinfo, 0, sizeof(pktinfo));
00541
00542 memset(&sa, 0, sizeof(sa));
00543 if (RSTRING_LEN(v_addr) != sizeof(sa))
00544 rb_raise(rb_eArgError, "addr size different to AF_INET6 sockaddr");
00545 memcpy(&sa, RSTRING_PTR(v_addr), sizeof(sa));
00546 if (sa.sin6_family != AF_INET6)
00547 rb_raise(rb_eArgError, "addr is not AF_INET6 sockaddr");
00548 memcpy(&pktinfo.ipi6_addr, &sa.sin6_addr, sizeof(pktinfo.ipi6_addr));
00549
00550 pktinfo.ipi6_ifindex = ifindex;
00551
00552 return ancdata_new(AF_INET6, IPPROTO_IPV6, IPV6_PKTINFO, rb_str_new((char *)&pktinfo, sizeof(pktinfo)));
00553 }
00554 #else
00555 #define ancillary_s_ipv6_pktinfo rb_f_notimplement
00556 #endif
00557
00558 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)
00559 static void
00560 extract_ipv6_pktinfo(VALUE self, struct in6_pktinfo *pktinfo_ptr, struct sockaddr_in6 *sa_ptr)
00561 {
00562 int level, type;
00563 VALUE data;
00564
00565 level = ancillary_level(self);
00566 type = ancillary_type(self);
00567 data = ancillary_data(self);
00568
00569 if (level != IPPROTO_IPV6 || type != IPV6_PKTINFO ||
00570 RSTRING_LEN(data) != sizeof(struct in6_pktinfo)) {
00571 rb_raise(rb_eTypeError, "IPV6_PKTINFO ancillary data expected");
00572 }
00573
00574 memcpy(pktinfo_ptr, RSTRING_PTR(data), sizeof(*pktinfo_ptr));
00575
00576 INIT_SOCKADDR((struct sockaddr *)sa_ptr, AF_INET6, sizeof(*sa_ptr));
00577 memcpy(&sa_ptr->sin6_addr, &pktinfo_ptr->ipi6_addr, sizeof(sa_ptr->sin6_addr));
00578 if (IN6_IS_ADDR_LINKLOCAL(&sa_ptr->sin6_addr))
00579 sa_ptr->sin6_scope_id = pktinfo_ptr->ipi6_ifindex;
00580 }
00581 #endif
00582
00583 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598 static VALUE
00599 ancillary_ipv6_pktinfo(VALUE self)
00600 {
00601 struct in6_pktinfo pktinfo;
00602 struct sockaddr_in6 sa;
00603 VALUE v_addr;
00604
00605 extract_ipv6_pktinfo(self, &pktinfo, &sa);
00606 v_addr = rsock_addrinfo_new((struct sockaddr *)&sa, (socklen_t)sizeof(sa), PF_INET6, 0, 0, Qnil, Qnil);
00607 return rb_ary_new3(2, v_addr, UINT2NUM(pktinfo.ipi6_ifindex));
00608 }
00609 #else
00610 #define ancillary_ipv6_pktinfo rb_f_notimplement
00611 #endif
00612
00613 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628 static VALUE
00629 ancillary_ipv6_pktinfo_addr(VALUE self)
00630 {
00631 struct in6_pktinfo pktinfo;
00632 struct sockaddr_in6 sa;
00633 extract_ipv6_pktinfo(self, &pktinfo, &sa);
00634 return rsock_addrinfo_new((struct sockaddr *)&sa, (socklen_t)sizeof(sa), PF_INET6, 0, 0, Qnil, Qnil);
00635 }
00636 #else
00637 #define ancillary_ipv6_pktinfo_addr rb_f_notimplement
00638 #endif
00639
00640 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655 static VALUE
00656 ancillary_ipv6_pktinfo_ifindex(VALUE self)
00657 {
00658 struct in6_pktinfo pktinfo;
00659 struct sockaddr_in6 sa;
00660 extract_ipv6_pktinfo(self, &pktinfo, &sa);
00661 return UINT2NUM(pktinfo.ipi6_ifindex);
00662 }
00663 #else
00664 #define ancillary_ipv6_pktinfo_ifindex rb_f_notimplement
00665 #endif
00666
00667 #if defined(SOL_SOCKET) && defined(SCM_RIGHTS)
00668 static int
00669 anc_inspect_socket_rights(int level, int type, VALUE data, VALUE ret)
00670 {
00671 if (level == SOL_SOCKET && type == SCM_RIGHTS &&
00672 0 < RSTRING_LEN(data) && (RSTRING_LEN(data) % sizeof(int) == 0)) {
00673 long off;
00674 for (off = 0; off < RSTRING_LEN(data); off += sizeof(int)) {
00675 int fd;
00676 memcpy((char*)&fd, RSTRING_PTR(data)+off, sizeof(int));
00677 rb_str_catf(ret, " %d", fd);
00678 }
00679 return 1;
00680 }
00681 else {
00682 return 0;
00683 }
00684 }
00685 #endif
00686
00687 #if defined(SCM_CREDENTIALS)
00688 static int
00689 anc_inspect_passcred_credentials(int level, int type, VALUE data, VALUE ret)
00690 {
00691 if (level == SOL_SOCKET && type == SCM_CREDENTIALS &&
00692 RSTRING_LEN(data) == sizeof(struct ucred)) {
00693 struct ucred cred;
00694 memcpy(&cred, RSTRING_PTR(data), sizeof(struct ucred));
00695 rb_str_catf(ret, " pid=%u uid=%u gid=%u", cred.pid, cred.uid, cred.gid);
00696 rb_str_cat2(ret, " (ucred)");
00697 return 1;
00698 }
00699 else {
00700 return 0;
00701 }
00702 }
00703 #endif
00704
00705 #if defined(SCM_CREDS)
00706 #define INSPECT_SCM_CREDS
00707 static int
00708 anc_inspect_socket_creds(int level, int type, VALUE data, VALUE ret)
00709 {
00710 if (level != SOL_SOCKET && type != SCM_CREDS)
00711 return 0;
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724 #if defined(HAVE_TYPE_STRUCT_CMSGCRED)
00725 if (RSTRING_LEN(data) == sizeof(struct cmsgcred)) {
00726 struct cmsgcred cred;
00727 memcpy(&cred, RSTRING_PTR(data), sizeof(struct cmsgcred));
00728 rb_str_catf(ret, " pid=%u", cred.cmcred_pid);
00729 rb_str_catf(ret, " uid=%u", cred.cmcred_uid);
00730 rb_str_catf(ret, " euid=%u", cred.cmcred_euid);
00731 rb_str_catf(ret, " gid=%u", cred.cmcred_gid);
00732 if (cred.cmcred_ngroups) {
00733 int i;
00734 const char *sep = " groups=";
00735 for (i = 0; i < cred.cmcred_ngroups; i++) {
00736 rb_str_catf(ret, "%s%u", sep, cred.cmcred_groups[i]);
00737 sep = ",";
00738 }
00739 }
00740 rb_str_cat2(ret, " (cmsgcred)");
00741 return 1;
00742 }
00743 #endif
00744 #if defined(HAVE_TYPE_STRUCT_SOCKCRED)
00745 if ((size_t)RSTRING_LEN(data) >= SOCKCREDSIZE(0)) {
00746 struct sockcred cred0, *cred;
00747 memcpy(&cred0, RSTRING_PTR(data), SOCKCREDSIZE(0));
00748 if ((size_t)RSTRING_LEN(data) == SOCKCREDSIZE(cred0.sc_ngroups)) {
00749 cred = (struct sockcred *)ALLOCA_N(char, SOCKCREDSIZE(cred0.sc_ngroups));
00750 memcpy(cred, RSTRING_PTR(data), SOCKCREDSIZE(cred0.sc_ngroups));
00751 rb_str_catf(ret, " uid=%u", cred->sc_uid);
00752 rb_str_catf(ret, " euid=%u", cred->sc_euid);
00753 rb_str_catf(ret, " gid=%u", cred->sc_gid);
00754 rb_str_catf(ret, " egid=%u", cred->sc_egid);
00755 if (cred0.sc_ngroups) {
00756 int i;
00757 const char *sep = " groups=";
00758 for (i = 0; i < cred0.sc_ngroups; i++) {
00759 rb_str_catf(ret, "%s%u", sep, cred->sc_groups[i]);
00760 sep = ",";
00761 }
00762 }
00763 rb_str_cat2(ret, " (sockcred)");
00764 return 1;
00765 }
00766 }
00767 #endif
00768 return 0;
00769 }
00770 #endif
00771
00772 #if defined(IPPROTO_IP) && defined(IP_RECVDSTADDR)
00773 static int
00774 anc_inspect_ip_recvdstaddr(int level, int type, VALUE data, VALUE ret)
00775 {
00776 if (level == IPPROTO_IP && type == IP_RECVDSTADDR &&
00777 RSTRING_LEN(data) == sizeof(struct in_addr)) {
00778 struct in_addr addr;
00779 char addrbuf[INET_ADDRSTRLEN];
00780 memcpy(&addr, RSTRING_PTR(data), sizeof(addr));
00781 if (inet_ntop(AF_INET, &addr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
00782 rb_str_cat2(ret, " invalid-address");
00783 else
00784 rb_str_catf(ret, " %s", addrbuf);
00785 return 1;
00786 }
00787 else {
00788 return 0;
00789 }
00790 }
00791 #endif
00792
00793 #if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST)
00794 static int
00795 anc_inspect_ip_pktinfo(int level, int type, VALUE data, VALUE ret)
00796 {
00797 if (level == IPPROTO_IP && type == IP_PKTINFO &&
00798 RSTRING_LEN(data) == sizeof(struct in_pktinfo)) {
00799 struct in_pktinfo pktinfo;
00800 char buf[INET_ADDRSTRLEN > IFNAMSIZ ? INET_ADDRSTRLEN : IFNAMSIZ];
00801 memcpy(&pktinfo, RSTRING_PTR(data), sizeof(pktinfo));
00802 if (inet_ntop(AF_INET, &pktinfo.ipi_addr, buf, sizeof(buf)) == NULL)
00803 rb_str_cat2(ret, " invalid-address");
00804 else
00805 rb_str_catf(ret, " %s", buf);
00806 if (if_indextoname(pktinfo.ipi_ifindex, buf) == NULL)
00807 rb_str_catf(ret, " ifindex:%d", pktinfo.ipi_ifindex);
00808 else
00809 rb_str_catf(ret, " %s", buf);
00810 if (inet_ntop(AF_INET, &pktinfo.ipi_spec_dst, buf, sizeof(buf)) == NULL)
00811 rb_str_cat2(ret, " spec_dst:invalid-address");
00812 else
00813 rb_str_catf(ret, " spec_dst:%s", buf);
00814 return 1;
00815 }
00816 else {
00817 return 0;
00818 }
00819 }
00820 #endif
00821
00822 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) && defined(HAVE_TYPE_STRUCT_IN6_PKTINFO)
00823 static int
00824 anc_inspect_ipv6_pktinfo(int level, int type, VALUE data, VALUE ret)
00825 {
00826 if (level == IPPROTO_IPV6 && type == IPV6_PKTINFO &&
00827 RSTRING_LEN(data) == sizeof(struct in6_pktinfo)) {
00828 struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)RSTRING_PTR(data);
00829 struct in6_addr addr;
00830 unsigned int ifindex;
00831 char addrbuf[INET6_ADDRSTRLEN], ifbuf[IFNAMSIZ];
00832 memcpy(&addr, &pktinfo->ipi6_addr, sizeof(addr));
00833 memcpy(&ifindex, &pktinfo->ipi6_ifindex, sizeof(ifindex));
00834 if (inet_ntop(AF_INET6, &addr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
00835 rb_str_cat2(ret, " invalid-address");
00836 else
00837 rb_str_catf(ret, " %s", addrbuf);
00838 if (if_indextoname(ifindex, ifbuf) == NULL)
00839 rb_str_catf(ret, " ifindex:%d", ifindex);
00840 else
00841 rb_str_catf(ret, " %s", ifbuf);
00842 return 1;
00843 }
00844 else {
00845 return 0;
00846 }
00847 }
00848 #endif
00849
00850 #if defined(SCM_TIMESTAMP)
00851 static int
00852 inspect_timeval_as_abstime(int level, int optname, VALUE data, VALUE ret)
00853 {
00854 if (RSTRING_LEN(data) == sizeof(struct timeval)) {
00855 struct timeval tv;
00856 time_t time;
00857 struct tm tm;
00858 char buf[32];
00859 memcpy((char*)&tv, RSTRING_PTR(data), sizeof(tv));
00860 time = tv.tv_sec;
00861 tm = *localtime(&time);
00862 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
00863 rb_str_catf(ret, " %s.%06ld", buf, (long)tv.tv_usec);
00864 return 1;
00865 }
00866 else {
00867 return 0;
00868 }
00869 }
00870 #endif
00871
00872 #if defined(SCM_TIMESTAMPNS)
00873 static int
00874 inspect_timespec_as_abstime(int level, int optname, VALUE data, VALUE ret)
00875 {
00876 if (RSTRING_LEN(data) == sizeof(struct timespec)) {
00877 struct timespec ts;
00878 struct tm tm;
00879 char buf[32];
00880 memcpy((char*)&ts, RSTRING_PTR(data), sizeof(ts));
00881 tm = *localtime(&ts.tv_sec);
00882 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
00883 rb_str_catf(ret, " %s.%09ld", buf, (long)ts.tv_nsec);
00884 return 1;
00885 }
00886 else {
00887 return 0;
00888 }
00889 }
00890 #endif
00891
00892 #if defined(SCM_BINTIME)
00893 static int
00894 inspect_bintime_as_abstime(int level, int optname, VALUE data, VALUE ret)
00895 {
00896 if (RSTRING_LEN(data) == sizeof(struct bintime)) {
00897 struct bintime bt;
00898 struct tm tm;
00899 uint64_t frac_h, frac_l;
00900 uint64_t scale_h, scale_l;
00901 uint64_t tmp1, tmp2;
00902 uint64_t res_h, res_l;
00903 char buf[32];
00904 memcpy((char*)&bt, RSTRING_PTR(data), sizeof(bt));
00905 tm = *localtime(&bt.sec);
00906 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
00907
00908
00909
00910 frac_h = bt.frac >> 32;
00911 frac_l = bt.frac & 0xffffffff;
00912
00913 scale_h = 0x8ac72304;
00914 scale_l = 0x89e80000;
00915
00916 res_h = frac_h * scale_h;
00917 res_l = frac_l * scale_l;
00918
00919 tmp1 = frac_h * scale_l;
00920 res_h += tmp1 >> 32;
00921 tmp2 = res_l;
00922 res_l += tmp1 & 0xffffffff;
00923 if (res_l < tmp2) res_h++;
00924
00925 tmp1 = frac_l * scale_h;
00926 res_h += tmp1 >> 32;
00927 tmp2 = res_l;
00928 res_l += tmp1 & 0xffffffff;
00929 if (res_l < tmp2) res_h++;
00930
00931 rb_str_catf(ret, " %s.%019"PRIu64, buf, res_h);
00932 return 1;
00933 }
00934 else {
00935 return 0;
00936 }
00937 }
00938 #endif
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949 static VALUE
00950 ancillary_inspect(VALUE self)
00951 {
00952 VALUE ret;
00953 int family, level, type;
00954 VALUE data;
00955 ID family_id, level_id, type_id;
00956 VALUE vtype;
00957 int inspected;
00958
00959 family = ancillary_family(self);
00960 level = ancillary_level(self);
00961 type = ancillary_type(self);
00962 data = ancillary_data(self);
00963
00964 ret = rb_sprintf("#<%s:", rb_obj_classname(self));
00965
00966 family_id = rsock_intern_family_noprefix(family);
00967 if (family_id)
00968 rb_str_catf(ret, " %s", rb_id2name(family_id));
00969 else
00970 rb_str_catf(ret, " family:%d", family);
00971
00972 if (level == SOL_SOCKET) {
00973 rb_str_cat2(ret, " SOCKET");
00974
00975 type_id = rsock_intern_scm_optname(type);
00976 if (type_id)
00977 rb_str_catf(ret, " %s", rb_id2name(type_id));
00978 else
00979 rb_str_catf(ret, " cmsg_type:%d", type);
00980 }
00981 else if (IS_IP_FAMILY(family)) {
00982 level_id = rsock_intern_iplevel(level);
00983 if (level_id)
00984 rb_str_catf(ret, " %s", rb_id2name(level_id));
00985 else
00986 rb_str_catf(ret, " cmsg_level:%d", level);
00987
00988 vtype = ip_cmsg_type_to_sym(level, type);
00989 if (SYMBOL_P(vtype))
00990 rb_str_catf(ret, " %s", rb_id2name(SYM2ID(vtype)));
00991 else
00992 rb_str_catf(ret, " cmsg_type:%d", type);
00993 }
00994 else {
00995 rb_str_catf(ret, " cmsg_level:%d", level);
00996 rb_str_catf(ret, " cmsg_type:%d", type);
00997 }
00998
00999 inspected = 0;
01000
01001 if (level == SOL_SOCKET)
01002 family = AF_UNSPEC;
01003
01004 switch (family) {
01005 case AF_UNSPEC:
01006 switch (level) {
01007 # if defined(SOL_SOCKET)
01008 case SOL_SOCKET:
01009 switch (type) {
01010 # if defined(SCM_TIMESTAMP)
01011 case SCM_TIMESTAMP: inspected = inspect_timeval_as_abstime(level, type, data, ret); break;
01012 # endif
01013 # if defined(SCM_TIMESTAMPNS)
01014 case SCM_TIMESTAMPNS: inspected = inspect_timespec_as_abstime(level, type, data, ret); break;
01015 # endif
01016 # if defined(SCM_BINTIME)
01017 case SCM_BINTIME: inspected = inspect_bintime_as_abstime(level, type, data, ret); break;
01018 # endif
01019 # if defined(SCM_RIGHTS)
01020 case SCM_RIGHTS: inspected = anc_inspect_socket_rights(level, type, data, ret); break;
01021 # endif
01022 # if defined(SCM_CREDENTIALS)
01023 case SCM_CREDENTIALS: inspected = anc_inspect_passcred_credentials(level, type, data, ret); break;
01024 # endif
01025 # if defined(INSPECT_SCM_CREDS)
01026 case SCM_CREDS: inspected = anc_inspect_socket_creds(level, type, data, ret); break;
01027 # endif
01028 }
01029 break;
01030 # endif
01031 }
01032 break;
01033
01034 case AF_INET:
01035 #ifdef INET6
01036 case AF_INET6:
01037 #endif
01038 switch (level) {
01039 # if defined(IPPROTO_IP)
01040 case IPPROTO_IP:
01041 switch (type) {
01042 # if defined(IP_RECVDSTADDR)
01043 case IP_RECVDSTADDR: inspected = anc_inspect_ip_recvdstaddr(level, type, data, ret); break;
01044 # endif
01045 # if defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST)
01046 case IP_PKTINFO: inspected = anc_inspect_ip_pktinfo(level, type, data, ret); break;
01047 # endif
01048 }
01049 break;
01050 # endif
01051
01052 # if defined(IPPROTO_IPV6)
01053 case IPPROTO_IPV6:
01054 switch (type) {
01055 # if defined(IPV6_PKTINFO) && defined(HAVE_TYPE_STRUCT_IN6_PKTINFO)
01056 case IPV6_PKTINFO: inspected = anc_inspect_ipv6_pktinfo(level, type, data, ret); break;
01057 # endif
01058 }
01059 break;
01060 # endif
01061 }
01062 break;
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
01086
01087 static VALUE
01088 ancillary_cmsg_is_p(VALUE self, VALUE vlevel, VALUE vtype)
01089 {
01090 int family = ancillary_family(self);
01091 int level = rsock_level_arg(family, vlevel);
01092 int type = rsock_cmsg_type_arg(family, level, vtype);
01093
01094 if (ancillary_level(self) == level &&
01095 ancillary_type(self) == type)
01096 return Qtrue;
01097 else
01098 return Qfalse;
01099 }
01100
01101 #endif
01102
01103 #if defined(HAVE_SENDMSG)
01104 struct sendmsg_args_struct {
01105 int fd;
01106 const struct msghdr *msg;
01107 int flags;
01108 };
01109
01110 static void *
01111 nogvl_sendmsg_func(void *ptr)
01112 {
01113 struct sendmsg_args_struct *args = ptr;
01114 return (void *)(VALUE)sendmsg(args->fd, args->msg, args->flags);
01115 }
01116
01117 static ssize_t
01118 rb_sendmsg(int fd, const struct msghdr *msg, int flags)
01119 {
01120 struct sendmsg_args_struct args;
01121 args.fd = fd;
01122 args.msg = msg;
01123 args.flags = flags;
01124 return (ssize_t)rb_thread_call_without_gvl(nogvl_sendmsg_func, &args, RUBY_UBF_IO, 0);
01125 }
01126
01127 static VALUE
01128 bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
01129 {
01130 rb_io_t *fptr;
01131 VALUE data, vflags, dest_sockaddr;
01132 int controls_num;
01133 struct msghdr mh;
01134 struct iovec iov;
01135 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01136 volatile VALUE controls_str = 0;
01137 VALUE *controls_ptr = NULL;
01138 int family;
01139 #endif
01140 int flags;
01141 ssize_t ss;
01142
01143 GetOpenFile(sock, fptr);
01144 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01145 family = rsock_getfamily(fptr->fd);
01146 #endif
01147
01148 data = vflags = dest_sockaddr = Qnil;
01149
01150 if (argc == 0)
01151 rb_raise(rb_eArgError, "mesg argument required");
01152 data = argv[0];
01153 if (1 < argc) vflags = argv[1];
01154 if (2 < argc) dest_sockaddr = argv[2];
01155 controls_num = 3 < argc ? argc - 3 : 0;
01156 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01157 if (3 < argc) { controls_ptr = &argv[3]; }
01158 #endif
01159
01160 StringValue(data);
01161
01162 if (controls_num) {
01163 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01164 int i;
01165 size_t last_pad = 0;
01166 #if defined(__NetBSD__)
01167 int last_level = 0;
01168 int last_type = 0;
01169 #endif
01170 controls_str = rb_str_tmp_new(0);
01171 for (i = 0; i < controls_num; i++) {
01172 VALUE elt = controls_ptr[i], v;
01173 VALUE vlevel, vtype;
01174 int level, type;
01175 VALUE cdata;
01176 long oldlen;
01177 struct cmsghdr cmh;
01178 char *cmsg;
01179 size_t cspace;
01180 v = rb_check_convert_type(elt, T_ARRAY, "Array", "to_ary");
01181 if (!NIL_P(v)) {
01182 elt = v;
01183 if (RARRAY_LEN(elt) != 3)
01184 rb_raise(rb_eArgError, "an element of controls should be 3-elements array");
01185 vlevel = rb_ary_entry(elt, 0);
01186 vtype = rb_ary_entry(elt, 1);
01187 cdata = rb_ary_entry(elt, 2);
01188 }
01189 else {
01190 vlevel = rb_funcall(elt, rb_intern("level"), 0);
01191 vtype = rb_funcall(elt, rb_intern("type"), 0);
01192 cdata = rb_funcall(elt, rb_intern("data"), 0);
01193 }
01194 level = rsock_level_arg(family, vlevel);
01195 type = rsock_cmsg_type_arg(family, level, vtype);
01196 StringValue(cdata);
01197 oldlen = RSTRING_LEN(controls_str);
01198 cspace = CMSG_SPACE(RSTRING_LEN(cdata));
01199 rb_str_resize(controls_str, oldlen + cspace);
01200 cmsg = RSTRING_PTR(controls_str)+oldlen;
01201 memset((char *)cmsg, 0, cspace);
01202 memset((char *)&cmh, 0, sizeof(cmh));
01203 cmh.cmsg_level = level;
01204 cmh.cmsg_type = type;
01205 cmh.cmsg_len = (socklen_t)CMSG_LEN(RSTRING_LEN(cdata));
01206 MEMCPY(cmsg, &cmh, char, sizeof(cmh));
01207 MEMCPY(cmsg+((char*)CMSG_DATA(&cmh)-(char*)&cmh), RSTRING_PTR(cdata), char, RSTRING_LEN(cdata));
01208 #if defined(__NetBSD__)
01209 last_level = cmh.cmsg_level;
01210 last_type = cmh.cmsg_type;
01211 #endif
01212 last_pad = cspace - cmh.cmsg_len;
01213 }
01214 if (last_pad) {
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235 #if defined(__NetBSD__)
01236 if (last_level == SOL_SOCKET && last_type == SCM_RIGHTS)
01237 rb_str_set_len(controls_str, RSTRING_LEN(controls_str)-last_pad);
01238 #endif
01239 }
01240 #else
01241 rb_raise(rb_eNotImpError, "control message for sendmsg is unimplemented");
01242 #endif
01243 }
01244
01245 flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
01246 #ifdef MSG_DONTWAIT
01247 if (nonblock)
01248 flags |= MSG_DONTWAIT;
01249 #endif
01250
01251 if (!NIL_P(dest_sockaddr))
01252 SockAddrStringValue(dest_sockaddr);
01253
01254 rb_io_check_closed(fptr);
01255
01256 retry:
01257 memset(&mh, 0, sizeof(mh));
01258 if (!NIL_P(dest_sockaddr)) {
01259 mh.msg_name = RSTRING_PTR(dest_sockaddr);
01260 mh.msg_namelen = RSTRING_SOCKLEN(dest_sockaddr);
01261 }
01262 mh.msg_iovlen = 1;
01263 mh.msg_iov = &iov;
01264 iov.iov_base = RSTRING_PTR(data);
01265 iov.iov_len = RSTRING_LEN(data);
01266 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01267 if (controls_str) {
01268 mh.msg_control = RSTRING_PTR(controls_str);
01269 mh.msg_controllen = RSTRING_SOCKLEN(controls_str);
01270 }
01271 else {
01272 mh.msg_control = NULL;
01273 mh.msg_controllen = 0;
01274 }
01275 #endif
01276
01277 rb_io_check_closed(fptr);
01278 if (nonblock)
01279 rb_io_set_nonblock(fptr);
01280
01281 ss = rb_sendmsg(fptr->fd, &mh, flags);
01282
01283 if (ss == -1) {
01284 if (!nonblock && rb_io_wait_writable(fptr->fd)) {
01285 rb_io_check_closed(fptr);
01286 goto retry;
01287 }
01288 if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
01289 rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, "sendmsg(2) would block");
01290 rb_sys_fail("sendmsg(2)");
01291 }
01292
01293 return SSIZET2NUM(ss);
01294 }
01295 #endif
01296
01297 #if defined(HAVE_SENDMSG)
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330 VALUE
01331 rsock_bsock_sendmsg(int argc, VALUE *argv, VALUE sock)
01332 {
01333 return bsock_sendmsg_internal(argc, argv, sock, 0);
01334 }
01335 #endif
01336
01337 #if defined(HAVE_SENDMSG)
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349 VALUE
01350 rsock_bsock_sendmsg_nonblock(int argc, VALUE *argv, VALUE sock)
01351 {
01352 return bsock_sendmsg_internal(argc, argv, sock, 1);
01353 }
01354 #endif
01355
01356 #if defined(HAVE_RECVMSG)
01357 struct recvmsg_args_struct {
01358 int fd;
01359 struct msghdr *msg;
01360 int flags;
01361 };
01362
01363 ssize_t
01364 rsock_recvmsg(int socket, struct msghdr *message, int flags)
01365 {
01366 ssize_t ret;
01367 socklen_t len0;
01368 #ifdef MSG_CMSG_CLOEXEC
01369
01370 flags |= MSG_CMSG_CLOEXEC;
01371 #endif
01372 len0 = message->msg_namelen;
01373 ret = recvmsg(socket, message, flags);
01374 if (ret != -1 && len0 < message->msg_namelen)
01375 message->msg_namelen = len0;
01376 return ret;
01377 }
01378
01379 static void *
01380 nogvl_recvmsg_func(void *ptr)
01381 {
01382 struct recvmsg_args_struct *args = ptr;
01383 int flags = args->flags;
01384 return (void *)rsock_recvmsg(args->fd, args->msg, flags);
01385 }
01386
01387 static ssize_t
01388 rb_recvmsg(int fd, struct msghdr *msg, int flags)
01389 {
01390 struct recvmsg_args_struct args;
01391 args.fd = fd;
01392 args.msg = msg;
01393 args.flags = flags;
01394 return (ssize_t)rb_thread_call_without_gvl(nogvl_recvmsg_func, &args, RUBY_UBF_IO, 0);
01395 }
01396
01397 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01398 static void
01399 discard_cmsg(struct cmsghdr *cmh, char *msg_end, int msg_peek_p)
01400 {
01401 # if !defined(FD_PASSING_WORK_WITH_RECVMSG_MSG_PEEK)
01402
01403
01404
01405
01406
01407
01408
01409
01410 if (msg_peek_p)
01411 return;
01412 # endif
01413 if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
01414 int *fdp = (int *)CMSG_DATA(cmh);
01415 int *end = (int *)((char *)cmh + cmh->cmsg_len);
01416 while ((char *)fdp + sizeof(int) <= (char *)end &&
01417 (char *)fdp + sizeof(int) <= msg_end) {
01418 rb_fd_fix_cloexec(*fdp);
01419 close(*fdp);
01420 fdp++;
01421 }
01422 }
01423 }
01424 #endif
01425
01426 void
01427 rsock_discard_cmsg_resource(struct msghdr *mh, int msg_peek_p)
01428 {
01429 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01430 struct cmsghdr *cmh;
01431 char *msg_end;
01432
01433 if (mh->msg_controllen == 0)
01434 return;
01435
01436 msg_end = (char *)mh->msg_control + mh->msg_controllen;
01437
01438 for (cmh = CMSG_FIRSTHDR(mh); cmh != NULL; cmh = CMSG_NXTHDR(mh, cmh)) {
01439 discard_cmsg(cmh, msg_end, msg_peek_p);
01440 }
01441 #endif
01442 }
01443
01444 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01445 static void
01446 make_io_for_unix_rights(VALUE ctl, struct cmsghdr *cmh, char *msg_end)
01447 {
01448 if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
01449 int *fdp, *end;
01450 VALUE ary = rb_ary_new();
01451 rb_ivar_set(ctl, rb_intern("unix_rights"), ary);
01452 fdp = (int *)CMSG_DATA(cmh);
01453 end = (int *)((char *)cmh + cmh->cmsg_len);
01454 while ((char *)fdp + sizeof(int) <= (char *)end &&
01455 (char *)fdp + sizeof(int) <= msg_end) {
01456 int fd = *fdp;
01457 struct stat stbuf;
01458 VALUE io;
01459 if (fstat(fd, &stbuf) == -1)
01460 rb_raise(rb_eSocket, "invalid fd in SCM_RIGHTS");
01461 rb_fd_fix_cloexec(fd);
01462 if (S_ISSOCK(stbuf.st_mode))
01463 io = rsock_init_sock(rb_obj_alloc(rb_cSocket), fd);
01464 else
01465 io = rb_io_fdopen(fd, O_RDWR, NULL);
01466 ary = rb_attr_get(ctl, rb_intern("unix_rights"));
01467 rb_ary_push(ary, io);
01468 fdp++;
01469 }
01470 OBJ_FREEZE(ary);
01471 }
01472 }
01473 #endif
01474
01475 static VALUE
01476 bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
01477 {
01478 rb_io_t *fptr;
01479 VALUE vmaxdatlen, vmaxctllen, vflags;
01480 VALUE vopts;
01481 int grow_buffer;
01482 size_t maxdatlen;
01483 int flags, orig_flags;
01484 struct msghdr mh;
01485 struct iovec iov;
01486 union_sockaddr namebuf;
01487 char datbuf0[4096], *datbuf;
01488 VALUE dat_str = Qnil;
01489 VALUE ret;
01490 ssize_t ss;
01491 int request_scm_rights;
01492 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01493 struct cmsghdr *cmh;
01494 size_t maxctllen;
01495 union {
01496 char bytes[4096];
01497 struct cmsghdr align;
01498 } ctlbuf0;
01499 char *ctlbuf;
01500 VALUE ctl_str = Qnil;
01501 int family;
01502 int gc_done = 0;
01503 #endif
01504
01505
01506 rb_scan_args(argc, argv, "03:", &vmaxdatlen, &vflags, &vmaxctllen, &vopts);
01507
01508 maxdatlen = NIL_P(vmaxdatlen) ? sizeof(datbuf0) : NUM2SIZET(vmaxdatlen);
01509 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01510 maxctllen = NIL_P(vmaxctllen) ? sizeof(ctlbuf0) : NUM2SIZET(vmaxctllen);
01511 #else
01512 if (!NIL_P(vmaxctllen))
01513 rb_raise(rb_eArgError, "control message not supported");
01514 #endif
01515 flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
01516 #ifdef MSG_DONTWAIT
01517 if (nonblock)
01518 flags |= MSG_DONTWAIT;
01519 #endif
01520 orig_flags = flags;
01521
01522 grow_buffer = NIL_P(vmaxdatlen) || NIL_P(vmaxctllen);
01523
01524 request_scm_rights = 0;
01525 if (!NIL_P(vopts) && RTEST(rb_hash_aref(vopts, ID2SYM(rb_intern("scm_rights")))))
01526 request_scm_rights = 1;
01527 #if !defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01528 if (request_scm_rights)
01529 rb_raise(rb_eNotImpError, "control message for recvmsg is unimplemented");
01530 #endif
01531
01532 GetOpenFile(sock, fptr);
01533 if (rb_io_read_pending(fptr)) {
01534 rb_raise(rb_eIOError, "recvmsg for buffered IO");
01535 }
01536
01537 #if !defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01538 if (grow_buffer) {
01539 int socktype;
01540 socklen_t optlen = (socklen_t)sizeof(socktype);
01541 if (getsockopt(fptr->fd, SOL_SOCKET, SO_TYPE, (void*)&socktype, &optlen) == -1) {
01542 rb_sys_fail("getsockopt(SO_TYPE)");
01543 }
01544 if (socktype == SOCK_STREAM)
01545 grow_buffer = 0;
01546 }
01547 #endif
01548
01549 retry:
01550 if (maxdatlen <= sizeof(datbuf0))
01551 datbuf = datbuf0;
01552 else {
01553 if (NIL_P(dat_str))
01554 dat_str = rb_str_tmp_new(maxdatlen);
01555 else
01556 rb_str_resize(dat_str, maxdatlen);
01557 datbuf = RSTRING_PTR(dat_str);
01558 }
01559
01560 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01561 if (maxctllen <= sizeof(ctlbuf0))
01562 ctlbuf = ctlbuf0.bytes;
01563 else {
01564 if (NIL_P(ctl_str))
01565 ctl_str = rb_str_tmp_new(maxctllen);
01566 else
01567 rb_str_resize(ctl_str, maxctllen);
01568 ctlbuf = RSTRING_PTR(ctl_str);
01569 }
01570 #endif
01571
01572 memset(&mh, 0, sizeof(mh));
01573
01574 memset(&namebuf, 0, sizeof(namebuf));
01575 mh.msg_name = &namebuf.addr;
01576 mh.msg_namelen = (socklen_t)sizeof(namebuf);
01577
01578 mh.msg_iov = &iov;
01579 mh.msg_iovlen = 1;
01580 iov.iov_base = datbuf;
01581 iov.iov_len = maxdatlen;
01582
01583 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01584 mh.msg_control = ctlbuf;
01585 mh.msg_controllen = (socklen_t)maxctllen;
01586 #endif
01587
01588 if (grow_buffer)
01589 flags |= MSG_PEEK;
01590
01591 rb_io_check_closed(fptr);
01592 if (nonblock)
01593 rb_io_set_nonblock(fptr);
01594
01595 ss = rb_recvmsg(fptr->fd, &mh, flags);
01596
01597 if (ss == -1) {
01598 if (!nonblock && rb_io_wait_readable(fptr->fd)) {
01599 rb_io_check_closed(fptr);
01600 goto retry;
01601 }
01602 if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
01603 rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "recvmsg(2) would block");
01604 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01605 if (!gc_done && (errno == EMFILE || errno == EMSGSIZE)) {
01606
01607
01608
01609
01610
01611
01612 gc_and_retry:
01613 rb_gc();
01614 gc_done = 1;
01615 goto retry;
01616 }
01617 #endif
01618 rb_sys_fail("recvmsg(2)");
01619 }
01620
01621 if (grow_buffer) {
01622 int grown = 0;
01623 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01624 if (NIL_P(vmaxdatlen) && (mh.msg_flags & MSG_TRUNC)) {
01625 if (SIZE_MAX/2 < maxdatlen)
01626 rb_raise(rb_eArgError, "max data length too big");
01627 maxdatlen *= 2;
01628 grown = 1;
01629 }
01630 if (NIL_P(vmaxctllen) && (mh.msg_flags & MSG_CTRUNC)) {
01631 #define BIG_ENOUGH_SPACE 65536
01632 if (BIG_ENOUGH_SPACE < maxctllen &&
01633 (socklen_t)mh.msg_controllen < (socklen_t)(maxctllen - BIG_ENOUGH_SPACE)) {
01634
01635
01636 if (!gc_done) {
01637 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
01638 goto gc_and_retry;
01639 }
01640 }
01641 else {
01642 if (SIZE_MAX/2 < maxctllen)
01643 rb_raise(rb_eArgError, "max control message length too big");
01644 maxctllen *= 2;
01645 grown = 1;
01646 }
01647 #undef BIG_ENOUGH_SPACE
01648 }
01649 #else
01650 if (NIL_P(vmaxdatlen) && ss != -1 && ss == (ssize_t)iov.iov_len) {
01651 if (SIZE_MAX/2 < maxdatlen)
01652 rb_raise(rb_eArgError, "max data length too big");
01653 maxdatlen *= 2;
01654 grown = 1;
01655 }
01656 #endif
01657 if (grown) {
01658 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
01659 goto retry;
01660 }
01661 else {
01662 grow_buffer = 0;
01663 if (flags != orig_flags) {
01664 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
01665 flags = orig_flags;
01666 goto retry;
01667 }
01668 }
01669 }
01670
01671 if (NIL_P(dat_str))
01672 dat_str = rb_tainted_str_new(datbuf, ss);
01673 else {
01674 rb_str_resize(dat_str, ss);
01675 OBJ_TAINT(dat_str);
01676 rb_obj_reveal(dat_str, rb_cString);
01677 }
01678
01679 ret = rb_ary_new3(3, dat_str,
01680 rsock_io_socket_addrinfo(sock, mh.msg_name, mh.msg_namelen),
01681 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01682 INT2NUM(mh.msg_flags)
01683 #else
01684 Qnil
01685 #endif
01686 );
01687
01688 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01689 family = rsock_getfamily(fptr->fd);
01690 if (mh.msg_controllen) {
01691 char *msg_end = (char *)mh.msg_control + mh.msg_controllen;
01692 for (cmh = CMSG_FIRSTHDR(&mh); cmh != NULL; cmh = CMSG_NXTHDR(&mh, cmh)) {
01693 VALUE ctl;
01694 char *ctl_end;
01695 size_t clen;
01696 if (cmh->cmsg_len == 0) {
01697 rb_raise(rb_eTypeError, "invalid control message (cmsg_len == 0)");
01698 }
01699 ctl_end = (char*)cmh + cmh->cmsg_len;
01700 clen = (ctl_end <= msg_end ? ctl_end : msg_end) - (char*)CMSG_DATA(cmh);
01701 ctl = ancdata_new(family, cmh->cmsg_level, cmh->cmsg_type, rb_tainted_str_new((char*)CMSG_DATA(cmh), clen));
01702 if (request_scm_rights)
01703 make_io_for_unix_rights(ctl, cmh, msg_end);
01704 else
01705 discard_cmsg(cmh, msg_end, (flags & MSG_PEEK) != 0);
01706 rb_ary_push(ret, ctl);
01707 }
01708 }
01709 #endif
01710
01711 return ret;
01712 }
01713 #endif
01714
01715 #if defined(HAVE_RECVMSG)
01716
01717
01718
01719
01720
01721
01722
01723
01724
01725
01726
01727
01728
01729
01730
01731
01732
01733
01734
01735
01736
01737
01738
01739
01740
01741
01742
01743
01744
01745
01746
01747
01748
01749
01750
01751
01752
01753
01754
01755
01756
01757
01758
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769 VALUE
01770 rsock_bsock_recvmsg(int argc, VALUE *argv, VALUE sock)
01771 {
01772 return bsock_recvmsg_internal(argc, argv, sock, 0);
01773 }
01774 #endif
01775
01776 #if defined(HAVE_RECVMSG)
01777
01778
01779
01780
01781
01782
01783
01784
01785
01786
01787
01788 VALUE
01789 rsock_bsock_recvmsg_nonblock(int argc, VALUE *argv, VALUE sock)
01790 {
01791 return bsock_recvmsg_internal(argc, argv, sock, 1);
01792 }
01793 #endif
01794
01795 void
01796 rsock_init_ancdata(void)
01797 {
01798 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01799
01800
01801
01802
01803
01804
01805
01806 rb_cAncillaryData = rb_define_class_under(rb_cSocket, "AncillaryData", rb_cObject);
01807 rb_define_method(rb_cAncillaryData, "initialize", ancillary_initialize, 4);
01808 rb_define_method(rb_cAncillaryData, "inspect", ancillary_inspect, 0);
01809 rb_define_method(rb_cAncillaryData, "family", ancillary_family_m, 0);
01810 rb_define_method(rb_cAncillaryData, "level", ancillary_level_m, 0);
01811 rb_define_method(rb_cAncillaryData, "type", ancillary_type_m, 0);
01812 rb_define_method(rb_cAncillaryData, "data", ancillary_data, 0);
01813
01814 rb_define_method(rb_cAncillaryData, "cmsg_is?", ancillary_cmsg_is_p, 2);
01815
01816 rb_define_singleton_method(rb_cAncillaryData, "int", ancillary_s_int, 4);
01817 rb_define_method(rb_cAncillaryData, "int", ancillary_int, 0);
01818
01819 rb_define_singleton_method(rb_cAncillaryData, "unix_rights", ancillary_s_unix_rights, -1);
01820 rb_define_method(rb_cAncillaryData, "unix_rights", ancillary_unix_rights, 0);
01821
01822 rb_define_method(rb_cAncillaryData, "timestamp", ancillary_timestamp, 0);
01823
01824 rb_define_singleton_method(rb_cAncillaryData, "ip_pktinfo", ancillary_s_ip_pktinfo, -1);
01825 rb_define_method(rb_cAncillaryData, "ip_pktinfo", ancillary_ip_pktinfo, 0);
01826
01827 rb_define_singleton_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_s_ipv6_pktinfo, 2);
01828 rb_define_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_ipv6_pktinfo, 0);
01829 rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_addr", ancillary_ipv6_pktinfo_addr, 0);
01830 rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_ifindex", ancillary_ipv6_pktinfo_ifindex, 0);
01831 #endif
01832 }
01833