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
00255 static VALUE
00256 ancillary_unix_rights(VALUE self)
00257 {
00258 int level, type;
00259
00260 level = ancillary_level(self);
00261 type = ancillary_type(self);
00262
00263 if (level != SOL_SOCKET || type != SCM_RIGHTS)
00264 rb_raise(rb_eTypeError, "SCM_RIGHTS ancillary data expected");
00265
00266 return rb_attr_get(self, rb_intern("unix_rights"));
00267 }
00268 #else
00269 #define ancillary_unix_rights rb_f_notimplement
00270 #endif
00271
00272 #if defined(SCM_TIMESTAMP) || defined(SCM_TIMESTAMPNS) || defined(SCM_BINTIME)
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
00298 static VALUE
00299 ancillary_timestamp(VALUE self)
00300 {
00301 int level, type;
00302 VALUE data;
00303 VALUE result = Qnil;
00304
00305 level = ancillary_level(self);
00306 type = ancillary_type(self);
00307 data = ancillary_data(self);
00308
00309 # ifdef SCM_TIMESTAMP
00310 if (level == SOL_SOCKET && type == SCM_TIMESTAMP &&
00311 RSTRING_LEN(data) == sizeof(struct timeval)) {
00312 struct timeval tv;
00313 memcpy((char*)&tv, RSTRING_PTR(data), sizeof(tv));
00314 result = rb_time_new(tv.tv_sec, tv.tv_usec);
00315 }
00316 # endif
00317
00318 # ifdef SCM_TIMESTAMPNS
00319 if (level == SOL_SOCKET && type == SCM_TIMESTAMPNS &&
00320 RSTRING_LEN(data) == sizeof(struct timespec)) {
00321 struct timespec ts;
00322 memcpy((char*)&ts, RSTRING_PTR(data), sizeof(ts));
00323 result = rb_time_nano_new(ts.tv_sec, ts.tv_nsec);
00324 }
00325 # endif
00326
00327 #define add(x,y) (rb_funcall((x), '+', 1, (y)))
00328 #define mul(x,y) (rb_funcall((x), '*', 1, (y)))
00329 #define quo(x,y) (rb_funcall((x), rb_intern("quo"), 1, (y)))
00330
00331 # ifdef SCM_BINTIME
00332 if (level == SOL_SOCKET && type == SCM_BINTIME &&
00333 RSTRING_LEN(data) == sizeof(struct bintime)) {
00334 struct bintime bt;
00335 VALUE d, timev;
00336 memcpy((char*)&bt, RSTRING_PTR(data), sizeof(bt));
00337 d = ULL2NUM(0x100000000ULL);
00338 d = mul(d,d);
00339 timev = add(TIMET2NUM(bt.sec), quo(ULL2NUM(bt.frac), d));
00340 result = rb_time_num_new(timev, Qnil);
00341 }
00342 # endif
00343
00344 if (result == Qnil)
00345 rb_raise(rb_eTypeError, "timestamp ancillary data expected");
00346
00347 return result;
00348 }
00349 #else
00350 #define ancillary_timestamp rb_f_notimplement
00351 #endif
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364 static VALUE
00365 ancillary_s_int(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE vtype, VALUE integer)
00366 {
00367 int family = rsock_family_arg(vfamily);
00368 int level = rsock_level_arg(family, vlevel);
00369 int type = rsock_cmsg_type_arg(family, level, vtype);
00370 int i = NUM2INT(integer);
00371 return ancdata_new(family, level, type, rb_str_new((char*)&i, sizeof(i)));
00372 }
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385 static VALUE
00386 ancillary_int(VALUE self)
00387 {
00388 VALUE data;
00389 int i;
00390 data = ancillary_data(self);
00391 if (RSTRING_LEN(data) != sizeof(int))
00392 rb_raise(rb_eTypeError, "size differ. expected as sizeof(int)=%d but %ld", (int)sizeof(int), (long)RSTRING_LEN(data));
00393 memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
00394 return INT2NUM(i);
00395 }
00396
00397 #if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST)
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418 static VALUE
00419 ancillary_s_ip_pktinfo(int argc, VALUE *argv, VALUE self)
00420 {
00421 VALUE v_addr, v_ifindex, v_spec_dst;
00422 unsigned int ifindex;
00423 struct sockaddr_in sa;
00424 struct in_pktinfo pktinfo;
00425
00426 rb_scan_args(argc, argv, "21", &v_addr, &v_ifindex, &v_spec_dst);
00427
00428 SockAddrStringValue(v_addr);
00429 ifindex = NUM2UINT(v_ifindex);
00430 if (NIL_P(v_spec_dst))
00431 v_spec_dst = v_addr;
00432 else
00433 SockAddrStringValue(v_spec_dst);
00434
00435 memset(&pktinfo, 0, sizeof(pktinfo));
00436
00437 memset(&sa, 0, sizeof(sa));
00438 if (RSTRING_LEN(v_addr) != sizeof(sa))
00439 rb_raise(rb_eArgError, "addr size different to AF_INET sockaddr");
00440 memcpy(&sa, RSTRING_PTR(v_addr), sizeof(sa));
00441 if (sa.sin_family != AF_INET)
00442 rb_raise(rb_eArgError, "addr is not AF_INET sockaddr");
00443 memcpy(&pktinfo.ipi_addr, &sa.sin_addr, sizeof(pktinfo.ipi_addr));
00444
00445 pktinfo.ipi_ifindex = ifindex;
00446
00447 memset(&sa, 0, sizeof(sa));
00448 if (RSTRING_LEN(v_spec_dst) != sizeof(sa))
00449 rb_raise(rb_eArgError, "spec_dat size different to AF_INET sockaddr");
00450 memcpy(&sa, RSTRING_PTR(v_spec_dst), sizeof(sa));
00451 if (sa.sin_family != AF_INET)
00452 rb_raise(rb_eArgError, "spec_dst is not AF_INET sockaddr");
00453 memcpy(&pktinfo.ipi_spec_dst, &sa.sin_addr, sizeof(pktinfo.ipi_spec_dst));
00454
00455 return ancdata_new(AF_INET, IPPROTO_IP, IP_PKTINFO, rb_str_new((char *)&pktinfo, sizeof(pktinfo)));
00456 }
00457 #else
00458 #define ancillary_s_ip_pktinfo rb_f_notimplement
00459 #endif
00460
00461 #if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST)
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481 static VALUE
00482 ancillary_ip_pktinfo(VALUE self)
00483 {
00484 int level, type;
00485 VALUE data;
00486 struct in_pktinfo pktinfo;
00487 struct sockaddr_in sa;
00488 VALUE v_spec_dst, v_addr;
00489
00490 level = ancillary_level(self);
00491 type = ancillary_type(self);
00492 data = ancillary_data(self);
00493
00494 if (level != IPPROTO_IP || type != IP_PKTINFO ||
00495 RSTRING_LEN(data) != sizeof(struct in_pktinfo)) {
00496 rb_raise(rb_eTypeError, "IP_PKTINFO ancillary data expected");
00497 }
00498
00499 memcpy(&pktinfo, RSTRING_PTR(data), sizeof(struct in_pktinfo));
00500 memset(&sa, 0, sizeof(sa));
00501
00502 sa.sin_family = AF_INET;
00503 memcpy(&sa.sin_addr, &pktinfo.ipi_addr, sizeof(sa.sin_addr));
00504 v_addr = rsock_addrinfo_new((struct sockaddr *)&sa, sizeof(sa), PF_INET, 0, 0, Qnil, Qnil);
00505
00506 sa.sin_family = AF_INET;
00507 memcpy(&sa.sin_addr, &pktinfo.ipi_spec_dst, sizeof(sa.sin_addr));
00508 v_spec_dst = rsock_addrinfo_new((struct sockaddr *)&sa, sizeof(sa), PF_INET, 0, 0, Qnil, Qnil);
00509
00510 return rb_ary_new3(3, v_addr, UINT2NUM(pktinfo.ipi_ifindex), v_spec_dst);
00511 }
00512 #else
00513 #define ancillary_ip_pktinfo rb_f_notimplement
00514 #endif
00515
00516 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531 static VALUE
00532 ancillary_s_ipv6_pktinfo(VALUE self, VALUE v_addr, VALUE v_ifindex)
00533 {
00534 unsigned int ifindex;
00535 struct sockaddr_in6 sa;
00536 struct in6_pktinfo pktinfo;
00537
00538 SockAddrStringValue(v_addr);
00539 ifindex = NUM2UINT(v_ifindex);
00540
00541 memset(&pktinfo, 0, sizeof(pktinfo));
00542
00543 memset(&sa, 0, sizeof(sa));
00544 if (RSTRING_LEN(v_addr) != sizeof(sa))
00545 rb_raise(rb_eArgError, "addr size different to AF_INET6 sockaddr");
00546 memcpy(&sa, RSTRING_PTR(v_addr), sizeof(sa));
00547 if (sa.sin6_family != AF_INET6)
00548 rb_raise(rb_eArgError, "addr is not AF_INET6 sockaddr");
00549 memcpy(&pktinfo.ipi6_addr, &sa.sin6_addr, sizeof(pktinfo.ipi6_addr));
00550
00551 pktinfo.ipi6_ifindex = ifindex;
00552
00553 return ancdata_new(AF_INET6, IPPROTO_IPV6, IPV6_PKTINFO, rb_str_new((char *)&pktinfo, sizeof(pktinfo)));
00554 }
00555 #else
00556 #define ancillary_s_ipv6_pktinfo rb_f_notimplement
00557 #endif
00558
00559 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)
00560 static void
00561 extract_ipv6_pktinfo(VALUE self, struct in6_pktinfo *pktinfo_ptr, struct sockaddr_in6 *sa_ptr)
00562 {
00563 int level, type;
00564 VALUE data;
00565
00566 level = ancillary_level(self);
00567 type = ancillary_type(self);
00568 data = ancillary_data(self);
00569
00570 if (level != IPPROTO_IPV6 || type != IPV6_PKTINFO ||
00571 RSTRING_LEN(data) != sizeof(struct in6_pktinfo)) {
00572 rb_raise(rb_eTypeError, "IPV6_PKTINFO ancillary data expected");
00573 }
00574
00575 memcpy(pktinfo_ptr, RSTRING_PTR(data), sizeof(*pktinfo_ptr));
00576
00577 memset(sa_ptr, 0, sizeof(*sa_ptr));
00578 SET_SA_LEN((struct sockaddr *)sa_ptr, sizeof(struct sockaddr_in6));
00579 sa_ptr->sin6_family = AF_INET6;
00580 memcpy(&sa_ptr->sin6_addr, &pktinfo_ptr->ipi6_addr, sizeof(sa_ptr->sin6_addr));
00581 if (IN6_IS_ADDR_LINKLOCAL(&sa_ptr->sin6_addr))
00582 sa_ptr->sin6_scope_id = pktinfo_ptr->ipi6_ifindex;
00583 }
00584 #endif
00585
00586 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601 static VALUE
00602 ancillary_ipv6_pktinfo(VALUE self)
00603 {
00604 struct in6_pktinfo pktinfo;
00605 struct sockaddr_in6 sa;
00606 VALUE v_addr;
00607
00608 extract_ipv6_pktinfo(self, &pktinfo, &sa);
00609 v_addr = rsock_addrinfo_new((struct sockaddr *)&sa, (socklen_t)sizeof(sa), PF_INET6, 0, 0, Qnil, Qnil);
00610 return rb_ary_new3(2, v_addr, UINT2NUM(pktinfo.ipi6_ifindex));
00611 }
00612 #else
00613 #define ancillary_ipv6_pktinfo rb_f_notimplement
00614 #endif
00615
00616 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631 static VALUE
00632 ancillary_ipv6_pktinfo_addr(VALUE self)
00633 {
00634 struct in6_pktinfo pktinfo;
00635 struct sockaddr_in6 sa;
00636 extract_ipv6_pktinfo(self, &pktinfo, &sa);
00637 return rsock_addrinfo_new((struct sockaddr *)&sa, (socklen_t)sizeof(sa), PF_INET6, 0, 0, Qnil, Qnil);
00638 }
00639 #else
00640 #define ancillary_ipv6_pktinfo_addr rb_f_notimplement
00641 #endif
00642
00643 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658 static VALUE
00659 ancillary_ipv6_pktinfo_ifindex(VALUE self)
00660 {
00661 struct in6_pktinfo pktinfo;
00662 struct sockaddr_in6 sa;
00663 extract_ipv6_pktinfo(self, &pktinfo, &sa);
00664 return UINT2NUM(pktinfo.ipi6_ifindex);
00665 }
00666 #else
00667 #define ancillary_ipv6_pktinfo_ifindex rb_f_notimplement
00668 #endif
00669
00670 #if defined(SOL_SOCKET) && defined(SCM_RIGHTS)
00671 static int
00672 anc_inspect_socket_rights(int level, int type, VALUE data, VALUE ret)
00673 {
00674 if (level == SOL_SOCKET && type == SCM_RIGHTS &&
00675 0 < RSTRING_LEN(data) && (RSTRING_LEN(data) % sizeof(int) == 0)) {
00676 long off;
00677 for (off = 0; off < RSTRING_LEN(data); off += sizeof(int)) {
00678 int fd;
00679 memcpy((char*)&fd, RSTRING_PTR(data)+off, sizeof(int));
00680 rb_str_catf(ret, " %d", fd);
00681 }
00682 return 1;
00683 }
00684 else {
00685 return 0;
00686 }
00687 }
00688 #endif
00689
00690 #if defined(SCM_CREDENTIALS)
00691 static int
00692 anc_inspect_passcred_credentials(int level, int type, VALUE data, VALUE ret)
00693 {
00694 if (level == SOL_SOCKET && type == SCM_CREDENTIALS &&
00695 RSTRING_LEN(data) == sizeof(struct ucred)) {
00696 struct ucred cred;
00697 memcpy(&cred, RSTRING_PTR(data), sizeof(struct ucred));
00698 rb_str_catf(ret, " pid=%u uid=%u gid=%u", cred.pid, cred.uid, cred.gid);
00699 rb_str_cat2(ret, " (ucred)");
00700 return 1;
00701 }
00702 else {
00703 return 0;
00704 }
00705 }
00706 #endif
00707
00708 #if defined(SCM_CREDS)
00709 #define INSPECT_SCM_CREDS
00710 static int
00711 anc_inspect_socket_creds(int level, int type, VALUE data, VALUE ret)
00712 {
00713 if (level != SOL_SOCKET && type != SCM_CREDS)
00714 return 0;
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727 #if defined(HAVE_TYPE_STRUCT_CMSGCRED)
00728 if (RSTRING_LEN(data) == sizeof(struct cmsgcred)) {
00729 struct cmsgcred cred;
00730 memcpy(&cred, RSTRING_PTR(data), sizeof(struct cmsgcred));
00731 rb_str_catf(ret, " pid=%u", cred.cmcred_pid);
00732 rb_str_catf(ret, " uid=%u", cred.cmcred_uid);
00733 rb_str_catf(ret, " euid=%u", cred.cmcred_euid);
00734 rb_str_catf(ret, " gid=%u", cred.cmcred_gid);
00735 if (cred.cmcred_ngroups) {
00736 int i;
00737 const char *sep = " groups=";
00738 for (i = 0; i < cred.cmcred_ngroups; i++) {
00739 rb_str_catf(ret, "%s%u", sep, cred.cmcred_groups[i]);
00740 sep = ",";
00741 }
00742 }
00743 rb_str_cat2(ret, " (cmsgcred)");
00744 return 1;
00745 }
00746 #endif
00747 #if defined(HAVE_TYPE_STRUCT_SOCKCRED)
00748 if ((size_t)RSTRING_LEN(data) >= SOCKCREDSIZE(0)) {
00749 struct sockcred cred0, *cred;
00750 memcpy(&cred0, RSTRING_PTR(data), SOCKCREDSIZE(0));
00751 if ((size_t)RSTRING_LEN(data) == SOCKCREDSIZE(cred0.sc_ngroups)) {
00752 cred = (struct sockcred *)ALLOCA_N(char, SOCKCREDSIZE(cred0.sc_ngroups));
00753 memcpy(cred, RSTRING_PTR(data), SOCKCREDSIZE(cred0.sc_ngroups));
00754 rb_str_catf(ret, " uid=%u", cred->sc_uid);
00755 rb_str_catf(ret, " euid=%u", cred->sc_euid);
00756 rb_str_catf(ret, " gid=%u", cred->sc_gid);
00757 rb_str_catf(ret, " egid=%u", cred->sc_egid);
00758 if (cred0.sc_ngroups) {
00759 int i;
00760 const char *sep = " groups=";
00761 for (i = 0; i < cred0.sc_ngroups; i++) {
00762 rb_str_catf(ret, "%s%u", sep, cred->sc_groups[i]);
00763 sep = ",";
00764 }
00765 }
00766 rb_str_cat2(ret, " (sockcred)");
00767 return 1;
00768 }
00769 }
00770 #endif
00771 return 0;
00772 }
00773 #endif
00774
00775 #if defined(IPPROTO_IP) && defined(IP_RECVDSTADDR)
00776 static int
00777 anc_inspect_ip_recvdstaddr(int level, int type, VALUE data, VALUE ret)
00778 {
00779 if (level == IPPROTO_IP && type == IP_RECVDSTADDR &&
00780 RSTRING_LEN(data) == sizeof(struct in_addr)) {
00781 struct in_addr addr;
00782 char addrbuf[INET_ADDRSTRLEN];
00783 memcpy(&addr, RSTRING_PTR(data), sizeof(addr));
00784 if (inet_ntop(AF_INET, &addr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
00785 rb_str_cat2(ret, " invalid-address");
00786 else
00787 rb_str_catf(ret, " %s", addrbuf);
00788 return 1;
00789 }
00790 else {
00791 return 0;
00792 }
00793 }
00794 #endif
00795
00796 #if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST)
00797 static int
00798 anc_inspect_ip_pktinfo(int level, int type, VALUE data, VALUE ret)
00799 {
00800 if (level == IPPROTO_IP && type == IP_PKTINFO &&
00801 RSTRING_LEN(data) == sizeof(struct in_pktinfo)) {
00802 struct in_pktinfo pktinfo;
00803 char buf[INET_ADDRSTRLEN > IFNAMSIZ ? INET_ADDRSTRLEN : IFNAMSIZ];
00804 memcpy(&pktinfo, RSTRING_PTR(data), sizeof(pktinfo));
00805 if (inet_ntop(AF_INET, &pktinfo.ipi_addr, buf, sizeof(buf)) == NULL)
00806 rb_str_cat2(ret, " invalid-address");
00807 else
00808 rb_str_catf(ret, " %s", buf);
00809 if (if_indextoname(pktinfo.ipi_ifindex, buf) == NULL)
00810 rb_str_catf(ret, " ifindex:%d", pktinfo.ipi_ifindex);
00811 else
00812 rb_str_catf(ret, " %s", buf);
00813 if (inet_ntop(AF_INET, &pktinfo.ipi_spec_dst, buf, sizeof(buf)) == NULL)
00814 rb_str_cat2(ret, " spec_dst:invalid-address");
00815 else
00816 rb_str_catf(ret, " spec_dst:%s", buf);
00817 return 1;
00818 }
00819 else {
00820 return 0;
00821 }
00822 }
00823 #endif
00824
00825 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) && defined(HAVE_TYPE_STRUCT_IN6_PKTINFO)
00826 static int
00827 anc_inspect_ipv6_pktinfo(int level, int type, VALUE data, VALUE ret)
00828 {
00829 if (level == IPPROTO_IPV6 && type == IPV6_PKTINFO &&
00830 RSTRING_LEN(data) == sizeof(struct in6_pktinfo)) {
00831 struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)RSTRING_PTR(data);
00832 struct in6_addr addr;
00833 unsigned int ifindex;
00834 char addrbuf[INET6_ADDRSTRLEN], ifbuf[IFNAMSIZ];
00835 memcpy(&addr, &pktinfo->ipi6_addr, sizeof(addr));
00836 memcpy(&ifindex, &pktinfo->ipi6_ifindex, sizeof(ifindex));
00837 if (inet_ntop(AF_INET6, &addr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
00838 rb_str_cat2(ret, " invalid-address");
00839 else
00840 rb_str_catf(ret, " %s", addrbuf);
00841 if (if_indextoname(ifindex, ifbuf) == NULL)
00842 rb_str_catf(ret, " ifindex:%d", ifindex);
00843 else
00844 rb_str_catf(ret, " %s", ifbuf);
00845 return 1;
00846 }
00847 else {
00848 return 0;
00849 }
00850 }
00851 #endif
00852
00853 #if defined(SCM_TIMESTAMP)
00854 static int
00855 inspect_timeval_as_abstime(int level, int optname, VALUE data, VALUE ret)
00856 {
00857 if (RSTRING_LEN(data) == sizeof(struct timeval)) {
00858 struct timeval tv;
00859 time_t time;
00860 struct tm tm;
00861 char buf[32];
00862 memcpy((char*)&tv, RSTRING_PTR(data), sizeof(tv));
00863 time = tv.tv_sec;
00864 tm = *localtime(&time);
00865 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
00866 rb_str_catf(ret, " %s.%06ld", buf, (long)tv.tv_usec);
00867 return 1;
00868 }
00869 else {
00870 return 0;
00871 }
00872 }
00873 #endif
00874
00875 #if defined(SCM_TIMESTAMPNS)
00876 static int
00877 inspect_timespec_as_abstime(int level, int optname, VALUE data, VALUE ret)
00878 {
00879 if (RSTRING_LEN(data) == sizeof(struct timespec)) {
00880 struct timespec ts;
00881 struct tm tm;
00882 char buf[32];
00883 memcpy((char*)&ts, RSTRING_PTR(data), sizeof(ts));
00884 tm = *localtime(&ts.tv_sec);
00885 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
00886 rb_str_catf(ret, " %s.%09ld", buf, (long)ts.tv_nsec);
00887 return 1;
00888 }
00889 else {
00890 return 0;
00891 }
00892 }
00893 #endif
00894
00895 #if defined(SCM_BINTIME)
00896 static int
00897 inspect_bintime_as_abstime(int level, int optname, VALUE data, VALUE ret)
00898 {
00899 if (RSTRING_LEN(data) == sizeof(struct bintime)) {
00900 struct bintime bt;
00901 struct tm tm;
00902 uint64_t frac_h, frac_l;
00903 uint64_t scale_h, scale_l;
00904 uint64_t tmp1, tmp2;
00905 uint64_t res_h, res_l;
00906 char buf[32];
00907 memcpy((char*)&bt, RSTRING_PTR(data), sizeof(bt));
00908 tm = *localtime(&bt.sec);
00909 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
00910
00911
00912
00913 frac_h = bt.frac >> 32;
00914 frac_l = bt.frac & 0xffffffff;
00915
00916 scale_h = 0x8ac72304;
00917 scale_l = 0x89e80000;
00918
00919 res_h = frac_h * scale_h;
00920 res_l = frac_l * scale_l;
00921
00922 tmp1 = frac_h * scale_l;
00923 res_h += tmp1 >> 32;
00924 tmp2 = res_l;
00925 res_l += tmp1 & 0xffffffff;
00926 if (res_l < tmp2) res_h++;
00927
00928 tmp1 = frac_l * scale_h;
00929 res_h += tmp1 >> 32;
00930 tmp2 = res_l;
00931 res_l += tmp1 & 0xffffffff;
00932 if (res_l < tmp2) res_h++;
00933
00934 rb_str_catf(ret, " %s.%019"PRIu64, buf, res_h);
00935 return 1;
00936 }
00937 else {
00938 return 0;
00939 }
00940 }
00941 #endif
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952 static VALUE
00953 ancillary_inspect(VALUE self)
00954 {
00955 VALUE ret;
00956 int family, level, type;
00957 VALUE data;
00958 ID family_id, level_id, type_id;
00959 VALUE vtype;
00960 int inspected;
00961
00962 family = ancillary_family(self);
00963 level = ancillary_level(self);
00964 type = ancillary_type(self);
00965 data = ancillary_data(self);
00966
00967 ret = rb_sprintf("#<%s:", rb_obj_classname(self));
00968
00969 family_id = rsock_intern_family_noprefix(family);
00970 if (family_id)
00971 rb_str_catf(ret, " %s", rb_id2name(family_id));
00972 else
00973 rb_str_catf(ret, " family:%d", family);
00974
00975 if (level == SOL_SOCKET) {
00976 rb_str_cat2(ret, " SOCKET");
00977
00978 type_id = rsock_intern_scm_optname(type);
00979 if (type_id)
00980 rb_str_catf(ret, " %s", rb_id2name(type_id));
00981 else
00982 rb_str_catf(ret, " cmsg_type:%d", type);
00983 }
00984 else if (IS_IP_FAMILY(family)) {
00985 level_id = rsock_intern_iplevel(level);
00986 if (level_id)
00987 rb_str_catf(ret, " %s", rb_id2name(level_id));
00988 else
00989 rb_str_catf(ret, " cmsg_level:%d", level);
00990
00991 vtype = ip_cmsg_type_to_sym(level, type);
00992 if (SYMBOL_P(vtype))
00993 rb_str_catf(ret, " %s", rb_id2name(SYM2ID(vtype)));
00994 else
00995 rb_str_catf(ret, " cmsg_type:%d", type);
00996 }
00997 else {
00998 rb_str_catf(ret, " cmsg_level:%d", level);
00999 rb_str_catf(ret, " cmsg_type:%d", type);
01000 }
01001
01002 inspected = 0;
01003
01004 if (level == SOL_SOCKET)
01005 family = AF_UNSPEC;
01006
01007 switch (family) {
01008 case AF_UNSPEC:
01009 switch (level) {
01010 # if defined(SOL_SOCKET)
01011 case SOL_SOCKET:
01012 switch (type) {
01013 # if defined(SCM_TIMESTAMP)
01014 case SCM_TIMESTAMP: inspected = inspect_timeval_as_abstime(level, type, data, ret); break;
01015 # endif
01016 # if defined(SCM_TIMESTAMPNS)
01017 case SCM_TIMESTAMPNS: inspected = inspect_timespec_as_abstime(level, type, data, ret); break;
01018 # endif
01019 # if defined(SCM_BINTIME)
01020 case SCM_BINTIME: inspected = inspect_bintime_as_abstime(level, type, data, ret); break;
01021 # endif
01022 # if defined(SCM_RIGHTS)
01023 case SCM_RIGHTS: inspected = anc_inspect_socket_rights(level, type, data, ret); break;
01024 # endif
01025 # if defined(SCM_CREDENTIALS)
01026 case SCM_CREDENTIALS: inspected = anc_inspect_passcred_credentials(level, type, data, ret); break;
01027 # endif
01028 # if defined(INSPECT_SCM_CREDS)
01029 case SCM_CREDS: inspected = anc_inspect_socket_creds(level, type, data, ret); break;
01030 # endif
01031 }
01032 break;
01033 # endif
01034 }
01035 break;
01036
01037 case AF_INET:
01038 #ifdef INET6
01039 case AF_INET6:
01040 #endif
01041 switch (level) {
01042 # if defined(IPPROTO_IP)
01043 case IPPROTO_IP:
01044 switch (type) {
01045 # if defined(IP_RECVDSTADDR)
01046 case IP_RECVDSTADDR: inspected = anc_inspect_ip_recvdstaddr(level, type, data, ret); break;
01047 # endif
01048 # if defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST)
01049 case IP_PKTINFO: inspected = anc_inspect_ip_pktinfo(level, type, data, ret); break;
01050 # endif
01051 }
01052 break;
01053 # endif
01054
01055 # if defined(IPPROTO_IPV6)
01056 case IPPROTO_IPV6:
01057 switch (type) {
01058 # if defined(IPV6_PKTINFO)
01059 case IPV6_PKTINFO: inspected = anc_inspect_ipv6_pktinfo(level, type, data, ret); break;
01060 # endif
01061 }
01062 break;
01063 # endif
01064 }
01065 break;
01066 }
01067
01068 if (!inspected) {
01069 rb_str_cat2(ret, " ");
01070 rb_str_append(ret, rb_str_dump(data));
01071 }
01072
01073 rb_str_cat2(ret, ">");
01074
01075 return ret;
01076 }
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090 static VALUE
01091 ancillary_cmsg_is_p(VALUE self, VALUE vlevel, VALUE vtype)
01092 {
01093 int family = ancillary_family(self);
01094 int level = rsock_level_arg(family, vlevel);
01095 int type = rsock_cmsg_type_arg(family, level, vtype);
01096
01097 if (ancillary_level(self) == level &&
01098 ancillary_type(self) == type)
01099 return Qtrue;
01100 else
01101 return Qfalse;
01102 }
01103
01104 #endif
01105
01106 #if defined(HAVE_SENDMSG)
01107 struct sendmsg_args_struct {
01108 int fd;
01109 const struct msghdr *msg;
01110 int flags;
01111 };
01112
01113 static VALUE
01114 nogvl_sendmsg_func(void *ptr)
01115 {
01116 struct sendmsg_args_struct *args = ptr;
01117 return sendmsg(args->fd, args->msg, args->flags);
01118 }
01119
01120 static ssize_t
01121 rb_sendmsg(int fd, const struct msghdr *msg, int flags)
01122 {
01123 struct sendmsg_args_struct args;
01124 args.fd = fd;
01125 args.msg = msg;
01126 args.flags = flags;
01127 return rb_thread_blocking_region(nogvl_sendmsg_func, &args, RUBY_UBF_IO, 0);
01128 }
01129
01130 static VALUE
01131 bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
01132 {
01133 rb_io_t *fptr;
01134 VALUE data, vflags, dest_sockaddr;
01135 VALUE *controls_ptr;
01136 int controls_num;
01137 struct msghdr mh;
01138 struct iovec iov;
01139 #if defined(HAVE_ST_MSG_CONTROL)
01140 volatile VALUE controls_str = 0;
01141 #endif
01142 int flags;
01143 ssize_t ss;
01144 int family;
01145
01146 rb_secure(4);
01147 GetOpenFile(sock, fptr);
01148 family = rsock_getfamily(fptr->fd);
01149
01150 data = vflags = dest_sockaddr = Qnil;
01151 controls_ptr = NULL;
01152 controls_num = 0;
01153
01154 if (argc == 0)
01155 rb_raise(rb_eArgError, "mesg argument required");
01156 data = argv[0];
01157 if (1 < argc) vflags = argv[1];
01158 if (2 < argc) dest_sockaddr = argv[2];
01159 if (3 < argc) { controls_ptr = &argv[3]; controls_num = argc - 3; }
01160
01161 StringValue(data);
01162
01163 if (controls_num) {
01164 #if defined(HAVE_ST_MSG_CONTROL)
01165 int i;
01166 size_t last_pad = 0;
01167 int last_level = 0;
01168 int last_type = 0;
01169 controls_str = rb_str_tmp_new(0);
01170 for (i = 0; i < controls_num; i++) {
01171 VALUE elt = controls_ptr[i], v;
01172 VALUE vlevel, vtype;
01173 int level, type;
01174 VALUE cdata;
01175 long oldlen;
01176 struct cmsghdr cmh;
01177 char *cmsg;
01178 size_t cspace;
01179 v = rb_check_convert_type(elt, T_ARRAY, "Array", "to_ary");
01180 if (!NIL_P(v)) {
01181 elt = v;
01182 if (RARRAY_LEN(elt) != 3)
01183 rb_raise(rb_eArgError, "an element of controls should be 3-elements array");
01184 vlevel = rb_ary_entry(elt, 0);
01185 vtype = rb_ary_entry(elt, 1);
01186 cdata = rb_ary_entry(elt, 2);
01187 }
01188 else {
01189 vlevel = rb_funcall(elt, rb_intern("level"), 0);
01190 vtype = rb_funcall(elt, rb_intern("type"), 0);
01191 cdata = rb_funcall(elt, rb_intern("data"), 0);
01192 }
01193 level = rsock_level_arg(family, vlevel);
01194 type = rsock_cmsg_type_arg(family, level, vtype);
01195 StringValue(cdata);
01196 oldlen = RSTRING_LEN(controls_str);
01197 cspace = CMSG_SPACE(RSTRING_LEN(cdata));
01198 rb_str_resize(controls_str, oldlen + cspace);
01199 cmsg = RSTRING_PTR(controls_str)+oldlen;
01200 memset((char *)cmsg, 0, cspace);
01201 memset((char *)&cmh, 0, sizeof(cmh));
01202 cmh.cmsg_level = level;
01203 cmh.cmsg_type = type;
01204 cmh.cmsg_len = (socklen_t)CMSG_LEN(RSTRING_LEN(cdata));
01205 MEMCPY(cmsg, &cmh, char, sizeof(cmh));
01206 MEMCPY(cmsg+((char*)CMSG_DATA(&cmh)-(char*)&cmh), RSTRING_PTR(cdata), char, RSTRING_LEN(cdata));
01207 last_level = cmh.cmsg_level;
01208 last_type = cmh.cmsg_type;
01209 last_pad = cspace - cmh.cmsg_len;
01210 }
01211 if (last_pad) {
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232 #if defined(__NetBSD__)
01233 if (last_level == SOL_SOCKET && last_type == SCM_RIGHTS)
01234 rb_str_set_len(controls_str, RSTRING_LEN(controls_str)-last_pad);
01235 #endif
01236 }
01237 #else
01238 rb_raise(rb_eNotImpError, "control message for sendmsg is unimplemented");
01239 #endif
01240 }
01241
01242 flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
01243 #ifdef MSG_DONTWAIT
01244 if (nonblock)
01245 flags |= MSG_DONTWAIT;
01246 #endif
01247
01248 if (!NIL_P(dest_sockaddr))
01249 SockAddrStringValue(dest_sockaddr);
01250
01251 rb_io_check_closed(fptr);
01252
01253 retry:
01254 memset(&mh, 0, sizeof(mh));
01255 if (!NIL_P(dest_sockaddr)) {
01256 mh.msg_name = RSTRING_PTR(dest_sockaddr);
01257 mh.msg_namelen = RSTRING_LENINT(dest_sockaddr);
01258 }
01259 mh.msg_iovlen = 1;
01260 mh.msg_iov = &iov;
01261 iov.iov_base = RSTRING_PTR(data);
01262 iov.iov_len = RSTRING_LEN(data);
01263 #if defined(HAVE_ST_MSG_CONTROL)
01264 if (controls_str) {
01265 mh.msg_control = RSTRING_PTR(controls_str);
01266 mh.msg_controllen = RSTRING_LENINT(controls_str);
01267 }
01268 else {
01269 mh.msg_control = NULL;
01270 mh.msg_controllen = 0;
01271 }
01272 #endif
01273
01274 rb_io_check_closed(fptr);
01275 if (nonblock)
01276 rb_io_set_nonblock(fptr);
01277
01278 ss = rb_sendmsg(fptr->fd, &mh, flags);
01279
01280 if (ss == -1) {
01281 if (!nonblock && rb_io_wait_writable(fptr->fd)) {
01282 rb_io_check_closed(fptr);
01283 goto retry;
01284 }
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, int msg_peek_p)
01380 {
01381 # if !defined(FD_PASSING_WORK_WITH_RECVMSG_MSG_PEEK)
01382
01383
01384
01385
01386
01387
01388
01389
01390 if (msg_peek_p)
01391 return;
01392 # endif
01393 if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
01394 int *fdp = (int *)CMSG_DATA(cmh);
01395 int *end = (int *)((char *)cmh + cmh->cmsg_len);
01396 while ((char *)fdp + sizeof(int) <= (char *)end &&
01397 (char *)fdp + sizeof(int) <= msg_end) {
01398 rb_update_max_fd(*fdp);
01399 close(*fdp);
01400 fdp++;
01401 }
01402 }
01403 }
01404 #endif
01405
01406 void
01407 rsock_discard_cmsg_resource(struct msghdr *mh, int msg_peek_p)
01408 {
01409 #if defined(HAVE_ST_MSG_CONTROL)
01410 struct cmsghdr *cmh;
01411 char *msg_end;
01412
01413 if (mh->msg_controllen == 0)
01414 return;
01415
01416 msg_end = (char *)mh->msg_control + mh->msg_controllen;
01417
01418 for (cmh = CMSG_FIRSTHDR(mh); cmh != NULL; cmh = CMSG_NXTHDR(mh, cmh)) {
01419 discard_cmsg(cmh, msg_end, msg_peek_p);
01420 }
01421 #endif
01422 }
01423
01424 #if defined(HAVE_ST_MSG_CONTROL)
01425 static void
01426 make_io_for_unix_rights(VALUE ctl, struct cmsghdr *cmh, char *msg_end)
01427 {
01428 if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
01429 int *fdp, *end;
01430 VALUE ary = rb_ary_new();
01431 rb_ivar_set(ctl, rb_intern("unix_rights"), ary);
01432 fdp = (int *)CMSG_DATA(cmh);
01433 end = (int *)((char *)cmh + cmh->cmsg_len);
01434 while ((char *)fdp + sizeof(int) <= (char *)end &&
01435 (char *)fdp + sizeof(int) <= msg_end) {
01436 int fd = *fdp;
01437 struct stat stbuf;
01438 VALUE io;
01439 if (fstat(fd, &stbuf) == -1)
01440 rb_raise(rb_eSocket, "invalid fd in SCM_RIGHTS");
01441 rb_update_max_fd(fd);
01442 if (S_ISSOCK(stbuf.st_mode))
01443 io = rsock_init_sock(rb_obj_alloc(rb_cSocket), fd);
01444 else
01445 io = rb_io_fdopen(fd, O_RDWR, NULL);
01446 ary = rb_attr_get(ctl, rb_intern("unix_rights"));
01447 rb_ary_push(ary, io);
01448 fdp++;
01449 }
01450 OBJ_FREEZE(ary);
01451 }
01452 }
01453 #endif
01454
01455 static VALUE
01456 bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
01457 {
01458 rb_io_t *fptr;
01459 VALUE vmaxdatlen, vmaxctllen, vflags, vopts;
01460 int grow_buffer;
01461 size_t maxdatlen;
01462 int flags, orig_flags;
01463 int request_scm_rights;
01464 struct msghdr mh;
01465 struct iovec iov;
01466 struct sockaddr_storage namebuf;
01467 char datbuf0[4096], *datbuf;
01468 VALUE dat_str = Qnil;
01469 VALUE ret;
01470 ssize_t ss;
01471 #if defined(HAVE_ST_MSG_CONTROL)
01472 struct cmsghdr *cmh;
01473 size_t maxctllen;
01474 union {
01475 char bytes[4096];
01476 struct cmsghdr align;
01477 } ctlbuf0;
01478 char *ctlbuf;
01479 VALUE ctl_str = Qnil;
01480 int family;
01481 int gc_done = 0;
01482 #endif
01483
01484 rb_secure(4);
01485
01486 vopts = Qnil;
01487 if (0 < argc && TYPE(argv[argc-1]) == T_HASH)
01488 vopts = argv[--argc];
01489
01490 rb_scan_args(argc, argv, "03", &vmaxdatlen, &vflags, &vmaxctllen);
01491
01492 maxdatlen = NIL_P(vmaxdatlen) ? sizeof(datbuf0) : NUM2SIZET(vmaxdatlen);
01493 #if defined(HAVE_ST_MSG_CONTROL)
01494 maxctllen = NIL_P(vmaxctllen) ? sizeof(ctlbuf0) : NUM2SIZET(vmaxctllen);
01495 #else
01496 if (!NIL_P(vmaxctllen))
01497 rb_raise(rb_eArgError, "control message not supported");
01498 #endif
01499 flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
01500 #ifdef MSG_DONTWAIT
01501 if (nonblock)
01502 flags |= MSG_DONTWAIT;
01503 #endif
01504 orig_flags = flags;
01505
01506 grow_buffer = NIL_P(vmaxdatlen) || NIL_P(vmaxctllen);
01507
01508 request_scm_rights = 0;
01509 if (!NIL_P(vopts) && RTEST(rb_hash_aref(vopts, ID2SYM(rb_intern("scm_rights")))))
01510 request_scm_rights = 1;
01511
01512 GetOpenFile(sock, fptr);
01513 if (rb_io_read_pending(fptr)) {
01514 rb_raise(rb_eIOError, "recvmsg for buffered IO");
01515 }
01516
01517 #if !defined(HAVE_ST_MSG_CONTROL)
01518 if (grow_buffer) {
01519 int socktype;
01520 socklen_t optlen = (socklen_t)sizeof(socktype);
01521 if (getsockopt(fptr->fd, SOL_SOCKET, SO_TYPE, (void*)&socktype, &optlen) == -1) {
01522 rb_sys_fail("getsockopt(SO_TYPE)");
01523 }
01524 if (socktype == SOCK_STREAM)
01525 grow_buffer = 0;
01526 }
01527 #endif
01528
01529 retry:
01530 if (maxdatlen <= sizeof(datbuf0))
01531 datbuf = datbuf0;
01532 else {
01533 if (NIL_P(dat_str))
01534 dat_str = rb_str_tmp_new(maxdatlen);
01535 else
01536 rb_str_resize(dat_str, maxdatlen);
01537 datbuf = RSTRING_PTR(dat_str);
01538 }
01539
01540 #if defined(HAVE_ST_MSG_CONTROL)
01541 if (maxctllen <= sizeof(ctlbuf0))
01542 ctlbuf = ctlbuf0.bytes;
01543 else {
01544 if (NIL_P(ctl_str))
01545 ctl_str = rb_str_tmp_new(maxctllen);
01546 else
01547 rb_str_resize(ctl_str, maxctllen);
01548 ctlbuf = RSTRING_PTR(ctl_str);
01549 }
01550 #endif
01551
01552 memset(&mh, 0, sizeof(mh));
01553
01554 memset(&namebuf, 0, sizeof(namebuf));
01555 mh.msg_name = (struct sockaddr *)&namebuf;
01556 mh.msg_namelen = (socklen_t)sizeof(namebuf);
01557
01558 mh.msg_iov = &iov;
01559 mh.msg_iovlen = 1;
01560 iov.iov_base = datbuf;
01561 iov.iov_len = maxdatlen;
01562
01563 #if defined(HAVE_ST_MSG_CONTROL)
01564 mh.msg_control = ctlbuf;
01565 mh.msg_controllen = (socklen_t)maxctllen;
01566 #endif
01567
01568 if (grow_buffer)
01569 flags |= MSG_PEEK;
01570
01571 rb_io_check_closed(fptr);
01572 if (nonblock)
01573 rb_io_set_nonblock(fptr);
01574
01575 ss = rb_recvmsg(fptr->fd, &mh, flags);
01576
01577 if (ss == -1) {
01578 if (!nonblock && rb_io_wait_readable(fptr->fd)) {
01579 rb_io_check_closed(fptr);
01580 goto retry;
01581 }
01582 if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
01583 rb_mod_sys_fail(rb_mWaitReadable, "recvmsg(2) would block");
01584 #if defined(HAVE_ST_MSG_CONTROL)
01585 if (!gc_done && (errno == EMFILE || errno == EMSGSIZE)) {
01586
01587
01588
01589
01590
01591
01592 gc_and_retry:
01593 rb_gc();
01594 gc_done = 1;
01595 goto retry;
01596 }
01597 #endif
01598 rb_sys_fail("recvmsg(2)");
01599 }
01600
01601 if (grow_buffer) {
01602 int grown = 0;
01603 #if defined(HAVE_ST_MSG_CONTROL)
01604 if (NIL_P(vmaxdatlen) && (mh.msg_flags & MSG_TRUNC)) {
01605 if (SIZE_MAX/2 < maxdatlen)
01606 rb_raise(rb_eArgError, "max data length too big");
01607 maxdatlen *= 2;
01608 grown = 1;
01609 }
01610 if (NIL_P(vmaxctllen) && (mh.msg_flags & MSG_CTRUNC)) {
01611 #define BIG_ENOUGH_SPACE 65536
01612 if (BIG_ENOUGH_SPACE < maxctllen &&
01613 mh.msg_controllen < (socklen_t)(maxctllen - BIG_ENOUGH_SPACE)) {
01614
01615
01616 if (!gc_done) {
01617 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
01618 goto gc_and_retry;
01619 }
01620 }
01621 else {
01622 if (SIZE_MAX/2 < maxctllen)
01623 rb_raise(rb_eArgError, "max control message length too big");
01624 maxctllen *= 2;
01625 grown = 1;
01626 }
01627 #undef BIG_ENOUGH_SPACE
01628 }
01629 #else
01630 if (NIL_P(vmaxdatlen) && ss != -1 && ss == (ssize_t)iov.iov_len) {
01631 if (SIZE_MAX/2 < maxdatlen)
01632 rb_raise(rb_eArgError, "max data length too big");
01633 maxdatlen *= 2;
01634 grown = 1;
01635 }
01636 #endif
01637 if (grown) {
01638 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
01639 goto retry;
01640 }
01641 else {
01642 grow_buffer = 0;
01643 if (flags != orig_flags) {
01644 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
01645 flags = orig_flags;
01646 goto retry;
01647 }
01648 }
01649 }
01650
01651 if (NIL_P(dat_str))
01652 dat_str = rb_tainted_str_new(datbuf, ss);
01653 else {
01654 rb_str_resize(dat_str, ss);
01655 OBJ_TAINT(dat_str);
01656 RBASIC(dat_str)->klass = rb_cString;
01657 }
01658
01659 ret = rb_ary_new3(3, dat_str,
01660 rsock_io_socket_addrinfo(sock, mh.msg_name, mh.msg_namelen),
01661 #if defined(HAVE_ST_MSG_CONTROL)
01662 INT2NUM(mh.msg_flags)
01663 #else
01664 Qnil
01665 #endif
01666 );
01667
01668 #if defined(HAVE_ST_MSG_CONTROL)
01669 family = rsock_getfamily(fptr->fd);
01670 if (mh.msg_controllen) {
01671 char *msg_end = (char *)mh.msg_control + mh.msg_controllen;
01672 for (cmh = CMSG_FIRSTHDR(&mh); cmh != NULL; cmh = CMSG_NXTHDR(&mh, cmh)) {
01673 VALUE ctl;
01674 char *ctl_end;
01675 size_t clen;
01676 if (cmh->cmsg_len == 0) {
01677 rb_raise(rb_eTypeError, "invalid control message (cmsg_len == 0)");
01678 }
01679 ctl_end = (char*)cmh + cmh->cmsg_len;
01680 clen = (ctl_end <= msg_end ? ctl_end : msg_end) - (char*)CMSG_DATA(cmh);
01681 ctl = ancdata_new(family, cmh->cmsg_level, cmh->cmsg_type, rb_tainted_str_new((char*)CMSG_DATA(cmh), clen));
01682 if (request_scm_rights)
01683 make_io_for_unix_rights(ctl, cmh, msg_end);
01684 else
01685 discard_cmsg(cmh, msg_end, (flags & MSG_PEEK) != 0);
01686 rb_ary_push(ret, ctl);
01687 }
01688 }
01689 #endif
01690
01691 return ret;
01692 }
01693 #endif
01694
01695 #if defined(HAVE_RECVMSG)
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
01737
01738
01739
01740
01741
01742
01743
01744
01745
01746
01747
01748
01749 VALUE
01750 rsock_bsock_recvmsg(int argc, VALUE *argv, VALUE sock)
01751 {
01752 return bsock_recvmsg_internal(argc, argv, sock, 0);
01753 }
01754 #endif
01755
01756 #if defined(HAVE_RECVMSG)
01757
01758
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768 VALUE
01769 rsock_bsock_recvmsg_nonblock(int argc, VALUE *argv, VALUE sock)
01770 {
01771 return bsock_recvmsg_internal(argc, argv, sock, 1);
01772 }
01773 #endif
01774
01775 void
01776 rsock_init_ancdata(void)
01777 {
01778 #if defined(HAVE_ST_MSG_CONTROL)
01779
01780
01781
01782
01783
01784
01785
01786 rb_cAncillaryData = rb_define_class_under(rb_cSocket, "AncillaryData", rb_cObject);
01787 rb_define_method(rb_cAncillaryData, "initialize", ancillary_initialize, 4);
01788 rb_define_method(rb_cAncillaryData, "inspect", ancillary_inspect, 0);
01789 rb_define_method(rb_cAncillaryData, "family", ancillary_family_m, 0);
01790 rb_define_method(rb_cAncillaryData, "level", ancillary_level_m, 0);
01791 rb_define_method(rb_cAncillaryData, "type", ancillary_type_m, 0);
01792 rb_define_method(rb_cAncillaryData, "data", ancillary_data, 0);
01793
01794 rb_define_method(rb_cAncillaryData, "cmsg_is?", ancillary_cmsg_is_p, 2);
01795
01796 rb_define_singleton_method(rb_cAncillaryData, "int", ancillary_s_int, 4);
01797 rb_define_method(rb_cAncillaryData, "int", ancillary_int, 0);
01798
01799 rb_define_singleton_method(rb_cAncillaryData, "unix_rights", ancillary_s_unix_rights, -1);
01800 rb_define_method(rb_cAncillaryData, "unix_rights", ancillary_unix_rights, 0);
01801
01802 rb_define_method(rb_cAncillaryData, "timestamp", ancillary_timestamp, 0);
01803
01804 rb_define_singleton_method(rb_cAncillaryData, "ip_pktinfo", ancillary_s_ip_pktinfo, -1);
01805 rb_define_method(rb_cAncillaryData, "ip_pktinfo", ancillary_ip_pktinfo, 0);
01806
01807 rb_define_singleton_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_s_ipv6_pktinfo, 2);
01808 rb_define_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_ipv6_pktinfo, 0);
01809 rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_addr", ancillary_ipv6_pktinfo_addr, 0);
01810 rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_ifindex", ancillary_ipv6_pktinfo_ifindex, 0);
01811 #endif
01812 }
01813