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(obj, struct RObject);
00090 OBJSETUP(obj, rb_cAncillaryData, T_OBJECT);
00091 StringValue(data);
00092 ancillary_initialize((VALUE)obj, INT2NUM(family), INT2NUM(level), INT2NUM(type), data);
00093 return (VALUE)obj;
00094 }
00095
00096 static int
00097 ancillary_family(VALUE self)
00098 {
00099 VALUE v = rb_attr_get(self, rb_intern("family"));
00100 return NUM2INT(v);
00101 }
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112 static VALUE
00113 ancillary_family_m(VALUE self)
00114 {
00115 return INT2NUM(ancillary_family(self));
00116 }
00117
00118 static int
00119 ancillary_level(VALUE self)
00120 {
00121 VALUE v = rb_attr_get(self, rb_intern("level"));
00122 return NUM2INT(v);
00123 }
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134 static VALUE
00135 ancillary_level_m(VALUE self)
00136 {
00137 return INT2NUM(ancillary_level(self));
00138 }
00139
00140 static int
00141 ancillary_type(VALUE self)
00142 {
00143 VALUE v = rb_attr_get(self, rb_intern("type"));
00144 return NUM2INT(v);
00145 }
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156 static VALUE
00157 ancillary_type_m(VALUE self)
00158 {
00159 return INT2NUM(ancillary_type(self));
00160 }
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171 static VALUE
00172 ancillary_data(VALUE self)
00173 {
00174 VALUE v = rb_attr_get(self, rb_intern("data"));
00175 StringValue(v);
00176 return v;
00177 }
00178
00179 #ifdef SCM_RIGHTS
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189 static VALUE
00190 ancillary_s_unix_rights(int argc, VALUE *argv, VALUE klass)
00191 {
00192 VALUE result, str, ary;
00193 int i;
00194
00195 ary = rb_ary_new();
00196
00197 for (i = 0 ; i < argc; i++) {
00198 VALUE obj = argv[i];
00199 if (TYPE(obj) != T_FILE) {
00200 rb_raise(rb_eTypeError, "IO expected");
00201 }
00202 rb_ary_push(ary, obj);
00203 }
00204
00205 str = rb_str_buf_new(sizeof(int) * argc);
00206
00207 for (i = 0 ; i < argc; i++) {
00208 VALUE obj = RARRAY_PTR(ary)[i];
00209 rb_io_t *fptr;
00210 int fd;
00211 GetOpenFile(obj, fptr);
00212 fd = fptr->fd;
00213 rb_str_buf_cat(str, (char *)&fd, sizeof(int));
00214 }
00215
00216 result = ancdata_new(AF_UNIX, SOL_SOCKET, SCM_RIGHTS, str);
00217 rb_ivar_set(result, rb_intern("unix_rights"), ary);
00218 return result;
00219 }
00220 #else
00221 #define ancillary_s_unix_rights rb_f_notimplement
00222 #endif
00223
00224 #ifdef SCM_RIGHTS
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(0x100000000UL);
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 VALUE
01113 nogvl_sendmsg_func(void *ptr)
01114 {
01115 struct sendmsg_args_struct *args = ptr;
01116 return 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 rb_thread_blocking_region(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 int last_level = 0;
01167 int last_type = 0;
01168 controls_str = rb_str_tmp_new(0);
01169 for (i = 0; i < controls_num; i++) {
01170 VALUE elt = controls_ptr[i], v;
01171 VALUE vlevel, vtype;
01172 int level, type;
01173 VALUE cdata;
01174 long oldlen;
01175 struct cmsghdr cmh;
01176 char *cmsg;
01177 size_t cspace;
01178 v = rb_check_convert_type(elt, T_ARRAY, "Array", "to_ary");
01179 if (!NIL_P(v)) {
01180 elt = v;
01181 if (RARRAY_LEN(elt) != 3)
01182 rb_raise(rb_eArgError, "an element of controls should be 3-elements array");
01183 vlevel = rb_ary_entry(elt, 0);
01184 vtype = rb_ary_entry(elt, 1);
01185 cdata = rb_ary_entry(elt, 2);
01186 }
01187 else {
01188 vlevel = rb_funcall(elt, rb_intern("level"), 0);
01189 vtype = rb_funcall(elt, rb_intern("type"), 0);
01190 cdata = rb_funcall(elt, rb_intern("data"), 0);
01191 }
01192 level = rsock_level_arg(family, vlevel);
01193 type = rsock_cmsg_type_arg(family, level, vtype);
01194 StringValue(cdata);
01195 oldlen = RSTRING_LEN(controls_str);
01196 cspace = CMSG_SPACE(RSTRING_LEN(cdata));
01197 rb_str_resize(controls_str, oldlen + cspace);
01198 cmsg = RSTRING_PTR(controls_str)+oldlen;
01199 memset((char *)cmsg, 0, cspace);
01200 memset((char *)&cmh, 0, sizeof(cmh));
01201 cmh.cmsg_level = level;
01202 cmh.cmsg_type = type;
01203 cmh.cmsg_len = (socklen_t)CMSG_LEN(RSTRING_LEN(cdata));
01204 MEMCPY(cmsg, &cmh, char, sizeof(cmh));
01205 MEMCPY(cmsg+((char*)CMSG_DATA(&cmh)-(char*)&cmh), RSTRING_PTR(cdata), char, RSTRING_LEN(cdata));
01206 last_level = cmh.cmsg_level;
01207 last_type = cmh.cmsg_type;
01208 last_pad = cspace - cmh.cmsg_len;
01209 }
01210 if (last_pad) {
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231 #if defined(__NetBSD__)
01232 if (last_level == SOL_SOCKET && last_type == SCM_RIGHTS)
01233 rb_str_set_len(controls_str, RSTRING_LEN(controls_str)-last_pad);
01234 #endif
01235 }
01236 #else
01237 rb_raise(rb_eNotImpError, "control message for sendmsg is unimplemented");
01238 #endif
01239 }
01240
01241 flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
01242 #ifdef MSG_DONTWAIT
01243 if (nonblock)
01244 flags |= MSG_DONTWAIT;
01245 #endif
01246
01247 if (!NIL_P(dest_sockaddr))
01248 SockAddrStringValue(dest_sockaddr);
01249
01250 rb_io_check_closed(fptr);
01251
01252 retry:
01253 memset(&mh, 0, sizeof(mh));
01254 if (!NIL_P(dest_sockaddr)) {
01255 mh.msg_name = RSTRING_PTR(dest_sockaddr);
01256 mh.msg_namelen = RSTRING_LENINT(dest_sockaddr);
01257 }
01258 mh.msg_iovlen = 1;
01259 mh.msg_iov = &iov;
01260 iov.iov_base = RSTRING_PTR(data);
01261 iov.iov_len = RSTRING_LEN(data);
01262 #if defined(HAVE_ST_MSG_CONTROL)
01263 if (controls_str) {
01264 mh.msg_control = RSTRING_PTR(controls_str);
01265 mh.msg_controllen = RSTRING_LENINT(controls_str);
01266 }
01267 else {
01268 mh.msg_control = NULL;
01269 mh.msg_controllen = 0;
01270 }
01271 #endif
01272
01273 rb_io_check_closed(fptr);
01274 if (nonblock)
01275 rb_io_set_nonblock(fptr);
01276
01277 ss = rb_sendmsg(fptr->fd, &mh, flags);
01278
01279 if (!nonblock && rb_io_wait_writable(fptr->fd)) {
01280 rb_io_check_closed(fptr);
01281 goto retry;
01282 }
01283
01284 if (ss == -1) {
01285 if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
01286 rb_mod_sys_fail(rb_mWaitWritable, "sendmsg(2) would block");
01287 rb_sys_fail("sendmsg(2)");
01288 }
01289
01290 return SSIZET2NUM(ss);
01291 }
01292 #endif
01293
01294 #if defined(HAVE_SENDMSG)
01295
01296
01297
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 VALUE
01328 rsock_bsock_sendmsg(int argc, VALUE *argv, VALUE sock)
01329 {
01330 return bsock_sendmsg_internal(argc, argv, sock, 0);
01331 }
01332 #endif
01333
01334 #if defined(HAVE_SENDMSG)
01335
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346 VALUE
01347 rsock_bsock_sendmsg_nonblock(int argc, VALUE *argv, VALUE sock)
01348 {
01349 return bsock_sendmsg_internal(argc, argv, sock, 1);
01350 }
01351 #endif
01352
01353 #if defined(HAVE_RECVMSG)
01354 struct recvmsg_args_struct {
01355 int fd;
01356 struct msghdr *msg;
01357 int flags;
01358 };
01359
01360 static VALUE
01361 nogvl_recvmsg_func(void *ptr)
01362 {
01363 struct recvmsg_args_struct *args = ptr;
01364 return recvmsg(args->fd, args->msg, args->flags);
01365 }
01366
01367 static ssize_t
01368 rb_recvmsg(int fd, struct msghdr *msg, int flags)
01369 {
01370 struct recvmsg_args_struct args;
01371 args.fd = fd;
01372 args.msg = msg;
01373 args.flags = flags;
01374 return rb_thread_blocking_region(nogvl_recvmsg_func, &args, RUBY_UBF_IO, 0);
01375 }
01376
01377 #if defined(HAVE_ST_MSG_CONTROL)
01378 static void
01379 discard_cmsg(struct cmsghdr *cmh, char *msg_end)
01380 {
01381 if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
01382 int *fdp = (int *)CMSG_DATA(cmh);
01383 int *end = (int *)((char *)cmh + cmh->cmsg_len);
01384 while ((char *)fdp + sizeof(int) <= (char *)end &&
01385 (char *)fdp + sizeof(int) <= msg_end) {
01386 close(*fdp);
01387 fdp++;
01388 }
01389 }
01390 }
01391 #endif
01392
01393 void
01394 rsock_discard_cmsg_resource(struct msghdr *mh)
01395 {
01396 #if defined(HAVE_ST_MSG_CONTROL)
01397 struct cmsghdr *cmh;
01398 char *msg_end;
01399
01400 if (mh->msg_controllen == 0)
01401 return;
01402
01403 msg_end = (char *)mh->msg_control + mh->msg_controllen;
01404
01405 for (cmh = CMSG_FIRSTHDR(mh); cmh != NULL; cmh = CMSG_NXTHDR(mh, cmh)) {
01406 discard_cmsg(cmh, msg_end);
01407 }
01408 #endif
01409 }
01410
01411 #if defined(HAVE_ST_MSG_CONTROL)
01412 static void
01413 make_io_for_unix_rights(VALUE ctl, struct cmsghdr *cmh, char *msg_end)
01414 {
01415 if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
01416 int *fdp, *end;
01417 VALUE ary = rb_ary_new();
01418 rb_ivar_set(ctl, rb_intern("unix_rights"), ary);
01419 fdp = (int *)CMSG_DATA(cmh);
01420 end = (int *)((char *)cmh + cmh->cmsg_len);
01421 while ((char *)fdp + sizeof(int) <= (char *)end &&
01422 (char *)fdp + sizeof(int) <= msg_end) {
01423 int fd = *fdp;
01424 struct stat stbuf;
01425 VALUE io;
01426 if (fstat(fd, &stbuf) == -1)
01427 rb_raise(rb_eSocket, "invalid fd in SCM_RIGHTS");
01428 if (S_ISSOCK(stbuf.st_mode))
01429 io = rsock_init_sock(rb_obj_alloc(rb_cSocket), fd);
01430 else
01431 io = rb_io_fdopen(fd, O_RDWR, NULL);
01432 ary = rb_attr_get(ctl, rb_intern("unix_rights"));
01433 rb_ary_push(ary, io);
01434 fdp++;
01435 }
01436 OBJ_FREEZE(ary);
01437 }
01438 }
01439 #endif
01440
01441 static VALUE
01442 bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
01443 {
01444 rb_io_t *fptr;
01445 VALUE vmaxdatlen, vmaxctllen, vflags, vopts;
01446 int grow_buffer;
01447 size_t maxdatlen;
01448 int flags, orig_flags;
01449 int request_scm_rights;
01450 struct msghdr mh;
01451 struct iovec iov;
01452 struct sockaddr_storage namebuf;
01453 char datbuf0[4096], *datbuf;
01454 VALUE dat_str = Qnil;
01455 VALUE ret;
01456 ssize_t ss;
01457 #if defined(HAVE_ST_MSG_CONTROL)
01458 struct cmsghdr *cmh;
01459 size_t maxctllen;
01460 union {
01461 char bytes[4096];
01462 struct cmsghdr align;
01463 } ctlbuf0;
01464 char *ctlbuf;
01465 VALUE ctl_str = Qnil;
01466 int family;
01467 int gc_done = 0;
01468 #endif
01469
01470 rb_secure(4);
01471
01472 vopts = Qnil;
01473 if (0 < argc && TYPE(argv[argc-1]) == T_HASH)
01474 vopts = argv[--argc];
01475
01476 rb_scan_args(argc, argv, "03", &vmaxdatlen, &vflags, &vmaxctllen);
01477
01478 maxdatlen = NIL_P(vmaxdatlen) ? sizeof(datbuf0) : NUM2SIZET(vmaxdatlen);
01479 #if defined(HAVE_ST_MSG_CONTROL)
01480 maxctllen = NIL_P(vmaxctllen) ? sizeof(ctlbuf0) : NUM2SIZET(vmaxctllen);
01481 #else
01482 if (!NIL_P(vmaxctllen))
01483 rb_raise(rb_eArgError, "control message not supported");
01484 #endif
01485 flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
01486 #ifdef MSG_DONTWAIT
01487 if (nonblock)
01488 flags |= MSG_DONTWAIT;
01489 #endif
01490 orig_flags = flags;
01491
01492 grow_buffer = NIL_P(vmaxdatlen) || NIL_P(vmaxctllen);
01493
01494 request_scm_rights = 0;
01495 if (!NIL_P(vopts) && RTEST(rb_hash_aref(vopts, ID2SYM(rb_intern("scm_rights")))))
01496 request_scm_rights = 1;
01497
01498 GetOpenFile(sock, fptr);
01499 if (rb_io_read_pending(fptr)) {
01500 rb_raise(rb_eIOError, "recvmsg for buffered IO");
01501 }
01502
01503 #if !defined(HAVE_ST_MSG_CONTROL)
01504 if (grow_buffer) {
01505 int socktype;
01506 socklen_t optlen = (socklen_t)sizeof(socktype);
01507 if (getsockopt(fptr->fd, SOL_SOCKET, SO_TYPE, (void*)&socktype, &optlen) == -1) {
01508 rb_sys_fail("getsockopt(SO_TYPE)");
01509 }
01510 if (socktype == SOCK_STREAM)
01511 grow_buffer = 0;
01512 }
01513 #endif
01514
01515 retry:
01516 if (maxdatlen <= sizeof(datbuf0))
01517 datbuf = datbuf0;
01518 else {
01519 if (NIL_P(dat_str))
01520 dat_str = rb_str_tmp_new(maxdatlen);
01521 else
01522 rb_str_resize(dat_str, maxdatlen);
01523 datbuf = RSTRING_PTR(dat_str);
01524 }
01525
01526 #if defined(HAVE_ST_MSG_CONTROL)
01527 if (maxctllen <= sizeof(ctlbuf0))
01528 ctlbuf = ctlbuf0.bytes;
01529 else {
01530 if (NIL_P(ctl_str))
01531 ctl_str = rb_str_tmp_new(maxctllen);
01532 else
01533 rb_str_resize(ctl_str, maxctllen);
01534 ctlbuf = RSTRING_PTR(ctl_str);
01535 }
01536 #endif
01537
01538 memset(&mh, 0, sizeof(mh));
01539
01540 memset(&namebuf, 0, sizeof(namebuf));
01541 mh.msg_name = (struct sockaddr *)&namebuf;
01542 mh.msg_namelen = (socklen_t)sizeof(namebuf);
01543
01544 mh.msg_iov = &iov;
01545 mh.msg_iovlen = 1;
01546 iov.iov_base = datbuf;
01547 iov.iov_len = maxdatlen;
01548
01549 #if defined(HAVE_ST_MSG_CONTROL)
01550 mh.msg_control = ctlbuf;
01551 mh.msg_controllen = (socklen_t)maxctllen;
01552 #endif
01553
01554 if (grow_buffer)
01555 flags |= MSG_PEEK;
01556
01557 rb_io_check_closed(fptr);
01558 if (nonblock)
01559 rb_io_set_nonblock(fptr);
01560
01561 ss = rb_recvmsg(fptr->fd, &mh, flags);
01562
01563 if (!nonblock && rb_io_wait_readable(fptr->fd)) {
01564 rb_io_check_closed(fptr);
01565 goto retry;
01566 }
01567
01568 if (ss == -1) {
01569 if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
01570 rb_mod_sys_fail(rb_mWaitReadable, "recvmsg(2) would block");
01571 #if defined(HAVE_ST_MSG_CONTROL)
01572 if (!gc_done && (errno == EMFILE || errno == EMSGSIZE)) {
01573
01574
01575
01576
01577
01578
01579 gc_and_retry:
01580 rb_gc();
01581 gc_done = 1;
01582 goto retry;
01583 }
01584 #endif
01585 rb_sys_fail("recvmsg(2)");
01586 }
01587
01588 if (grow_buffer) {
01589 int grown = 0;
01590 #if defined(HAVE_ST_MSG_CONTROL)
01591 if (NIL_P(vmaxdatlen) && (mh.msg_flags & MSG_TRUNC)) {
01592 if (SIZE_MAX/2 < maxdatlen)
01593 rb_raise(rb_eArgError, "max data length too big");
01594 maxdatlen *= 2;
01595 grown = 1;
01596 }
01597 if (NIL_P(vmaxctllen) && (mh.msg_flags & MSG_CTRUNC)) {
01598 #define BIG_ENOUGH_SPACE 65536
01599 if (BIG_ENOUGH_SPACE < maxctllen &&
01600 mh.msg_controllen < maxctllen - BIG_ENOUGH_SPACE) {
01601
01602
01603 if (!gc_done) {
01604 rsock_discard_cmsg_resource(&mh);
01605 goto gc_and_retry;
01606 }
01607 }
01608 else {
01609 if (SIZE_MAX/2 < maxctllen)
01610 rb_raise(rb_eArgError, "max control message length too big");
01611 maxctllen *= 2;
01612 grown = 1;
01613 }
01614 #undef BIG_ENOUGH_SPACE
01615 }
01616 #else
01617 if (NIL_P(vmaxdatlen) && ss != -1 && ss == (ssize_t)iov.iov_len) {
01618 if (SIZE_MAX/2 < maxdatlen)
01619 rb_raise(rb_eArgError, "max data length too big");
01620 maxdatlen *= 2;
01621 grown = 1;
01622 }
01623 #endif
01624 if (grown) {
01625 rsock_discard_cmsg_resource(&mh);
01626 goto retry;
01627 }
01628 else {
01629 grow_buffer = 0;
01630 if (flags != orig_flags) {
01631 flags = orig_flags;
01632 rsock_discard_cmsg_resource(&mh);
01633 goto retry;
01634 }
01635 }
01636 }
01637
01638 if (NIL_P(dat_str))
01639 dat_str = rb_tainted_str_new(datbuf, ss);
01640 else {
01641 rb_str_resize(dat_str, ss);
01642 OBJ_TAINT(dat_str);
01643 RBASIC(dat_str)->klass = rb_cString;
01644 }
01645
01646 ret = rb_ary_new3(3, dat_str,
01647 rsock_io_socket_addrinfo(sock, mh.msg_name, mh.msg_namelen),
01648 #if defined(HAVE_ST_MSG_CONTROL)
01649 INT2NUM(mh.msg_flags)
01650 #else
01651 Qnil
01652 #endif
01653 );
01654
01655 #if defined(HAVE_ST_MSG_CONTROL)
01656 family = rsock_getfamily(fptr->fd);
01657 if (mh.msg_controllen) {
01658 char *msg_end = (char *)mh.msg_control + mh.msg_controllen;
01659 for (cmh = CMSG_FIRSTHDR(&mh); cmh != NULL; cmh = CMSG_NXTHDR(&mh, cmh)) {
01660 VALUE ctl;
01661 char *ctl_end;
01662 size_t clen;
01663 if (cmh->cmsg_len == 0) {
01664 rb_raise(rb_eTypeError, "invalid control message (cmsg_len == 0)");
01665 }
01666 ctl_end = (char*)cmh + cmh->cmsg_len;
01667 clen = (ctl_end <= msg_end ? ctl_end : msg_end) - (char*)CMSG_DATA(cmh);
01668 ctl = ancdata_new(family, cmh->cmsg_level, cmh->cmsg_type, rb_tainted_str_new((char*)CMSG_DATA(cmh), clen));
01669 if (request_scm_rights)
01670 make_io_for_unix_rights(ctl, cmh, msg_end);
01671 else
01672 discard_cmsg(cmh, msg_end);
01673 rb_ary_push(ret, ctl);
01674 }
01675 }
01676 #endif
01677
01678 return ret;
01679 }
01680 #endif
01681
01682 #if defined(HAVE_RECVMSG)
01683
01684
01685
01686
01687
01688
01689
01690
01691
01692
01693
01694
01695
01696
01697
01698
01699
01700
01701
01702
01703
01704
01705
01706
01707
01708
01709
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 VALUE
01737 rsock_bsock_recvmsg(int argc, VALUE *argv, VALUE sock)
01738 {
01739 return bsock_recvmsg_internal(argc, argv, sock, 0);
01740 }
01741 #endif
01742
01743 #if defined(HAVE_RECVMSG)
01744
01745
01746
01747
01748
01749
01750
01751
01752
01753
01754
01755 VALUE
01756 rsock_bsock_recvmsg_nonblock(int argc, VALUE *argv, VALUE sock)
01757 {
01758 return bsock_recvmsg_internal(argc, argv, sock, 1);
01759 }
01760 #endif
01761
01762
01763
01764
01765
01766
01767
01768
01769 void
01770 rsock_init_ancdata(void)
01771 {
01772 #if defined(HAVE_ST_MSG_CONTROL)
01773 rb_cAncillaryData = rb_define_class_under(rb_cSocket, "AncillaryData", rb_cObject);
01774 rb_define_method(rb_cAncillaryData, "initialize", ancillary_initialize, 4);
01775 rb_define_method(rb_cAncillaryData, "inspect", ancillary_inspect, 0);
01776 rb_define_method(rb_cAncillaryData, "family", ancillary_family_m, 0);
01777 rb_define_method(rb_cAncillaryData, "level", ancillary_level_m, 0);
01778 rb_define_method(rb_cAncillaryData, "type", ancillary_type_m, 0);
01779 rb_define_method(rb_cAncillaryData, "data", ancillary_data, 0);
01780
01781 rb_define_method(rb_cAncillaryData, "cmsg_is?", ancillary_cmsg_is_p, 2);
01782
01783 rb_define_singleton_method(rb_cAncillaryData, "int", ancillary_s_int, 4);
01784 rb_define_method(rb_cAncillaryData, "int", ancillary_int, 0);
01785
01786 rb_define_singleton_method(rb_cAncillaryData, "unix_rights", ancillary_s_unix_rights, -1);
01787 rb_define_method(rb_cAncillaryData, "unix_rights", ancillary_unix_rights, 0);
01788
01789 rb_define_method(rb_cAncillaryData, "timestamp", ancillary_timestamp, 0);
01790
01791 rb_define_singleton_method(rb_cAncillaryData, "ip_pktinfo", ancillary_s_ip_pktinfo, -1);
01792 rb_define_method(rb_cAncillaryData, "ip_pktinfo", ancillary_ip_pktinfo, 0);
01793
01794 rb_define_singleton_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_s_ipv6_pktinfo, 2);
01795 rb_define_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_ipv6_pktinfo, 0);
01796 rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_addr", ancillary_ipv6_pktinfo_addr, 0);
01797 rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_ifindex", ancillary_ipv6_pktinfo_ifindex, 0);
01798 #endif
01799 }
01800