Ruby 1.9.3p327(2012-11-10revision37606)
ext/socket/ancdata.c
Go to the documentation of this file.
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  * call-seq:
00042  *   Socket::AncillaryData.new(family, cmsg_level, cmsg_type, cmsg_data) -> ancillarydata
00043  *
00044  * _family_ should be an integer, a string or a symbol.
00045  * - Socket::AF_INET, "AF_INET", "INET", :AF_INET, :INET
00046  * - Socket::AF_UNIX, "AF_UNIX", "UNIX", :AF_UNIX, :UNIX
00047  * - etc.
00048  *
00049  * _cmsg_level_ should be an integer, a string or a symbol.
00050  * - Socket::SOL_SOCKET, "SOL_SOCKET", "SOCKET", :SOL_SOCKET and :SOCKET
00051  * - Socket::IPPROTO_IP, "IP" and :IP
00052  * - Socket::IPPROTO_IPV6, "IPV6" and :IPV6
00053  * - Socket::IPPROTO_TCP, "TCP" and :TCP
00054  * - etc.
00055  *
00056  * _cmsg_type_ should be an integer, a string or a symbol.
00057  * If a string/symbol is specified, it is interpreted depend on _cmsg_level_.
00058  * - Socket::SCM_RIGHTS, "SCM_RIGHTS", "RIGHTS", :SCM_RIGHTS, :RIGHTS for SOL_SOCKET
00059  * - Socket::IP_RECVTTL, "RECVTTL" and :RECVTTL for IPPROTO_IP
00060  * - Socket::IPV6_PKTINFO, "PKTINFO" and :PKTINFO for IPPROTO_IPV6
00061  * - etc.
00062  *
00063  * _cmsg_data_ should be a string.
00064  *
00065  *   p Socket::AncillaryData.new(:INET, :TCP, :NODELAY, "")
00066  *   #=> #<Socket::AncillaryData: INET TCP NODELAY "">
00067  *
00068  *   p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "")
00069  *   #=> #<Socket::AncillaryData: INET6 IPV6 PKTINFO "">
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  * call-seq:
00105  *   ancillarydata.family => integer
00106  *
00107  * returns the socket family as an integer.
00108  *
00109  *   p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").family
00110  *   #=> 10
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  * call-seq:
00127  *   ancillarydata.level => integer
00128  *
00129  * returns the cmsg level as an integer.
00130  *
00131  *   p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").level
00132  *   #=> 41
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  * call-seq:
00149  *   ancillarydata.type => integer
00150  *
00151  * returns the cmsg type as an integer.
00152  *
00153  *   p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").type
00154  *   #=> 2
00155  */
00156 static VALUE
00157 ancillary_type_m(VALUE self)
00158 {
00159     return INT2NUM(ancillary_type(self));
00160 }
00161 
00162 /*
00163  * call-seq:
00164  *   ancillarydata.data => string
00165  *
00166  * returns the cmsg data as a string.
00167  *
00168  *   p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").data
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  * call-seq:
00182  *   Socket::AncillaryData.unix_rights(io1, io2, ...) => ancillarydata
00183  *
00184  * Creates a new Socket::AncillaryData object which contains file descriptors as data.
00185  *
00186  *   p Socket::AncillaryData.unix_rights(STDERR)
00187  *   #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 2>
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  * call-seq:
00227  *   ancillarydata.unix_rights => array-of-IOs or nil
00228  *
00229  * returns the array of IO objects for SCM_RIGHTS control message in UNIX domain socket.
00230  *
00231  * The class of the IO objects in the array is IO or Socket.
00232  *
00233  * The array is attached to _ancillarydata_ when it is instantiated.
00234  * For example, BasicSocket#recvmsg attach the array when
00235  * receives a SCM_RIGHTS control message and :scm_rights=>true option is given.
00236  *
00237  *   # recvmsg needs :scm_rights=>true for unix_rights
00238  *   s1, s2 = UNIXSocket.pair
00239  *   p s1                                         #=> #<UNIXSocket:fd 3>
00240  *   s1.sendmsg "stdin and a socket", 0, nil, Socket::AncillaryData.unix_rights(STDIN, s1)
00241  *   _, _, _, ctl = s2.recvmsg(:scm_rights=>true)
00242  *   p ctl                                        #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 6 7>
00243  *   p ctl.unix_rights                            #=> [#<IO:fd 6>, #<Socket:fd 7>]
00244  *   p File.identical?(STDIN, ctl.unix_rights[0]) #=> true
00245  *   p File.identical?(s1, ctl.unix_rights[1])    #=> true
00246  *
00247  *   # If :scm_rights=>true is not given, unix_rights returns nil
00248  *   s1, s2 = UNIXSocket.pair
00249  *   s1.sendmsg "stdin and a socket", 0, nil, Socket::AncillaryData.unix_rights(STDIN, s1)
00250  *   _, _, _, ctl = s2.recvmsg
00251  *   p ctl #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 6 7>
00252  *   p ctl.unix_rights #=> nil
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  * call-seq:
00275  *   ancillarydata.timestamp => time
00276  *
00277  * returns the timestamp as a time object.
00278  *
00279  * _ancillarydata_ should be one of following type:
00280  * - SOL_SOCKET/SCM_TIMESTAMP (micro second) GNU/Linux, FreeBSD, NetBSD, OpenBSD, Solaris, MacOS X
00281  * - SOL_SOCKET/SCM_TIMESTAMPNS (nano second) GNU/Linux
00282  * - SOL_SOCKET/SCM_BINTIME (2**(-64) second) FreeBSD
00283  *
00284  *   Addrinfo.udp("127.0.0.1", 0).bind {|s1|
00285  *     Addrinfo.udp("127.0.0.1", 0).bind {|s2|
00286  *       s1.setsockopt(:SOCKET, :TIMESTAMP, true)
00287  *       s2.send "a", 0, s1.local_address
00288  *       ctl = s1.recvmsg.last
00289  *       p ctl    #=> #<Socket::AncillaryData: INET SOCKET TIMESTAMP 2009-02-24 17:35:46.775581>
00290  *       t = ctl.timestamp
00291  *       p t      #=> 2009-02-24 17:35:46 +0900
00292  *       p t.usec #=> 775581
00293  *       p t.nsec #=> 775581000
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  * call-seq:
00355  *   Socket::AncillaryData.int(family, cmsg_level, cmsg_type, integer) => ancillarydata
00356  *
00357  * Creates a new Socket::AncillaryData object which contains a int as data.
00358  *
00359  * The size and endian is dependent on the host.
00360  *
00361  *   p Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, STDERR.fileno)
00362  *   #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 2>
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  * call-seq:
00376  *   ancillarydata.int => integer
00377  *
00378  * Returns the data in _ancillarydata_ as an int.
00379  *
00380  * The size and endian is dependent on the host.
00381  *
00382  *   ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, STDERR.fileno)
00383  *   p ancdata.int #=> 2
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) /* GNU/Linux */
00398 /*
00399  * call-seq:
00400  *   Socket::AncillaryData.ip_pktinfo(addr, ifindex) => ancdata
00401  *   Socket::AncillaryData.ip_pktinfo(addr, ifindex, spec_dst) => ancdata
00402  *
00403  * Returns new ancillary data for IP_PKTINFO.
00404  *
00405  * If spec_dst is not given, addr is used.
00406  *
00407  * IP_PKTINFO is not standard.
00408  *
00409  * Supported platform: GNU/Linux
00410  *
00411  *   addr = Addrinfo.ip("127.0.0.1")
00412  *   ifindex = 0
00413  *   spec_dst = Addrinfo.ip("127.0.0.1")
00414  *   p Socket::AncillaryData.ip_pktinfo(addr, ifindex, spec_dst)
00415  *   #=> #<Socket::AncillaryData: INET IP PKTINFO 127.0.0.1 ifindex:0 spec_dst:127.0.0.1>
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) /* GNU/Linux */
00462 /*
00463  * call-seq:
00464  *   ancdata.ip_pktinfo => [addr, ifindex, spec_dst]
00465  *
00466  * Extracts addr, ifindex and spec_dst from IP_PKTINFO ancillary data.
00467  *
00468  * IP_PKTINFO is not standard.
00469  *
00470  * Supported platform: GNU/Linux
00471  *
00472  *   addr = Addrinfo.ip("127.0.0.1")
00473  *   ifindex = 0
00474  *   spec_dest = Addrinfo.ip("127.0.0.1")
00475  *   ancdata = Socket::AncillaryData.ip_pktinfo(addr, ifindex, spec_dest)
00476  *   p ancdata.ip_pktinfo
00477  *   #=> [#<Addrinfo: 127.0.0.1>, 0, #<Addrinfo: 127.0.0.1>]
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) /* IPv6 RFC3542 */
00517 /*
00518  * call-seq:
00519  *   Socket::AncillaryData.ipv6_pktinfo(addr, ifindex) => ancdata
00520  *
00521  * Returns new ancillary data for IPV6_PKTINFO.
00522  *
00523  * IPV6_PKTINFO is defined by RFC 3542.
00524  *
00525  *   addr = Addrinfo.ip("::1")
00526  *   ifindex = 0
00527  *   p Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
00528  *   #=> #<Socket::AncillaryData: INET6 IPV6 PKTINFO ::1 ifindex:0>
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) /* IPv6 RFC3542 */
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) /* IPv6 RFC3542 */
00587 /*
00588  * call-seq:
00589  *   ancdata.ipv6_pktinfo => [addr, ifindex]
00590  *
00591  * Extracts addr and ifindex from IPV6_PKTINFO ancillary data.
00592  *
00593  * IPV6_PKTINFO is defined by RFC 3542.
00594  *
00595  *   addr = Addrinfo.ip("::1")
00596  *   ifindex = 0
00597  *   ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
00598  *   p ancdata.ipv6_pktinfo #=> [#<Addrinfo: ::1>, 0]
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) /* IPv6 RFC3542 */
00617 /*
00618  * call-seq:
00619  *   ancdata.ipv6_pktinfo_addr => addr
00620  *
00621  * Extracts addr from IPV6_PKTINFO ancillary data.
00622  *
00623  * IPV6_PKTINFO is defined by RFC 3542.
00624  *
00625  *   addr = Addrinfo.ip("::1")
00626  *   ifindex = 0
00627  *   ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
00628  *   p ancdata.ipv6_pktinfo_addr #=> #<Addrinfo: ::1>
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) /* IPv6 RFC3542 */
00644 /*
00645  * call-seq:
00646  *   ancdata.ipv6_pktinfo_ifindex => addr
00647  *
00648  * Extracts ifindex from IPV6_PKTINFO ancillary data.
00649  *
00650  * IPV6_PKTINFO is defined by RFC 3542.
00651  *
00652  *   addr = Addrinfo.ip("::1")
00653  *   ifindex = 0
00654  *   ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
00655  *   p ancdata.ipv6_pktinfo_ifindex #=> 0
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) /* 4.4BSD */
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) /* GNU/Linux */
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      * FreeBSD has struct cmsgcred and struct sockcred.
00718      * They use both SOL_SOCKET/SCM_CREDS in the ancillary message.
00719      * They are not ambiguous from the view of the caller
00720      * because struct sockcred is sent if and only if the caller sets LOCAL_CREDS socket option.
00721      * But inspect method doesn't know it.
00722      * So they are ambiguous from the view of inspect.
00723      * This function distinguish them by the size of the ancillary message.
00724      * This heuristics works well except when sc_ngroups == CMGROUP_MAX.
00725      */
00726 
00727 #if defined(HAVE_TYPE_STRUCT_CMSGCRED) /* FreeBSD */
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) /* FreeBSD, NetBSD */
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) /* 4.4BSD */
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) /* GNU/Linux */
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) /* IPv6 RFC3542 */
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) /* GNU/Linux, FreeBSD, NetBSD, OpenBSD, MacOS X, Solaris */
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) /* GNU/Linux */
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) /* FreeBSD */
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         /* res_h = frac * 10**19 / 2**64 */
00912 
00913         frac_h = bt.frac >> 32;
00914         frac_l = bt.frac & 0xffffffff;
00915 
00916         scale_h = 0x8ac72304; /* 0x8ac7230489e80000 == 10**19 */
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  * call-seq:
00945  *   ancillarydata.inspect => string
00946  *
00947  * returns a string which shows ancillarydata in human-readable form.
00948  *
00949  *   p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").inspect
00950  *   #=> "#<Socket::AncillaryData: INET6 IPV6 PKTINFO \"\">"
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) /* GNU/Linux, FreeBSD, NetBSD, OpenBSD, MacOS X, Solaris */
01014               case SCM_TIMESTAMP: inspected = inspect_timeval_as_abstime(level, type, data, ret); break;
01015 #            endif
01016 #            if defined(SCM_TIMESTAMPNS) /* GNU/Linux */
01017               case SCM_TIMESTAMPNS: inspected = inspect_timespec_as_abstime(level, type, data, ret); break;
01018 #            endif
01019 #            if defined(SCM_BINTIME) /* FreeBSD */
01020               case SCM_BINTIME: inspected = inspect_bintime_as_abstime(level, type, data, ret); break;
01021 #            endif
01022 #            if defined(SCM_RIGHTS) /* 4.4BSD */
01023               case SCM_RIGHTS: inspected = anc_inspect_socket_rights(level, type, data, ret); break;
01024 #            endif
01025 #            if defined(SCM_CREDENTIALS) /* GNU/Linux */
01026               case SCM_CREDENTIALS: inspected = anc_inspect_passcred_credentials(level, type, data, ret); break;
01027 #            endif
01028 #            if defined(INSPECT_SCM_CREDS) /* NetBSD */
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) /* 4.4BSD */
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) /* GNU/Linux */
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) /* RFC 3542 */
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  * call-seq:
01080  *   ancillarydata.cmsg_is?(level, type) => true or false
01081  *
01082  * tests the level and type of _ancillarydata_.
01083  *
01084  *   ancdata = Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "")
01085  *   ancdata.cmsg_is?(Socket::IPPROTO_IPV6, Socket::IPV6_PKTINFO) #=> true
01086  *   ancdata.cmsg_is?(:IPV6, :PKTINFO)       #=> true
01087  *   ancdata.cmsg_is?(:IP, :PKTINFO)         #=> false
01088  *   ancdata.cmsg_is?(:SOCKET, :RIGHTS)      #=> false
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              * This code removes the last padding from msg_controllen.
01214              *
01215              * 4.3BSD-Reno reject the padding for SCM_RIGHTS. (There was no 64bit environments in those days?)
01216              * RFC 2292 require the padding.
01217              * RFC 3542 relaxes the condition - implementation must accept both as valid.
01218              *
01219              * Actual problems:
01220              *
01221              * - NetBSD 4.0.1
01222              *   SCM_RIGHTS with padding causes EINVAL
01223              *   IPV6_PKTINFO without padding causes "page fault trap"
01224              *     http://www.netbsd.org/cgi-bin/query-pr-single.pl?number=40661
01225              *
01226              * - OpenBSD 4.4
01227              *   IPV6_PKTINFO without padding causes EINVAL
01228              *
01229              * Basically, msg_controllen should contains the padding.
01230              * So the padding is removed only if a problem really exists.
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  * call-seq:
01298  *    basicsocket.sendmsg(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent
01299  *
01300  * sendmsg sends a message using sendmsg(2) system call in blocking manner.
01301  *
01302  * _mesg_ is a string to send.
01303  *
01304  * _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_OOB.
01305  *
01306  * _dest_sockaddr_ is a destination socket address for connection-less socket.
01307  * It should be a sockaddr such as a result of Socket.sockaddr_in.
01308  * An Addrinfo object can be used too.
01309  *
01310  * _controls_ is a list of ancillary data.
01311  * The element of _controls_ should be Socket::AncillaryData or
01312  * 3-elements array.
01313  * The 3-element array should contains cmsg_level, cmsg_type and data.
01314  *
01315  * The return value, _numbytes_sent_ is an integer which is the number of bytes sent.
01316  *
01317  * sendmsg can be used to implement send_io as follows:
01318  *
01319  *   # use Socket::AncillaryData.
01320  *   ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, io.fileno)
01321  *   sock.sendmsg("a", 0, nil, ancdata)
01322  *
01323  *   # use 3-element array.
01324  *   ancdata = [:SOCKET, :RIGHTS, [io.fileno].pack("i!")]
01325  *   sock.sendmsg("\0", 0, nil, ancdata)
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  * call-seq:
01338  *    basicsocket.sendmsg_nonblock(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent
01339  *
01340  * sendmsg_nonblock sends a message using sendmsg(2) system call in non-blocking manner.
01341  *
01342  * It is similar to BasicSocket#sendmsg
01343  * but the non-blocking flag is set before the system call
01344  * and it doesn't retry the system call.
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, int msg_peek_p)
01381 {
01382 # if !defined(FD_PASSING_WORK_WITH_RECVMSG_MSG_PEEK)
01383     /*
01384      * FreeBSD 8.2.0, NetBSD 5 and MacOS X Snow Leopard doesn't
01385      * allocate fds by recvmsg with MSG_PEEK.
01386      * [ruby-dev:44189]
01387      * http://redmine.ruby-lang.org/issues/5075
01388      *
01389      * Linux 2.6.38 allocate fds by recvmsg with MSG_PEEK.
01390      */
01391     if (msg_peek_p)
01392         return;
01393 # endif
01394     if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
01395         int *fdp = (int *)CMSG_DATA(cmh);
01396         int *end = (int *)((char *)cmh + cmh->cmsg_len);
01397         while ((char *)fdp + sizeof(int) <= (char *)end &&
01398                (char *)fdp + sizeof(int) <= msg_end) {
01399             rb_update_max_fd(*fdp);
01400             close(*fdp);
01401             fdp++;
01402         }
01403     }
01404 }
01405 #endif
01406 
01407 void
01408 rsock_discard_cmsg_resource(struct msghdr *mh, int msg_peek_p)
01409 {
01410 #if defined(HAVE_ST_MSG_CONTROL)
01411     struct cmsghdr *cmh;
01412     char *msg_end;
01413 
01414     if (mh->msg_controllen == 0)
01415         return;
01416 
01417     msg_end = (char *)mh->msg_control + mh->msg_controllen;
01418 
01419     for (cmh = CMSG_FIRSTHDR(mh); cmh != NULL; cmh = CMSG_NXTHDR(mh, cmh)) {
01420         discard_cmsg(cmh, msg_end, msg_peek_p);
01421     }
01422 #endif
01423 }
01424 
01425 #if defined(HAVE_ST_MSG_CONTROL)
01426 static void
01427 make_io_for_unix_rights(VALUE ctl, struct cmsghdr *cmh, char *msg_end)
01428 {
01429     if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
01430         int *fdp, *end;
01431         VALUE ary = rb_ary_new();
01432         rb_ivar_set(ctl, rb_intern("unix_rights"), ary);
01433         fdp = (int *)CMSG_DATA(cmh);
01434         end = (int *)((char *)cmh + cmh->cmsg_len);
01435         while ((char *)fdp + sizeof(int) <= (char *)end &&
01436                (char *)fdp + sizeof(int) <= msg_end) {
01437             int fd = *fdp;
01438             struct stat stbuf;
01439             VALUE io;
01440             if (fstat(fd, &stbuf) == -1)
01441                 rb_raise(rb_eSocket, "invalid fd in SCM_RIGHTS");
01442             rb_update_max_fd(fd);
01443             if (S_ISSOCK(stbuf.st_mode))
01444                 io = rsock_init_sock(rb_obj_alloc(rb_cSocket), fd);
01445             else
01446                 io = rb_io_fdopen(fd, O_RDWR, NULL);
01447             ary = rb_attr_get(ctl, rb_intern("unix_rights"));
01448             rb_ary_push(ary, io);
01449             fdp++;
01450         }
01451         OBJ_FREEZE(ary);
01452     }
01453 }
01454 #endif
01455 
01456 static VALUE
01457 bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
01458 {
01459     rb_io_t *fptr;
01460     VALUE vmaxdatlen, vmaxctllen, vflags, vopts;
01461     int grow_buffer;
01462     size_t maxdatlen;
01463     int flags, orig_flags;
01464     int request_scm_rights;
01465     struct msghdr mh;
01466     struct iovec iov;
01467     struct sockaddr_storage namebuf;
01468     char datbuf0[4096], *datbuf;
01469     VALUE dat_str = Qnil;
01470     VALUE ret;
01471     ssize_t ss;
01472 #if defined(HAVE_ST_MSG_CONTROL)
01473     struct cmsghdr *cmh;
01474     size_t maxctllen;
01475     union {
01476         char bytes[4096];
01477         struct cmsghdr align;
01478     } ctlbuf0;
01479     char *ctlbuf;
01480     VALUE ctl_str = Qnil;
01481     int family;
01482     int gc_done = 0;
01483 #endif
01484 
01485     rb_secure(4);
01486 
01487     vopts = Qnil;
01488     if (0 < argc && TYPE(argv[argc-1]) == T_HASH)
01489         vopts = argv[--argc];
01490 
01491     rb_scan_args(argc, argv, "03", &vmaxdatlen, &vflags, &vmaxctllen);
01492 
01493     maxdatlen = NIL_P(vmaxdatlen) ? sizeof(datbuf0) : NUM2SIZET(vmaxdatlen);
01494 #if defined(HAVE_ST_MSG_CONTROL)
01495     maxctllen = NIL_P(vmaxctllen) ? sizeof(ctlbuf0) : NUM2SIZET(vmaxctllen);
01496 #else
01497     if (!NIL_P(vmaxctllen))
01498         rb_raise(rb_eArgError, "control message not supported");
01499 #endif
01500     flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
01501 #ifdef MSG_DONTWAIT
01502     if (nonblock)
01503         flags |= MSG_DONTWAIT;
01504 #endif
01505     orig_flags = flags;
01506 
01507     grow_buffer = NIL_P(vmaxdatlen) || NIL_P(vmaxctllen);
01508 
01509     request_scm_rights = 0;
01510     if (!NIL_P(vopts) && RTEST(rb_hash_aref(vopts, ID2SYM(rb_intern("scm_rights")))))
01511         request_scm_rights = 1;
01512 
01513     GetOpenFile(sock, fptr);
01514     if (rb_io_read_pending(fptr)) {
01515         rb_raise(rb_eIOError, "recvmsg for buffered IO");
01516     }
01517 
01518 #if !defined(HAVE_ST_MSG_CONTROL)
01519     if (grow_buffer) {
01520         int socktype;
01521         socklen_t optlen = (socklen_t)sizeof(socktype);
01522         if (getsockopt(fptr->fd, SOL_SOCKET, SO_TYPE, (void*)&socktype, &optlen) == -1) {
01523             rb_sys_fail("getsockopt(SO_TYPE)");
01524         }
01525         if (socktype == SOCK_STREAM)
01526             grow_buffer = 0;
01527     }
01528 #endif
01529 
01530   retry:
01531     if (maxdatlen <= sizeof(datbuf0))
01532         datbuf = datbuf0;
01533     else {
01534         if (NIL_P(dat_str))
01535             dat_str = rb_str_tmp_new(maxdatlen);
01536         else
01537             rb_str_resize(dat_str, maxdatlen);
01538         datbuf = RSTRING_PTR(dat_str);
01539     }
01540 
01541 #if defined(HAVE_ST_MSG_CONTROL)
01542     if (maxctllen <= sizeof(ctlbuf0))
01543         ctlbuf = ctlbuf0.bytes;
01544     else {
01545         if (NIL_P(ctl_str))
01546             ctl_str = rb_str_tmp_new(maxctllen);
01547         else
01548             rb_str_resize(ctl_str, maxctllen);
01549         ctlbuf = RSTRING_PTR(ctl_str);
01550     }
01551 #endif
01552 
01553     memset(&mh, 0, sizeof(mh));
01554 
01555     memset(&namebuf, 0, sizeof(namebuf));
01556     mh.msg_name = (struct sockaddr *)&namebuf;
01557     mh.msg_namelen = (socklen_t)sizeof(namebuf);
01558 
01559     mh.msg_iov = &iov;
01560     mh.msg_iovlen = 1;
01561     iov.iov_base = datbuf;
01562     iov.iov_len = maxdatlen;
01563 
01564 #if defined(HAVE_ST_MSG_CONTROL)
01565     mh.msg_control = ctlbuf;
01566     mh.msg_controllen = (socklen_t)maxctllen;
01567 #endif
01568 
01569     if (grow_buffer)
01570         flags |= MSG_PEEK;
01571 
01572     rb_io_check_closed(fptr);
01573     if (nonblock)
01574         rb_io_set_nonblock(fptr);
01575 
01576     ss = rb_recvmsg(fptr->fd, &mh, flags);
01577 
01578     if (!nonblock && rb_io_wait_readable(fptr->fd)) {
01579         rb_io_check_closed(fptr);
01580         goto retry;
01581     }
01582 
01583     if (ss == -1) {
01584         if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
01585             rb_mod_sys_fail(rb_mWaitReadable, "recvmsg(2) would block");
01586 #if defined(HAVE_ST_MSG_CONTROL)
01587         if (!gc_done && (errno == EMFILE || errno == EMSGSIZE)) {
01588           /*
01589            * When SCM_RIGHTS hit the file descriptors limit:
01590            * - Linux 2.6.18 causes success with MSG_CTRUNC
01591            * - MacOS X 10.4 causes EMSGSIZE (and lost file descriptors?)
01592            * - Solaris 11 causes EMFILE
01593            */
01594           gc_and_retry:
01595             rb_gc();
01596             gc_done = 1;
01597             goto retry;
01598         }
01599 #endif
01600         rb_sys_fail("recvmsg(2)");
01601     }
01602 
01603     if (grow_buffer) {
01604         int grown = 0;
01605 #if defined(HAVE_ST_MSG_CONTROL)
01606         if (NIL_P(vmaxdatlen) && (mh.msg_flags & MSG_TRUNC)) {
01607             if (SIZE_MAX/2 < maxdatlen)
01608                 rb_raise(rb_eArgError, "max data length too big");
01609             maxdatlen *= 2;
01610             grown = 1;
01611         }
01612         if (NIL_P(vmaxctllen) && (mh.msg_flags & MSG_CTRUNC)) {
01613 #define BIG_ENOUGH_SPACE 65536
01614             if (BIG_ENOUGH_SPACE < maxctllen &&
01615                 mh.msg_controllen < (socklen_t)(maxctllen - BIG_ENOUGH_SPACE)) {
01616                 /* there are big space bug truncated.
01617                  * file descriptors limit? */
01618                 if (!gc_done) {
01619                     rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
01620                     goto gc_and_retry;
01621                 }
01622             }
01623             else {
01624                 if (SIZE_MAX/2 < maxctllen)
01625                     rb_raise(rb_eArgError, "max control message length too big");
01626                 maxctllen *= 2;
01627                 grown = 1;
01628             }
01629 #undef BIG_ENOUGH_SPACE
01630         }
01631 #else
01632         if (NIL_P(vmaxdatlen) && ss != -1 && ss == (ssize_t)iov.iov_len) {
01633             if (SIZE_MAX/2 < maxdatlen)
01634                 rb_raise(rb_eArgError, "max data length too big");
01635             maxdatlen *= 2;
01636             grown = 1;
01637         }
01638 #endif
01639         if (grown) {
01640             rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
01641             goto retry;
01642         }
01643         else {
01644             grow_buffer = 0;
01645             if (flags != orig_flags) {
01646                 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
01647                 flags = orig_flags;
01648                 goto retry;
01649             }
01650         }
01651     }
01652 
01653     if (NIL_P(dat_str))
01654         dat_str = rb_tainted_str_new(datbuf, ss);
01655     else {
01656         rb_str_resize(dat_str, ss);
01657         OBJ_TAINT(dat_str);
01658         RBASIC(dat_str)->klass = rb_cString;
01659     }
01660 
01661     ret = rb_ary_new3(3, dat_str,
01662                          rsock_io_socket_addrinfo(sock, mh.msg_name, mh.msg_namelen),
01663 #if defined(HAVE_ST_MSG_CONTROL)
01664                          INT2NUM(mh.msg_flags)
01665 #else
01666                          Qnil
01667 #endif
01668                          );
01669 
01670 #if defined(HAVE_ST_MSG_CONTROL)
01671     family = rsock_getfamily(fptr->fd);
01672     if (mh.msg_controllen) {
01673         char *msg_end = (char *)mh.msg_control + mh.msg_controllen;
01674         for (cmh = CMSG_FIRSTHDR(&mh); cmh != NULL; cmh = CMSG_NXTHDR(&mh, cmh)) {
01675             VALUE ctl;
01676             char *ctl_end;
01677             size_t clen;
01678             if (cmh->cmsg_len == 0) {
01679                 rb_raise(rb_eTypeError, "invalid control message (cmsg_len == 0)");
01680             }
01681             ctl_end = (char*)cmh + cmh->cmsg_len;
01682             clen = (ctl_end <= msg_end ? ctl_end : msg_end) - (char*)CMSG_DATA(cmh);
01683             ctl = ancdata_new(family, cmh->cmsg_level, cmh->cmsg_type, rb_tainted_str_new((char*)CMSG_DATA(cmh), clen));
01684             if (request_scm_rights)
01685                 make_io_for_unix_rights(ctl, cmh, msg_end);
01686             else
01687                 discard_cmsg(cmh, msg_end, (flags & MSG_PEEK) != 0);
01688             rb_ary_push(ret, ctl);
01689         }
01690     }
01691 #endif
01692 
01693     return ret;
01694 }
01695 #endif
01696 
01697 #if defined(HAVE_RECVMSG)
01698 /*
01699  * call-seq:
01700  *    basicsocket.recvmsg(maxmesglen=nil, flags=0, maxcontrollen=nil, opts={}) => [mesg, sender_addrinfo, rflags, *controls]
01701  *
01702  * recvmsg receives a message using recvmsg(2) system call in blocking manner.
01703  *
01704  * _maxmesglen_ is the maximum length of mesg to receive.
01705  *
01706  * _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_PEEK.
01707  *
01708  * _maxcontrollen_ is the maximum length of controls (ancillary data) to receive.
01709  *
01710  * _opts_ is option hash.
01711  * Currently :scm_rights=>bool is the only option.
01712  *
01713  * :scm_rights option specifies that application expects SCM_RIGHTS control message.
01714  * If the value is nil or false, application don't expects SCM_RIGHTS control message.
01715  * In this case, recvmsg closes the passed file descriptors immediately.
01716  * This is the default behavior.
01717  *
01718  * If :scm_rights value is neither nil nor false, application expects SCM_RIGHTS control message.
01719  * In this case, recvmsg creates IO objects for each file descriptors for
01720  * Socket::AncillaryData#unix_rights method.
01721  *
01722  * The return value is 4-elements array.
01723  *
01724  * _mesg_ is a string of the received message.
01725  *
01726  * _sender_addrinfo_ is a sender socket address for connection-less socket.
01727  * It is an Addrinfo object.
01728  * For connection-oriented socket such as TCP, sender_addrinfo is platform dependent.
01729  *
01730  * _rflags_ is a flags on the received message which is bitwise OR of MSG_* constants such as Socket::MSG_TRUNC.
01731  * It will be nil if the system uses 4.3BSD style old recvmsg system call.
01732  *
01733  * _controls_ is ancillary data which is an array of Socket::AncillaryData objects such as:
01734  *
01735  *   #<Socket::AncillaryData: AF_UNIX SOCKET RIGHTS 7>
01736  *
01737  * _maxmesglen_ and _maxcontrollen_ can be nil.
01738  * In that case, the buffer will be grown until the message is not truncated.
01739  * Internally, MSG_PEEK is used and MSG_TRUNC/MSG_CTRUNC are checked.
01740  *
01741  * recvmsg can be used to implement recv_io as follows:
01742  *
01743  *   mesg, sender_sockaddr, rflags, *controls = sock.recvmsg(:scm_rights=>true)
01744  *   controls.each {|ancdata|
01745  *     if ancdata.cmsg_is?(:SOCKET, :RIGHTS)
01746  *       return ancdata.unix_rights[0]
01747  *     end
01748  *   }
01749  *
01750  */
01751 VALUE
01752 rsock_bsock_recvmsg(int argc, VALUE *argv, VALUE sock)
01753 {
01754     return bsock_recvmsg_internal(argc, argv, sock, 0);
01755 }
01756 #endif
01757 
01758 #if defined(HAVE_RECVMSG)
01759 /*
01760  * call-seq:
01761  *    basicsocket.recvmsg_nonblock(maxdatalen=nil, flags=0, maxcontrollen=nil, opts={}) => [data, sender_addrinfo, rflags, *controls]
01762  *
01763  * recvmsg receives a message using recvmsg(2) system call in non-blocking manner.
01764  *
01765  * It is similar to BasicSocket#recvmsg
01766  * but non-blocking flag is set before the system call
01767  * and it doesn't retry the system call.
01768  *
01769  */
01770 VALUE
01771 rsock_bsock_recvmsg_nonblock(int argc, VALUE *argv, VALUE sock)
01772 {
01773     return bsock_recvmsg_internal(argc, argv, sock, 1);
01774 }
01775 #endif
01776 
01777 void
01778 rsock_init_ancdata(void)
01779 {
01780 #if defined(HAVE_ST_MSG_CONTROL)
01781     /*
01782      * Document-class: Socket::AncillaryData
01783      *
01784      * Socket::AncillaryData represents the ancillary data (control information)
01785      * used by sendmsg and recvmsg system call.  It contains socket #family,
01786      * control message (cmsg) #level, cmsg #type and cmsg #data.
01787      */
01788     rb_cAncillaryData = rb_define_class_under(rb_cSocket, "AncillaryData", rb_cObject);
01789     rb_define_method(rb_cAncillaryData, "initialize", ancillary_initialize, 4);
01790     rb_define_method(rb_cAncillaryData, "inspect", ancillary_inspect, 0);
01791     rb_define_method(rb_cAncillaryData, "family", ancillary_family_m, 0);
01792     rb_define_method(rb_cAncillaryData, "level", ancillary_level_m, 0);
01793     rb_define_method(rb_cAncillaryData, "type", ancillary_type_m, 0);
01794     rb_define_method(rb_cAncillaryData, "data", ancillary_data, 0);
01795 
01796     rb_define_method(rb_cAncillaryData, "cmsg_is?", ancillary_cmsg_is_p, 2);
01797 
01798     rb_define_singleton_method(rb_cAncillaryData, "int", ancillary_s_int, 4);
01799     rb_define_method(rb_cAncillaryData, "int", ancillary_int, 0);
01800 
01801     rb_define_singleton_method(rb_cAncillaryData, "unix_rights", ancillary_s_unix_rights, -1);
01802     rb_define_method(rb_cAncillaryData, "unix_rights", ancillary_unix_rights, 0);
01803 
01804     rb_define_method(rb_cAncillaryData, "timestamp", ancillary_timestamp, 0);
01805 
01806     rb_define_singleton_method(rb_cAncillaryData, "ip_pktinfo", ancillary_s_ip_pktinfo, -1);
01807     rb_define_method(rb_cAncillaryData, "ip_pktinfo", ancillary_ip_pktinfo, 0);
01808 
01809     rb_define_singleton_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_s_ipv6_pktinfo, 2);
01810     rb_define_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_ipv6_pktinfo, 0);
01811     rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_addr", ancillary_ipv6_pktinfo_addr, 0);
01812     rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_ifindex", ancillary_ipv6_pktinfo_ifindex, 0);
01813 #endif
01814 }
01815