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 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 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01293 RB_GC_GUARD(controls_str);
01294 #endif
01295
01296 return SSIZET2NUM(ss);
01297 }
01298 #endif
01299
01300 #if defined(HAVE_SENDMSG)
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
01331
01332
01333 VALUE
01334 rsock_bsock_sendmsg(int argc, VALUE *argv, VALUE sock)
01335 {
01336 return bsock_sendmsg_internal(argc, argv, sock, 0);
01337 }
01338 #endif
01339
01340 #if defined(HAVE_SENDMSG)
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352 VALUE
01353 rsock_bsock_sendmsg_nonblock(int argc, VALUE *argv, VALUE sock)
01354 {
01355 return bsock_sendmsg_internal(argc, argv, sock, 1);
01356 }
01357 #endif
01358
01359 #if defined(HAVE_RECVMSG)
01360 struct recvmsg_args_struct {
01361 int fd;
01362 struct msghdr *msg;
01363 int flags;
01364 };
01365
01366 ssize_t
01367 rsock_recvmsg(int socket, struct msghdr *message, int flags)
01368 {
01369 ssize_t ret;
01370 socklen_t len0;
01371 #ifdef MSG_CMSG_CLOEXEC
01372
01373 flags |= MSG_CMSG_CLOEXEC;
01374 #endif
01375 len0 = message->msg_namelen;
01376 ret = recvmsg(socket, message, flags);
01377 if (ret != -1 && len0 < message->msg_namelen)
01378 message->msg_namelen = len0;
01379 return ret;
01380 }
01381
01382 static void *
01383 nogvl_recvmsg_func(void *ptr)
01384 {
01385 struct recvmsg_args_struct *args = ptr;
01386 int flags = args->flags;
01387 return (void *)rsock_recvmsg(args->fd, args->msg, flags);
01388 }
01389
01390 static ssize_t
01391 rb_recvmsg(int fd, struct msghdr *msg, int flags)
01392 {
01393 struct recvmsg_args_struct args;
01394 args.fd = fd;
01395 args.msg = msg;
01396 args.flags = flags;
01397 return (ssize_t)rb_thread_call_without_gvl(nogvl_recvmsg_func, &args, RUBY_UBF_IO, 0);
01398 }
01399
01400 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01401 static void
01402 discard_cmsg(struct cmsghdr *cmh, char *msg_end, int msg_peek_p)
01403 {
01404 # if !defined(FD_PASSING_WORK_WITH_RECVMSG_MSG_PEEK)
01405
01406
01407
01408
01409
01410
01411
01412
01413 if (msg_peek_p)
01414 return;
01415 # endif
01416 if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
01417 int *fdp = (int *)CMSG_DATA(cmh);
01418 int *end = (int *)((char *)cmh + cmh->cmsg_len);
01419 while ((char *)fdp + sizeof(int) <= (char *)end &&
01420 (char *)fdp + sizeof(int) <= msg_end) {
01421 rb_fd_fix_cloexec(*fdp);
01422 close(*fdp);
01423 fdp++;
01424 }
01425 }
01426 }
01427 #endif
01428
01429 void
01430 rsock_discard_cmsg_resource(struct msghdr *mh, int msg_peek_p)
01431 {
01432 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01433 struct cmsghdr *cmh;
01434 char *msg_end;
01435
01436 if (mh->msg_controllen == 0)
01437 return;
01438
01439 msg_end = (char *)mh->msg_control + mh->msg_controllen;
01440
01441 for (cmh = CMSG_FIRSTHDR(mh); cmh != NULL; cmh = CMSG_NXTHDR(mh, cmh)) {
01442 discard_cmsg(cmh, msg_end, msg_peek_p);
01443 }
01444 #endif
01445 }
01446
01447 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01448 static void
01449 make_io_for_unix_rights(VALUE ctl, struct cmsghdr *cmh, char *msg_end)
01450 {
01451 if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
01452 int *fdp, *end;
01453 VALUE ary = rb_ary_new();
01454 rb_ivar_set(ctl, rb_intern("unix_rights"), ary);
01455 fdp = (int *)CMSG_DATA(cmh);
01456 end = (int *)((char *)cmh + cmh->cmsg_len);
01457 while ((char *)fdp + sizeof(int) <= (char *)end &&
01458 (char *)fdp + sizeof(int) <= msg_end) {
01459 int fd = *fdp;
01460 struct stat stbuf;
01461 VALUE io;
01462 if (fstat(fd, &stbuf) == -1)
01463 rb_raise(rb_eSocket, "invalid fd in SCM_RIGHTS");
01464 rb_fd_fix_cloexec(fd);
01465 if (S_ISSOCK(stbuf.st_mode))
01466 io = rsock_init_sock(rb_obj_alloc(rb_cSocket), fd);
01467 else
01468 io = rb_io_fdopen(fd, O_RDWR, NULL);
01469 ary = rb_attr_get(ctl, rb_intern("unix_rights"));
01470 rb_ary_push(ary, io);
01471 fdp++;
01472 }
01473 OBJ_FREEZE(ary);
01474 }
01475 }
01476 #endif
01477
01478 static VALUE
01479 bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
01480 {
01481 rb_io_t *fptr;
01482 VALUE vmaxdatlen, vmaxctllen, vflags;
01483 VALUE vopts;
01484 int grow_buffer;
01485 size_t maxdatlen;
01486 int flags, orig_flags;
01487 struct msghdr mh;
01488 struct iovec iov;
01489 union_sockaddr namebuf;
01490 char datbuf0[4096], *datbuf;
01491 VALUE dat_str = Qnil;
01492 VALUE ret;
01493 ssize_t ss;
01494 int request_scm_rights;
01495 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01496 struct cmsghdr *cmh;
01497 size_t maxctllen;
01498 union {
01499 char bytes[4096];
01500 struct cmsghdr align;
01501 } ctlbuf0;
01502 char *ctlbuf;
01503 VALUE ctl_str = Qnil;
01504 int family;
01505 int gc_done = 0;
01506 #endif
01507
01508
01509 rb_scan_args(argc, argv, "03:", &vmaxdatlen, &vflags, &vmaxctllen, &vopts);
01510
01511 maxdatlen = NIL_P(vmaxdatlen) ? sizeof(datbuf0) : NUM2SIZET(vmaxdatlen);
01512 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01513 maxctllen = NIL_P(vmaxctllen) ? sizeof(ctlbuf0) : NUM2SIZET(vmaxctllen);
01514 #else
01515 if (!NIL_P(vmaxctllen))
01516 rb_raise(rb_eArgError, "control message not supported");
01517 #endif
01518 flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
01519 #ifdef MSG_DONTWAIT
01520 if (nonblock)
01521 flags |= MSG_DONTWAIT;
01522 #endif
01523 orig_flags = flags;
01524
01525 grow_buffer = NIL_P(vmaxdatlen) || NIL_P(vmaxctllen);
01526
01527 request_scm_rights = 0;
01528 if (!NIL_P(vopts) && RTEST(rb_hash_aref(vopts, ID2SYM(rb_intern("scm_rights")))))
01529 request_scm_rights = 1;
01530 #if !defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01531 if (request_scm_rights)
01532 rb_raise(rb_eNotImpError, "control message for recvmsg is unimplemented");
01533 #endif
01534
01535 GetOpenFile(sock, fptr);
01536 if (rb_io_read_pending(fptr)) {
01537 rb_raise(rb_eIOError, "recvmsg for buffered IO");
01538 }
01539
01540 #if !defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01541 if (grow_buffer) {
01542 int socktype;
01543 socklen_t optlen = (socklen_t)sizeof(socktype);
01544 if (getsockopt(fptr->fd, SOL_SOCKET, SO_TYPE, (void*)&socktype, &optlen) == -1) {
01545 rb_sys_fail("getsockopt(SO_TYPE)");
01546 }
01547 if (socktype == SOCK_STREAM)
01548 grow_buffer = 0;
01549 }
01550 #endif
01551
01552 retry:
01553 if (maxdatlen <= sizeof(datbuf0))
01554 datbuf = datbuf0;
01555 else {
01556 if (NIL_P(dat_str))
01557 dat_str = rb_str_tmp_new(maxdatlen);
01558 else
01559 rb_str_resize(dat_str, maxdatlen);
01560 datbuf = RSTRING_PTR(dat_str);
01561 }
01562
01563 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01564 if (maxctllen <= sizeof(ctlbuf0))
01565 ctlbuf = ctlbuf0.bytes;
01566 else {
01567 if (NIL_P(ctl_str))
01568 ctl_str = rb_str_tmp_new(maxctllen);
01569 else
01570 rb_str_resize(ctl_str, maxctllen);
01571 ctlbuf = RSTRING_PTR(ctl_str);
01572 }
01573 #endif
01574
01575 memset(&mh, 0, sizeof(mh));
01576
01577 memset(&namebuf, 0, sizeof(namebuf));
01578 mh.msg_name = &namebuf.addr;
01579 mh.msg_namelen = (socklen_t)sizeof(namebuf);
01580
01581 mh.msg_iov = &iov;
01582 mh.msg_iovlen = 1;
01583 iov.iov_base = datbuf;
01584 iov.iov_len = maxdatlen;
01585
01586 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01587 mh.msg_control = ctlbuf;
01588 mh.msg_controllen = (socklen_t)maxctllen;
01589 #endif
01590
01591 if (grow_buffer)
01592 flags |= MSG_PEEK;
01593
01594 rb_io_check_closed(fptr);
01595 if (nonblock)
01596 rb_io_set_nonblock(fptr);
01597
01598 ss = rb_recvmsg(fptr->fd, &mh, flags);
01599
01600 if (ss == -1) {
01601 if (!nonblock && rb_io_wait_readable(fptr->fd)) {
01602 rb_io_check_closed(fptr);
01603 goto retry;
01604 }
01605 if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
01606 rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "recvmsg(2) would block");
01607 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01608 if (!gc_done && (errno == EMFILE || errno == EMSGSIZE)) {
01609
01610
01611
01612
01613
01614
01615 gc_and_retry:
01616 rb_gc();
01617 gc_done = 1;
01618 goto retry;
01619 }
01620 #endif
01621 rb_sys_fail("recvmsg(2)");
01622 }
01623
01624 if (grow_buffer) {
01625 int grown = 0;
01626 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01627 if (NIL_P(vmaxdatlen) && (mh.msg_flags & MSG_TRUNC)) {
01628 if (SIZE_MAX/2 < maxdatlen)
01629 rb_raise(rb_eArgError, "max data length too big");
01630 maxdatlen *= 2;
01631 grown = 1;
01632 }
01633 if (NIL_P(vmaxctllen) && (mh.msg_flags & MSG_CTRUNC)) {
01634 #define BIG_ENOUGH_SPACE 65536
01635 if (BIG_ENOUGH_SPACE < maxctllen &&
01636 (socklen_t)mh.msg_controllen < (socklen_t)(maxctllen - BIG_ENOUGH_SPACE)) {
01637
01638
01639 if (!gc_done) {
01640 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
01641 goto gc_and_retry;
01642 }
01643 }
01644 else {
01645 if (SIZE_MAX/2 < maxctllen)
01646 rb_raise(rb_eArgError, "max control message length too big");
01647 maxctllen *= 2;
01648 grown = 1;
01649 }
01650 #undef BIG_ENOUGH_SPACE
01651 }
01652 #else
01653 if (NIL_P(vmaxdatlen) && ss != -1 && ss == (ssize_t)iov.iov_len) {
01654 if (SIZE_MAX/2 < maxdatlen)
01655 rb_raise(rb_eArgError, "max data length too big");
01656 maxdatlen *= 2;
01657 grown = 1;
01658 }
01659 #endif
01660 if (grown) {
01661 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
01662 goto retry;
01663 }
01664 else {
01665 grow_buffer = 0;
01666 if (flags != orig_flags) {
01667 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
01668 flags = orig_flags;
01669 goto retry;
01670 }
01671 }
01672 }
01673
01674 if (NIL_P(dat_str))
01675 dat_str = rb_tainted_str_new(datbuf, ss);
01676 else {
01677 rb_str_resize(dat_str, ss);
01678 OBJ_TAINT(dat_str);
01679 rb_obj_reveal(dat_str, rb_cString);
01680 }
01681
01682 ret = rb_ary_new3(3, dat_str,
01683 rsock_io_socket_addrinfo(sock, mh.msg_name, mh.msg_namelen),
01684 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01685 INT2NUM(mh.msg_flags)
01686 #else
01687 Qnil
01688 #endif
01689 );
01690
01691 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01692 family = rsock_getfamily(fptr->fd);
01693 if (mh.msg_controllen) {
01694 char *msg_end = (char *)mh.msg_control + mh.msg_controllen;
01695 for (cmh = CMSG_FIRSTHDR(&mh); cmh != NULL; cmh = CMSG_NXTHDR(&mh, cmh)) {
01696 VALUE ctl;
01697 char *ctl_end;
01698 size_t clen;
01699 if (cmh->cmsg_len == 0) {
01700 rb_raise(rb_eTypeError, "invalid control message (cmsg_len == 0)");
01701 }
01702 ctl_end = (char*)cmh + cmh->cmsg_len;
01703 clen = (ctl_end <= msg_end ? ctl_end : msg_end) - (char*)CMSG_DATA(cmh);
01704 ctl = ancdata_new(family, cmh->cmsg_level, cmh->cmsg_type, rb_tainted_str_new((char*)CMSG_DATA(cmh), clen));
01705 if (request_scm_rights)
01706 make_io_for_unix_rights(ctl, cmh, msg_end);
01707 else
01708 discard_cmsg(cmh, msg_end, (flags & MSG_PEEK) != 0);
01709 rb_ary_push(ret, ctl);
01710 }
01711 RB_GC_GUARD(ctl_str);
01712 }
01713 #endif
01714
01715 return ret;
01716 }
01717 #endif
01718
01719 #if defined(HAVE_RECVMSG)
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
01770
01771
01772
01773 VALUE
01774 rsock_bsock_recvmsg(int argc, VALUE *argv, VALUE sock)
01775 {
01776 return bsock_recvmsg_internal(argc, argv, sock, 0);
01777 }
01778 #endif
01779
01780 #if defined(HAVE_RECVMSG)
01781
01782
01783
01784
01785
01786
01787
01788
01789
01790
01791
01792 VALUE
01793 rsock_bsock_recvmsg_nonblock(int argc, VALUE *argv, VALUE sock)
01794 {
01795 return bsock_recvmsg_internal(argc, argv, sock, 1);
01796 }
01797 #endif
01798
01799 void
01800 rsock_init_ancdata(void)
01801 {
01802 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
01803
01804
01805
01806
01807
01808
01809
01810 rb_cAncillaryData = rb_define_class_under(rb_cSocket, "AncillaryData", rb_cObject);
01811 rb_define_method(rb_cAncillaryData, "initialize", ancillary_initialize, 4);
01812 rb_define_method(rb_cAncillaryData, "inspect", ancillary_inspect, 0);
01813 rb_define_method(rb_cAncillaryData, "family", ancillary_family_m, 0);
01814 rb_define_method(rb_cAncillaryData, "level", ancillary_level_m, 0);
01815 rb_define_method(rb_cAncillaryData, "type", ancillary_type_m, 0);
01816 rb_define_method(rb_cAncillaryData, "data", ancillary_data, 0);
01817
01818 rb_define_method(rb_cAncillaryData, "cmsg_is?", ancillary_cmsg_is_p, 2);
01819
01820 rb_define_singleton_method(rb_cAncillaryData, "int", ancillary_s_int, 4);
01821 rb_define_method(rb_cAncillaryData, "int", ancillary_int, 0);
01822
01823 rb_define_singleton_method(rb_cAncillaryData, "unix_rights", ancillary_s_unix_rights, -1);
01824 rb_define_method(rb_cAncillaryData, "unix_rights", ancillary_unix_rights, 0);
01825
01826 rb_define_method(rb_cAncillaryData, "timestamp", ancillary_timestamp, 0);
01827
01828 rb_define_singleton_method(rb_cAncillaryData, "ip_pktinfo", ancillary_s_ip_pktinfo, -1);
01829 rb_define_method(rb_cAncillaryData, "ip_pktinfo", ancillary_ip_pktinfo, 0);
01830
01831 rb_define_singleton_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_s_ipv6_pktinfo, 2);
01832 rb_define_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_ipv6_pktinfo, 0);
01833 rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_addr", ancillary_ipv6_pktinfo_addr, 0);
01834 rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_ifindex", ancillary_ipv6_pktinfo_ifindex, 0);
01835 #endif
01836 }
01837