00001 #include "rubysocket.h"
00002
00003 #include <time.h>
00004
00005 #if defined(HAVE_ST_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 memset(sa_ptr, 0, sizeof(*sa_ptr));
00577 SET_SA_LEN((struct sockaddr *)sa_ptr, sizeof(struct sockaddr_in6));
00578 sa_ptr->sin6_family = AF_INET6;
00579 memcpy(&sa_ptr->sin6_addr, &pktinfo_ptr->ipi6_addr, sizeof(sa_ptr->sin6_addr));
00580 if (IN6_IS_ADDR_LINKLOCAL(&sa_ptr->sin6_addr))
00581 sa_ptr->sin6_scope_id = pktinfo_ptr->ipi6_ifindex;
00582 }
00583 #endif
00584
00585 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600 static VALUE
00601 ancillary_ipv6_pktinfo(VALUE self)
00602 {
00603 struct in6_pktinfo pktinfo;
00604 struct sockaddr_in6 sa;
00605 VALUE v_addr;
00606
00607 extract_ipv6_pktinfo(self, &pktinfo, &sa);
00608 v_addr = rsock_addrinfo_new((struct sockaddr *)&sa, (socklen_t)sizeof(sa), PF_INET6, 0, 0, Qnil, Qnil);
00609 return rb_ary_new3(2, v_addr, UINT2NUM(pktinfo.ipi6_ifindex));
00610 }
00611 #else
00612 #define ancillary_ipv6_pktinfo rb_f_notimplement
00613 #endif
00614
00615 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630 static VALUE
00631 ancillary_ipv6_pktinfo_addr(VALUE self)
00632 {
00633 struct in6_pktinfo pktinfo;
00634 struct sockaddr_in6 sa;
00635 extract_ipv6_pktinfo(self, &pktinfo, &sa);
00636 return rsock_addrinfo_new((struct sockaddr *)&sa, (socklen_t)sizeof(sa), PF_INET6, 0, 0, Qnil, Qnil);
00637 }
00638 #else
00639 #define ancillary_ipv6_pktinfo_addr rb_f_notimplement
00640 #endif
00641
00642 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657 static VALUE
00658 ancillary_ipv6_pktinfo_ifindex(VALUE self)
00659 {
00660 struct in6_pktinfo pktinfo;
00661 struct sockaddr_in6 sa;
00662 extract_ipv6_pktinfo(self, &pktinfo, &sa);
00663 return UINT2NUM(pktinfo.ipi6_ifindex);
00664 }
00665 #else
00666 #define ancillary_ipv6_pktinfo_ifindex rb_f_notimplement
00667 #endif
00668
00669 #if defined(SOL_SOCKET) && defined(SCM_RIGHTS)
00670 static int
00671 anc_inspect_socket_rights(int level, int type, VALUE data, VALUE ret)
00672 {
00673 if (level == SOL_SOCKET && type == SCM_RIGHTS &&
00674 0 < RSTRING_LEN(data) && (RSTRING_LEN(data) % sizeof(int) == 0)) {
00675 long off;
00676 for (off = 0; off < RSTRING_LEN(data); off += sizeof(int)) {
00677 int fd;
00678 memcpy((char*)&fd, RSTRING_PTR(data)+off, sizeof(int));
00679 rb_str_catf(ret, " %d", fd);
00680 }
00681 return 1;
00682 }
00683 else {
00684 return 0;
00685 }
00686 }
00687 #endif
00688
00689 #if defined(SCM_CREDENTIALS)
00690 static int
00691 anc_inspect_passcred_credentials(int level, int type, VALUE data, VALUE ret)
00692 {
00693 if (level == SOL_SOCKET && type == SCM_CREDENTIALS &&
00694 RSTRING_LEN(data) == sizeof(struct ucred)) {
00695 struct ucred cred;
00696 memcpy(&cred, RSTRING_PTR(data), sizeof(struct ucred));
00697 rb_str_catf(ret, " pid=%u uid=%u gid=%u", cred.pid, cred.uid, cred.gid);
00698 rb_str_cat2(ret, " (ucred)");
00699 return 1;
00700 }
00701 else {
00702 return 0;
00703 }
00704 }
00705 #endif
00706
00707 #if defined(SCM_CREDS)
00708 #define INSPECT_SCM_CREDS
00709 static int
00710 anc_inspect_socket_creds(int level, int type, VALUE data, VALUE ret)
00711 {
00712 if (level != SOL_SOCKET && type != SCM_CREDS)
00713 return 0;
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726 #if defined(HAVE_TYPE_STRUCT_CMSGCRED)
00727 if (RSTRING_LEN(data) == sizeof(struct cmsgcred)) {
00728 struct cmsgcred cred;
00729 memcpy(&cred, RSTRING_PTR(data), sizeof(struct cmsgcred));
00730 rb_str_catf(ret, " pid=%u", cred.cmcred_pid);
00731 rb_str_catf(ret, " uid=%u", cred.cmcred_uid);
00732 rb_str_catf(ret, " euid=%u", cred.cmcred_euid);
00733 rb_str_catf(ret, " gid=%u", cred.cmcred_gid);
00734 if (cred.cmcred_ngroups) {
00735 int i;
00736 const char *sep = " groups=";
00737 for (i = 0; i < cred.cmcred_ngroups; i++) {
00738 rb_str_catf(ret, "%s%u", sep, cred.cmcred_groups[i]);
00739 sep = ",";
00740 }
00741 }
00742 rb_str_cat2(ret, " (cmsgcred)");
00743 return 1;
00744 }
00745 #endif
00746 #if defined(HAVE_TYPE_STRUCT_SOCKCRED)
00747 if ((size_t)RSTRING_LEN(data) >= SOCKCREDSIZE(0)) {
00748 struct sockcred cred0, *cred;
00749 memcpy(&cred0, RSTRING_PTR(data), SOCKCREDSIZE(0));
00750 if ((size_t)RSTRING_LEN(data) == SOCKCREDSIZE(cred0.sc_ngroups)) {
00751 cred = (struct sockcred *)ALLOCA_N(char, SOCKCREDSIZE(cred0.sc_ngroups));
00752 memcpy(cred, RSTRING_PTR(data), SOCKCREDSIZE(cred0.sc_ngroups));
00753 rb_str_catf(ret, " uid=%u", cred->sc_uid);
00754 rb_str_catf(ret, " euid=%u", cred->sc_euid);
00755 rb_str_catf(ret, " gid=%u", cred->sc_gid);
00756 rb_str_catf(ret, " egid=%u", cred->sc_egid);
00757 if (cred0.sc_ngroups) {
00758 int i;
00759 const char *sep = " groups=";
00760 for (i = 0; i < cred0.sc_ngroups; i++) {
00761 rb_str_catf(ret, "%s%u", sep, cred->sc_groups[i]);
00762 sep = ",";
00763 }
00764 }
00765 rb_str_cat2(ret, " (sockcred)");
00766 return 1;
00767 }
00768 }
00769 #endif
00770 return 0;
00771 }
00772 #endif
00773
00774 #if defined(IPPROTO_IP) && defined(IP_RECVDSTADDR)
00775 static int
00776 anc_inspect_ip_recvdstaddr(int level, int type, VALUE data, VALUE ret)
00777 {
00778 if (level == IPPROTO_IP && type == IP_RECVDSTADDR &&
00779 RSTRING_LEN(data) == sizeof(struct in_addr)) {
00780 struct in_addr addr;
00781 char addrbuf[INET_ADDRSTRLEN];
00782 memcpy(&addr, RSTRING_PTR(data), sizeof(addr));
00783 if (inet_ntop(AF_INET, &addr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
00784 rb_str_cat2(ret, " invalid-address");
00785 else
00786 rb_str_catf(ret, " %s", addrbuf);
00787 return 1;
00788 }
00789 else {
00790 return 0;
00791 }
00792 }
00793 #endif
00794
00795 #if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST)
00796 static int
00797 anc_inspect_ip_pktinfo(int level, int type, VALUE data, VALUE ret)
00798 {
00799 if (level == IPPROTO_IP && type == IP_PKTINFO &&
00800 RSTRING_LEN(data) == sizeof(struct in_pktinfo)) {
00801 struct in_pktinfo pktinfo;
00802 char buf[INET_ADDRSTRLEN > IFNAMSIZ ? INET_ADDRSTRLEN : IFNAMSIZ];
00803 memcpy(&pktinfo, RSTRING_PTR(data), sizeof(pktinfo));
00804 if (inet_ntop(AF_INET, &pktinfo.ipi_addr, buf, sizeof(buf)) == NULL)
00805 rb_str_cat2(ret, " invalid-address");
00806 else
00807 rb_str_catf(ret, " %s", buf);
00808 if (if_indextoname(pktinfo.ipi_ifindex, buf) == NULL)
00809 rb_str_catf(ret, " ifindex:%d", pktinfo.ipi_ifindex);
00810 else
00811 rb_str_catf(ret, " %s", buf);
00812 if (inet_ntop(AF_INET, &pktinfo.ipi_spec_dst, buf, sizeof(buf)) == NULL)
00813 rb_str_cat2(ret, " spec_dst:invalid-address");
00814 else
00815 rb_str_catf(ret, " spec_dst:%s", buf);
00816 return 1;
00817 }
00818 else {
00819 return 0;
00820 }
00821 }
00822 #endif
00823
00824 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) && defined(HAVE_TYPE_STRUCT_IN6_PKTINFO)
00825 static int
00826 anc_inspect_ipv6_pktinfo(int level, int type, VALUE data, VALUE ret)
00827 {
00828 if (level == IPPROTO_IPV6 && type == IPV6_PKTINFO &&
00829 RSTRING_LEN(data) == sizeof(struct in6_pktinfo)) {
00830 struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)RSTRING_PTR(data);
00831 struct in6_addr addr;
00832 unsigned int ifindex;
00833 char addrbuf[INET6_ADDRSTRLEN], ifbuf[IFNAMSIZ];
00834 memcpy(&addr, &pktinfo->ipi6_addr, sizeof(addr));
00835 memcpy(&ifindex, &pktinfo->ipi6_ifindex, sizeof(ifindex));
00836 if (inet_ntop(AF_INET6, &addr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
00837 rb_str_cat2(ret, " invalid-address");
00838 else
00839 rb_str_catf(ret, " %s", addrbuf);
00840 if (if_indextoname(ifindex, ifbuf) == NULL)
00841 rb_str_catf(ret, " ifindex:%d", ifindex);
00842 else
00843 rb_str_catf(ret, " %s", ifbuf);
00844 return 1;
00845 }
00846 else {
00847 return 0;
00848 }
00849 }
00850 #endif
00851
00852 #if defined(SCM_TIMESTAMP)
00853 static int
00854 inspect_timeval_as_abstime(int level, int optname, VALUE data, VALUE ret)
00855 {
00856 if (RSTRING_LEN(data) == sizeof(struct timeval)) {
00857 struct timeval tv;
00858 time_t time;
00859 struct tm tm;
00860 char buf[32];
00861 memcpy((char*)&tv, RSTRING_PTR(data), sizeof(tv));
00862 time = tv.tv_sec;
00863 tm = *localtime(&time);
00864 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
00865 rb_str_catf(ret, " %s.%06ld", buf, (long)tv.tv_usec);
00866 return 1;
00867 }
00868 else {
00869 return 0;
00870 }
00871 }
00872 #endif
00873
00874 #if defined(SCM_TIMESTAMPNS)
00875 static int
00876 inspect_timespec_as_abstime(int level, int optname, VALUE data, VALUE ret)
00877 {
00878 if (RSTRING_LEN(data) == sizeof(struct timespec)) {
00879 struct timespec ts;
00880 struct tm tm;
00881 char buf[32];
00882 memcpy((char*)&ts, RSTRING_PTR(data), sizeof(ts));
00883 tm = *localtime(&ts.tv_sec);
00884 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
00885 rb_str_catf(ret, " %s.%09ld", buf, (long)ts.tv_nsec);
00886 return 1;
00887 }
00888 else {
00889 return 0;
00890 }
00891 }
00892 #endif
00893
00894 #if defined(SCM_BINTIME)
00895 static int
00896 inspect_bintime_as_abstime(int level, int optname, VALUE data, VALUE ret)
00897 {
00898 if (RSTRING_LEN(data) == sizeof(struct bintime)) {
00899 struct bintime bt;
00900 struct tm tm;
00901 uint64_t frac_h, frac_l;
00902 uint64_t scale_h, scale_l;
00903 uint64_t tmp1, tmp2;
00904 uint64_t res_h, res_l;
00905 char buf[32];
00906 memcpy((char*)&bt, RSTRING_PTR(data), sizeof(bt));
00907 tm = *localtime(&bt.sec);
00908 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
00909
00910
00911
00912 frac_h = bt.frac >> 32;
00913 frac_l = bt.frac & 0xffffffff;
00914
00915 scale_h = 0x8ac72304;
00916 scale_l = 0x89e80000;
00917
00918 res_h = frac_h * scale_h;
00919 res_l = frac_l * scale_l;
00920
00921 tmp1 = frac_h * scale_l;
00922 res_h += tmp1 >> 32;
00923 tmp2 = res_l;
00924 res_l += tmp1 & 0xffffffff;
00925 if (res_l < tmp2) res_h++;
00926
00927 tmp1 = frac_l * scale_h;
00928 res_h += tmp1 >> 32;
00929 tmp2 = res_l;
00930 res_l += tmp1 & 0xffffffff;
00931 if (res_l < tmp2) res_h++;
00932
00933 rb_str_catf(ret, " %s.%019"PRIu64, buf, res_h);
00934 return 1;
00935 }
00936 else {
00937 return 0;
00938 }
00939 }
00940 #endif
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951 static VALUE
00952 ancillary_inspect(VALUE self)
00953 {
00954 VALUE ret;
00955 int family, level, type;
00956 VALUE data;
00957 ID family_id, level_id, type_id;
00958 VALUE vtype;
00959 int inspected;
00960
00961 family = ancillary_family(self);
00962 level = ancillary_level(self);
00963 type = ancillary_type(self);
00964 data = ancillary_data(self);
00965
00966 ret = rb_sprintf("#<%s:", rb_obj_classname(self));
00967
00968 family_id = rsock_intern_family_noprefix(family);
00969 if (family_id)
00970 rb_str_catf(ret, " %s", rb_id2name(family_id));
00971 else
00972 rb_str_catf(ret, " family:%d", family);
00973
00974 if (level == SOL_SOCKET) {
00975 rb_str_cat2(ret, " SOCKET");
00976
00977 type_id = rsock_intern_scm_optname(type);
00978 if (type_id)
00979 rb_str_catf(ret, " %s", rb_id2name(type_id));
00980 else
00981 rb_str_catf(ret, " cmsg_type:%d", type);
00982 }
00983 else if (IS_IP_FAMILY(family)) {
00984 level_id = rsock_intern_iplevel(level);
00985 if (level_id)
00986 rb_str_catf(ret, " %s", rb_id2name(level_id));
00987 else
00988 rb_str_catf(ret, " cmsg_level:%d", level);
00989
00990 vtype = ip_cmsg_type_to_sym(level, type);
00991 if (SYMBOL_P(vtype))
00992 rb_str_catf(ret, " %s", rb_id2name(SYM2ID(vtype)));
00993 else
00994 rb_str_catf(ret, " cmsg_type:%d", type);
00995 }
00996 else {
00997 rb_str_catf(ret, " cmsg_level:%d", level);
00998 rb_str_catf(ret, " cmsg_type:%d", type);
00999 }
01000
01001 inspected = 0;
01002
01003 if (level == SOL_SOCKET)
01004 family = AF_UNSPEC;
01005
01006 switch (family) {
01007 case AF_UNSPEC:
01008 switch (level) {
01009 # if defined(SOL_SOCKET)
01010 case SOL_SOCKET:
01011 switch (type) {
01012 # if defined(SCM_TIMESTAMP)
01013 case SCM_TIMESTAMP: inspected = inspect_timeval_as_abstime(level, type, data, ret); break;
01014 # endif
01015 # if defined(SCM_TIMESTAMPNS)
01016 case SCM_TIMESTAMPNS: inspected = inspect_timespec_as_abstime(level, type, data, ret); break;
01017 # endif
01018 # if defined(SCM_BINTIME)
01019 case SCM_BINTIME: inspected = inspect_bintime_as_abstime(level, type, data, ret); break;
01020 # endif
01021 # if defined(SCM_RIGHTS)
01022 case SCM_RIGHTS: inspected = anc_inspect_socket_rights(level, type, data, ret); break;
01023 # endif
01024 # if defined(SCM_CREDENTIALS)
01025 case SCM_CREDENTIALS: inspected = anc_inspect_passcred_credentials(level, type, data, ret); break;
01026 # endif
01027 # if defined(INSPECT_SCM_CREDS)
01028 case SCM_CREDS: inspected = anc_inspect_socket_creds(level, type, data, ret); break;
01029 # endif
01030 }
01031 break;
01032 # endif
01033 }
01034 break;
01035
01036 case AF_INET:
01037 #ifdef INET6
01038 case AF_INET6:
01039 #endif
01040 switch (level) {
01041 # if defined(IPPROTO_IP)
01042 case IPPROTO_IP:
01043 switch (type) {
01044 # if defined(IP_RECVDSTADDR)
01045 case IP_RECVDSTADDR: inspected = anc_inspect_ip_recvdstaddr(level, type, data, ret); break;
01046 # endif
01047 # if defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST)
01048 case IP_PKTINFO: inspected = anc_inspect_ip_pktinfo(level, type, data, ret); break;
01049 # endif
01050 }
01051 break;
01052 # endif
01053
01054 # if defined(IPPROTO_IPV6)
01055 case IPPROTO_IPV6:
01056 switch (type) {
01057 # if defined(IPV6_PKTINFO)
01058 case IPV6_PKTINFO: inspected = anc_inspect_ipv6_pktinfo(level, type, data, ret); break;
01059 # endif
01060 }
01061 break;
01062 # endif
01063 }
01064 break;
01065 }
01066
01067 if (!inspected) {
01068 rb_str_cat2(ret, " ");
01069 rb_str_append(ret, rb_str_dump(data));
01070 }
01071
01072 rb_str_cat2(ret, ">");
01073
01074 return ret;
01075 }
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089 static VALUE
01090 ancillary_cmsg_is_p(VALUE self, VALUE vlevel, VALUE vtype)
01091 {
01092 int family = ancillary_family(self);
01093 int level = rsock_level_arg(family, vlevel);
01094 int type = rsock_cmsg_type_arg(family, level, vtype);
01095
01096 if (ancillary_level(self) == level &&
01097 ancillary_type(self) == type)
01098 return Qtrue;
01099 else
01100 return Qfalse;
01101 }
01102
01103 #endif
01104
01105 #if defined(HAVE_SENDMSG)
01106 struct sendmsg_args_struct {
01107 int fd;
01108 const struct msghdr *msg;
01109 int flags;
01110 };
01111
01112 static void *
01113 nogvl_sendmsg_func(void *ptr)
01114 {
01115 struct sendmsg_args_struct *args = ptr;
01116 return (void *)(VALUE)sendmsg(args->fd, args->msg, args->flags);
01117 }
01118
01119 static ssize_t
01120 rb_sendmsg(int fd, const struct msghdr *msg, int flags)
01121 {
01122 struct sendmsg_args_struct args;
01123 args.fd = fd;
01124 args.msg = msg;
01125 args.flags = flags;
01126 return (ssize_t)rb_thread_call_without_gvl(nogvl_sendmsg_func, &args, RUBY_UBF_IO, 0);
01127 }
01128
01129 static VALUE
01130 bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
01131 {
01132 rb_io_t *fptr;
01133 VALUE data, vflags, dest_sockaddr;
01134 VALUE *controls_ptr;
01135 int controls_num;
01136 struct msghdr mh;
01137 struct iovec iov;
01138 #if defined(HAVE_ST_MSG_CONTROL)
01139 volatile VALUE controls_str = 0;
01140 #endif
01141 int flags;
01142 ssize_t ss;
01143 int family;
01144
01145 rb_secure(4);
01146 GetOpenFile(sock, fptr);
01147 family = rsock_getfamily(fptr->fd);
01148
01149 data = vflags = dest_sockaddr = Qnil;
01150 controls_ptr = NULL;
01151 controls_num = 0;
01152
01153 if (argc == 0)
01154 rb_raise(rb_eArgError, "mesg argument required");
01155 data = argv[0];
01156 if (1 < argc) vflags = argv[1];
01157 if (2 < argc) dest_sockaddr = argv[2];
01158 if (3 < argc) { controls_ptr = &argv[3]; controls_num = argc - 3; }
01159
01160 StringValue(data);
01161
01162 if (controls_num) {
01163 #if defined(HAVE_ST_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_LENINT(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_ST_MSG_CONTROL)
01267 if (controls_str) {
01268 mh.msg_control = RSTRING_PTR(controls_str);
01269 mh.msg_controllen = RSTRING_LENINT(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_mod_sys_fail(rb_mWaitWritable, "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 #ifdef MSG_CMSG_CLOEXEC
01367
01368 flags |= MSG_CMSG_CLOEXEC;
01369 #endif
01370 return recvmsg(socket, message, flags);
01371 }
01372
01373 static void *
01374 nogvl_recvmsg_func(void *ptr)
01375 {
01376 struct recvmsg_args_struct *args = ptr;
01377 int flags = args->flags;
01378 return (void *)rsock_recvmsg(args->fd, args->msg, flags);
01379 }
01380
01381 static ssize_t
01382 rb_recvmsg(int fd, struct msghdr *msg, int flags)
01383 {
01384 struct recvmsg_args_struct args;
01385 args.fd = fd;
01386 args.msg = msg;
01387 args.flags = flags;
01388 return (ssize_t)rb_thread_call_without_gvl(nogvl_recvmsg_func, &args, RUBY_UBF_IO, 0);
01389 }
01390
01391 #if defined(HAVE_ST_MSG_CONTROL)
01392 static void
01393 discard_cmsg(struct cmsghdr *cmh, char *msg_end, int msg_peek_p)
01394 {
01395 # if !defined(FD_PASSING_WORK_WITH_RECVMSG_MSG_PEEK)
01396
01397
01398
01399
01400
01401
01402
01403
01404 if (msg_peek_p)
01405 return;
01406 # endif
01407 if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
01408 int *fdp = (int *)CMSG_DATA(cmh);
01409 int *end = (int *)((char *)cmh + cmh->cmsg_len);
01410 while ((char *)fdp + sizeof(int) <= (char *)end &&
01411 (char *)fdp + sizeof(int) <= msg_end) {
01412 rb_fd_fix_cloexec(*fdp);
01413 close(*fdp);
01414 fdp++;
01415 }
01416 }
01417 }
01418 #endif
01419
01420 void
01421 rsock_discard_cmsg_resource(struct msghdr *mh, int msg_peek_p)
01422 {
01423 #if defined(HAVE_ST_MSG_CONTROL)
01424 struct cmsghdr *cmh;
01425 char *msg_end;
01426
01427 if (mh->msg_controllen == 0)
01428 return;
01429
01430 msg_end = (char *)mh->msg_control + mh->msg_controllen;
01431
01432 for (cmh = CMSG_FIRSTHDR(mh); cmh != NULL; cmh = CMSG_NXTHDR(mh, cmh)) {
01433 discard_cmsg(cmh, msg_end, msg_peek_p);
01434 }
01435 #endif
01436 }
01437
01438 #if defined(HAVE_ST_MSG_CONTROL)
01439 static void
01440 make_io_for_unix_rights(VALUE ctl, struct cmsghdr *cmh, char *msg_end)
01441 {
01442 if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
01443 int *fdp, *end;
01444 VALUE ary = rb_ary_new();
01445 rb_ivar_set(ctl, rb_intern("unix_rights"), ary);
01446 fdp = (int *)CMSG_DATA(cmh);
01447 end = (int *)((char *)cmh + cmh->cmsg_len);
01448 while ((char *)fdp + sizeof(int) <= (char *)end &&
01449 (char *)fdp + sizeof(int) <= msg_end) {
01450 int fd = *fdp;
01451 struct stat stbuf;
01452 VALUE io;
01453 if (fstat(fd, &stbuf) == -1)
01454 rb_raise(rb_eSocket, "invalid fd in SCM_RIGHTS");
01455 rb_fd_fix_cloexec(fd);
01456 if (S_ISSOCK(stbuf.st_mode))
01457 io = rsock_init_sock(rb_obj_alloc(rb_cSocket), fd);
01458 else
01459 io = rb_io_fdopen(fd, O_RDWR, NULL);
01460 ary = rb_attr_get(ctl, rb_intern("unix_rights"));
01461 rb_ary_push(ary, io);
01462 fdp++;
01463 }
01464 OBJ_FREEZE(ary);
01465 }
01466 }
01467 #endif
01468
01469 static VALUE
01470 bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
01471 {
01472 rb_io_t *fptr;
01473 VALUE vmaxdatlen, vmaxctllen, vflags, vopts;
01474 int grow_buffer;
01475 size_t maxdatlen;
01476 int flags, orig_flags;
01477 int request_scm_rights;
01478 struct msghdr mh;
01479 struct iovec iov;
01480 struct sockaddr_storage namebuf;
01481 char datbuf0[4096], *datbuf;
01482 VALUE dat_str = Qnil;
01483 VALUE ret;
01484 ssize_t ss;
01485 #if defined(HAVE_ST_MSG_CONTROL)
01486 struct cmsghdr *cmh;
01487 size_t maxctllen;
01488 union {
01489 char bytes[4096];
01490 struct cmsghdr align;
01491 } ctlbuf0;
01492 char *ctlbuf;
01493 VALUE ctl_str = Qnil;
01494 int family;
01495 int gc_done = 0;
01496 #endif
01497
01498 rb_secure(4);
01499
01500 vopts = Qnil;
01501 if (0 < argc && RB_TYPE_P(argv[argc-1], T_HASH))
01502 vopts = argv[--argc];
01503
01504 rb_scan_args(argc, argv, "03", &vmaxdatlen, &vflags, &vmaxctllen);
01505
01506 maxdatlen = NIL_P(vmaxdatlen) ? sizeof(datbuf0) : NUM2SIZET(vmaxdatlen);
01507 #if defined(HAVE_ST_MSG_CONTROL)
01508 maxctllen = NIL_P(vmaxctllen) ? sizeof(ctlbuf0) : NUM2SIZET(vmaxctllen);
01509 #else
01510 if (!NIL_P(vmaxctllen))
01511 rb_raise(rb_eArgError, "control message not supported");
01512 #endif
01513 flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
01514 #ifdef MSG_DONTWAIT
01515 if (nonblock)
01516 flags |= MSG_DONTWAIT;
01517 #endif
01518 orig_flags = flags;
01519
01520 grow_buffer = NIL_P(vmaxdatlen) || NIL_P(vmaxctllen);
01521
01522 request_scm_rights = 0;
01523 if (!NIL_P(vopts) && RTEST(rb_hash_aref(vopts, ID2SYM(rb_intern("scm_rights")))))
01524 request_scm_rights = 1;
01525
01526 GetOpenFile(sock, fptr);
01527 if (rb_io_read_pending(fptr)) {
01528 rb_raise(rb_eIOError, "recvmsg for buffered IO");
01529 }
01530
01531 #if !defined(HAVE_ST_MSG_CONTROL)
01532 if (grow_buffer) {
01533 int socktype;
01534 socklen_t optlen = (socklen_t)sizeof(socktype);
01535 if (getsockopt(fptr->fd, SOL_SOCKET, SO_TYPE, (void*)&socktype, &optlen) == -1) {
01536 rb_sys_fail("getsockopt(SO_TYPE)");
01537 }
01538 if (socktype == SOCK_STREAM)
01539 grow_buffer = 0;
01540 }
01541 #endif
01542
01543 retry:
01544 if (maxdatlen <= sizeof(datbuf0))
01545 datbuf = datbuf0;
01546 else {
01547 if (NIL_P(dat_str))
01548 dat_str = rb_str_tmp_new(maxdatlen);
01549 else
01550 rb_str_resize(dat_str, maxdatlen);
01551 datbuf = RSTRING_PTR(dat_str);
01552 }
01553
01554 #if defined(HAVE_ST_MSG_CONTROL)
01555 if (maxctllen <= sizeof(ctlbuf0))
01556 ctlbuf = ctlbuf0.bytes;
01557 else {
01558 if (NIL_P(ctl_str))
01559 ctl_str = rb_str_tmp_new(maxctllen);
01560 else
01561 rb_str_resize(ctl_str, maxctllen);
01562 ctlbuf = RSTRING_PTR(ctl_str);
01563 }
01564 #endif
01565
01566 memset(&mh, 0, sizeof(mh));
01567
01568 memset(&namebuf, 0, sizeof(namebuf));
01569 mh.msg_name = (struct sockaddr *)&namebuf;
01570 mh.msg_namelen = (socklen_t)sizeof(namebuf);
01571
01572 mh.msg_iov = &iov;
01573 mh.msg_iovlen = 1;
01574 iov.iov_base = datbuf;
01575 iov.iov_len = maxdatlen;
01576
01577 #if defined(HAVE_ST_MSG_CONTROL)
01578 mh.msg_control = ctlbuf;
01579 mh.msg_controllen = (socklen_t)maxctllen;
01580 #endif
01581
01582 if (grow_buffer)
01583 flags |= MSG_PEEK;
01584
01585 rb_io_check_closed(fptr);
01586 if (nonblock)
01587 rb_io_set_nonblock(fptr);
01588
01589 ss = rb_recvmsg(fptr->fd, &mh, flags);
01590
01591 if (ss == -1) {
01592 if (!nonblock && rb_io_wait_readable(fptr->fd)) {
01593 rb_io_check_closed(fptr);
01594 goto retry;
01595 }
01596 if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
01597 rb_mod_sys_fail(rb_mWaitReadable, "recvmsg(2) would block");
01598 #if defined(HAVE_ST_MSG_CONTROL)
01599 if (!gc_done && (errno == EMFILE || errno == EMSGSIZE)) {
01600
01601
01602
01603
01604
01605
01606 gc_and_retry:
01607 rb_gc();
01608 gc_done = 1;
01609 goto retry;
01610 }
01611 #endif
01612 rb_sys_fail("recvmsg(2)");
01613 }
01614
01615 if (grow_buffer) {
01616 int grown = 0;
01617 #if defined(HAVE_ST_MSG_CONTROL)
01618 if (NIL_P(vmaxdatlen) && (mh.msg_flags & MSG_TRUNC)) {
01619 if (SIZE_MAX/2 < maxdatlen)
01620 rb_raise(rb_eArgError, "max data length too big");
01621 maxdatlen *= 2;
01622 grown = 1;
01623 }
01624 if (NIL_P(vmaxctllen) && (mh.msg_flags & MSG_CTRUNC)) {
01625 #define BIG_ENOUGH_SPACE 65536
01626 if (BIG_ENOUGH_SPACE < maxctllen &&
01627 mh.msg_controllen < (socklen_t)(maxctllen - BIG_ENOUGH_SPACE)) {
01628
01629
01630 if (!gc_done) {
01631 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
01632 goto gc_and_retry;
01633 }
01634 }
01635 else {
01636 if (SIZE_MAX/2 < maxctllen)
01637 rb_raise(rb_eArgError, "max control message length too big");
01638 maxctllen *= 2;
01639 grown = 1;
01640 }
01641 #undef BIG_ENOUGH_SPACE
01642 }
01643 #else
01644 if (NIL_P(vmaxdatlen) && ss != -1 && ss == (ssize_t)iov.iov_len) {
01645 if (SIZE_MAX/2 < maxdatlen)
01646 rb_raise(rb_eArgError, "max data length too big");
01647 maxdatlen *= 2;
01648 grown = 1;
01649 }
01650 #endif
01651 if (grown) {
01652 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
01653 goto retry;
01654 }
01655 else {
01656 grow_buffer = 0;
01657 if (flags != orig_flags) {
01658 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
01659 flags = orig_flags;
01660 goto retry;
01661 }
01662 }
01663 }
01664
01665 if (NIL_P(dat_str))
01666 dat_str = rb_tainted_str_new(datbuf, ss);
01667 else {
01668 rb_str_resize(dat_str, ss);
01669 OBJ_TAINT(dat_str);
01670 RBASIC(dat_str)->klass = rb_cString;
01671 }
01672
01673 ret = rb_ary_new3(3, dat_str,
01674 rsock_io_socket_addrinfo(sock, mh.msg_name, mh.msg_namelen),
01675 #if defined(HAVE_ST_MSG_CONTROL)
01676 INT2NUM(mh.msg_flags)
01677 #else
01678 Qnil
01679 #endif
01680 );
01681
01682 #if defined(HAVE_ST_MSG_CONTROL)
01683 family = rsock_getfamily(fptr->fd);
01684 if (mh.msg_controllen) {
01685 char *msg_end = (char *)mh.msg_control + mh.msg_controllen;
01686 for (cmh = CMSG_FIRSTHDR(&mh); cmh != NULL; cmh = CMSG_NXTHDR(&mh, cmh)) {
01687 VALUE ctl;
01688 char *ctl_end;
01689 size_t clen;
01690 if (cmh->cmsg_len == 0) {
01691 rb_raise(rb_eTypeError, "invalid control message (cmsg_len == 0)");
01692 }
01693 ctl_end = (char*)cmh + cmh->cmsg_len;
01694 clen = (ctl_end <= msg_end ? ctl_end : msg_end) - (char*)CMSG_DATA(cmh);
01695 ctl = ancdata_new(family, cmh->cmsg_level, cmh->cmsg_type, rb_tainted_str_new((char*)CMSG_DATA(cmh), clen));
01696 if (request_scm_rights)
01697 make_io_for_unix_rights(ctl, cmh, msg_end);
01698 else
01699 discard_cmsg(cmh, msg_end, (flags & MSG_PEEK) != 0);
01700 rb_ary_push(ret, ctl);
01701 }
01702 }
01703 #endif
01704
01705 return ret;
01706 }
01707 #endif
01708
01709 #if defined(HAVE_RECVMSG)
01710
01711
01712
01713
01714
01715
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 VALUE
01764 rsock_bsock_recvmsg(int argc, VALUE *argv, VALUE sock)
01765 {
01766 return bsock_recvmsg_internal(argc, argv, sock, 0);
01767 }
01768 #endif
01769
01770 #if defined(HAVE_RECVMSG)
01771
01772
01773
01774
01775
01776
01777
01778
01779
01780
01781
01782 VALUE
01783 rsock_bsock_recvmsg_nonblock(int argc, VALUE *argv, VALUE sock)
01784 {
01785 return bsock_recvmsg_internal(argc, argv, sock, 1);
01786 }
01787 #endif
01788
01789 void
01790 rsock_init_ancdata(void)
01791 {
01792 #if defined(HAVE_ST_MSG_CONTROL)
01793
01794
01795
01796
01797
01798
01799
01800 rb_cAncillaryData = rb_define_class_under(rb_cSocket, "AncillaryData", rb_cObject);
01801 rb_define_method(rb_cAncillaryData, "initialize", ancillary_initialize, 4);
01802 rb_define_method(rb_cAncillaryData, "inspect", ancillary_inspect, 0);
01803 rb_define_method(rb_cAncillaryData, "family", ancillary_family_m, 0);
01804 rb_define_method(rb_cAncillaryData, "level", ancillary_level_m, 0);
01805 rb_define_method(rb_cAncillaryData, "type", ancillary_type_m, 0);
01806 rb_define_method(rb_cAncillaryData, "data", ancillary_data, 0);
01807
01808 rb_define_method(rb_cAncillaryData, "cmsg_is?", ancillary_cmsg_is_p, 2);
01809
01810 rb_define_singleton_method(rb_cAncillaryData, "int", ancillary_s_int, 4);
01811 rb_define_method(rb_cAncillaryData, "int", ancillary_int, 0);
01812
01813 rb_define_singleton_method(rb_cAncillaryData, "unix_rights", ancillary_s_unix_rights, -1);
01814 rb_define_method(rb_cAncillaryData, "unix_rights", ancillary_unix_rights, 0);
01815
01816 rb_define_method(rb_cAncillaryData, "timestamp", ancillary_timestamp, 0);
01817
01818 rb_define_singleton_method(rb_cAncillaryData, "ip_pktinfo", ancillary_s_ip_pktinfo, -1);
01819 rb_define_method(rb_cAncillaryData, "ip_pktinfo", ancillary_ip_pktinfo, 0);
01820
01821 rb_define_singleton_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_s_ipv6_pktinfo, 2);
01822 rb_define_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_ipv6_pktinfo, 0);
01823 rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_addr", ancillary_ipv6_pktinfo_addr, 0);
01824 rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_ifindex", ancillary_ipv6_pktinfo_ifindex, 0);
01825 #endif
01826 }
01827