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