Ruby  2.0.0p247(2013-06-27revision41674)
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_OF(obj, struct RObject, rb_cAncillaryData, T_OBJECT);
00090     StringValue(data);
00091     ancillary_initialize((VALUE)obj, INT2NUM(family), INT2NUM(level), INT2NUM(type), data);
00092     return (VALUE)obj;
00093 }
00094 
00095 static int
00096 ancillary_family(VALUE self)
00097 {
00098     VALUE v = rb_attr_get(self, rb_intern("family"));
00099     return NUM2INT(v);
00100 }
00101 
00102 /*
00103  * call-seq:
00104  *   ancillarydata.family => integer
00105  *
00106  * returns the socket family as an integer.
00107  *
00108  *   p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").family
00109  *   #=> 10
00110  */
00111 static VALUE
00112 ancillary_family_m(VALUE self)
00113 {
00114     return INT2NUM(ancillary_family(self));
00115 }
00116 
00117 static int
00118 ancillary_level(VALUE self)
00119 {
00120     VALUE v = rb_attr_get(self, rb_intern("level"));
00121     return NUM2INT(v);
00122 }
00123 
00124 /*
00125  * call-seq:
00126  *   ancillarydata.level => integer
00127  *
00128  * returns the cmsg level as an integer.
00129  *
00130  *   p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").level
00131  *   #=> 41
00132  */
00133 static VALUE
00134 ancillary_level_m(VALUE self)
00135 {
00136     return INT2NUM(ancillary_level(self));
00137 }
00138 
00139 static int
00140 ancillary_type(VALUE self)
00141 {
00142     VALUE v = rb_attr_get(self, rb_intern("type"));
00143     return NUM2INT(v);
00144 }
00145 
00146 /*
00147  * call-seq:
00148  *   ancillarydata.type => integer
00149  *
00150  * returns the cmsg type as an integer.
00151  *
00152  *   p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").type
00153  *   #=> 2
00154  */
00155 static VALUE
00156 ancillary_type_m(VALUE self)
00157 {
00158     return INT2NUM(ancillary_type(self));
00159 }
00160 
00161 /*
00162  * call-seq:
00163  *   ancillarydata.data => string
00164  *
00165  * returns the cmsg data as a string.
00166  *
00167  *   p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").data
00168  *   #=> ""
00169  */
00170 static VALUE
00171 ancillary_data(VALUE self)
00172 {
00173     VALUE v = rb_attr_get(self, rb_intern("data"));
00174     StringValue(v);
00175     return v;
00176 }
00177 
00178 #ifdef SCM_RIGHTS
00179 /*
00180  * call-seq:
00181  *   Socket::AncillaryData.unix_rights(io1, io2, ...) => ancillarydata
00182  *
00183  * Creates a new Socket::AncillaryData object which contains file descriptors as data.
00184  *
00185  *   p Socket::AncillaryData.unix_rights(STDERR)
00186  *   #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 2>
00187  */
00188 static VALUE
00189 ancillary_s_unix_rights(int argc, VALUE *argv, VALUE klass)
00190 {
00191     VALUE result, str, ary;
00192     int i;
00193 
00194     ary = rb_ary_new();
00195 
00196     for (i = 0 ; i < argc; i++) {
00197         VALUE obj = argv[i];
00198         if (!RB_TYPE_P(obj, T_FILE)) {
00199             rb_raise(rb_eTypeError, "IO expected");
00200         }
00201         rb_ary_push(ary, obj);
00202     }
00203 
00204     str = rb_str_buf_new(sizeof(int) * argc);
00205 
00206     for (i = 0 ; i < argc; i++) {
00207         VALUE obj = RARRAY_PTR(ary)[i];
00208         rb_io_t *fptr;
00209         int fd;
00210         GetOpenFile(obj, fptr);
00211         fd = fptr->fd;
00212         rb_str_buf_cat(str, (char *)&fd, sizeof(int));
00213     }
00214 
00215     result = ancdata_new(AF_UNIX, SOL_SOCKET, SCM_RIGHTS, str);
00216     rb_ivar_set(result, rb_intern("unix_rights"), ary);
00217     return result;
00218 }
00219 #else
00220 #define ancillary_s_unix_rights rb_f_notimplement
00221 #endif
00222 
00223 #ifdef SCM_RIGHTS
00224 /*
00225  * call-seq:
00226  *   ancillarydata.unix_rights => array-of-IOs or nil
00227  *
00228  * returns the array of IO objects for SCM_RIGHTS control message in UNIX domain socket.
00229  *
00230  * The class of the IO objects in the array is IO or Socket.
00231  *
00232  * The array is attached to _ancillarydata_ when it is instantiated.
00233  * For example, BasicSocket#recvmsg attach the array when
00234  * receives a SCM_RIGHTS control message and :scm_rights=>true option is given.
00235  *
00236  *   # recvmsg needs :scm_rights=>true for unix_rights
00237  *   s1, s2 = UNIXSocket.pair
00238  *   p s1                                         #=> #<UNIXSocket:fd 3>
00239  *   s1.sendmsg "stdin and a socket", 0, nil, Socket::AncillaryData.unix_rights(STDIN, s1)
00240  *   _, _, _, ctl = s2.recvmsg(:scm_rights=>true)
00241  *   p ctl                                        #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 6 7>
00242  *   p ctl.unix_rights                            #=> [#<IO:fd 6>, #<Socket:fd 7>]
00243  *   p File.identical?(STDIN, ctl.unix_rights[0]) #=> true
00244  *   p File.identical?(s1, ctl.unix_rights[1])    #=> true
00245  *
00246  *   # If :scm_rights=>true is not given, unix_rights returns nil
00247  *   s1, s2 = UNIXSocket.pair
00248  *   s1.sendmsg "stdin and a socket", 0, nil, Socket::AncillaryData.unix_rights(STDIN, s1)
00249  *   _, _, _, ctl = s2.recvmsg
00250  *   p ctl #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 6 7>
00251  *   p ctl.unix_rights #=> nil
00252  *
00253  */
00254 static VALUE
00255 ancillary_unix_rights(VALUE self)
00256 {
00257     int level, type;
00258 
00259     level = ancillary_level(self);
00260     type = ancillary_type(self);
00261 
00262     if (level != SOL_SOCKET || type != SCM_RIGHTS)
00263         rb_raise(rb_eTypeError, "SCM_RIGHTS ancillary data expected");
00264 
00265     return rb_attr_get(self, rb_intern("unix_rights"));
00266 }
00267 #else
00268 #define ancillary_unix_rights rb_f_notimplement
00269 #endif
00270 
00271 #if defined(SCM_TIMESTAMP) || defined(SCM_TIMESTAMPNS) || defined(SCM_BINTIME)
00272 /*
00273  * call-seq:
00274  *   ancillarydata.timestamp => time
00275  *
00276  * returns the timestamp as a time object.
00277  *
00278  * _ancillarydata_ should be one of following type:
00279  * - SOL_SOCKET/SCM_TIMESTAMP (micro second) GNU/Linux, FreeBSD, NetBSD, OpenBSD, Solaris, MacOS X
00280  * - SOL_SOCKET/SCM_TIMESTAMPNS (nano second) GNU/Linux
00281  * - SOL_SOCKET/SCM_BINTIME (2**(-64) second) FreeBSD
00282  *
00283  *   Addrinfo.udp("127.0.0.1", 0).bind {|s1|
00284  *     Addrinfo.udp("127.0.0.1", 0).bind {|s2|
00285  *       s1.setsockopt(:SOCKET, :TIMESTAMP, true)
00286  *       s2.send "a", 0, s1.local_address
00287  *       ctl = s1.recvmsg.last
00288  *       p ctl    #=> #<Socket::AncillaryData: INET SOCKET TIMESTAMP 2009-02-24 17:35:46.775581>
00289  *       t = ctl.timestamp
00290  *       p t      #=> 2009-02-24 17:35:46 +0900
00291  *       p t.usec #=> 775581
00292  *       p t.nsec #=> 775581000
00293  *     }
00294  *   }
00295  *
00296  */
00297 static VALUE
00298 ancillary_timestamp(VALUE self)
00299 {
00300     int level, type;
00301     VALUE data;
00302     VALUE result = Qnil;
00303 
00304     level = ancillary_level(self);
00305     type = ancillary_type(self);
00306     data = ancillary_data(self);
00307 
00308 # ifdef SCM_TIMESTAMP
00309     if (level == SOL_SOCKET && type == SCM_TIMESTAMP &&
00310         RSTRING_LEN(data) == sizeof(struct timeval)) {
00311         struct timeval tv;
00312         memcpy((char*)&tv, RSTRING_PTR(data), sizeof(tv));
00313         result = rb_time_new(tv.tv_sec, tv.tv_usec);
00314     }
00315 # endif
00316 
00317 # ifdef SCM_TIMESTAMPNS
00318     if (level == SOL_SOCKET && type == SCM_TIMESTAMPNS &&
00319         RSTRING_LEN(data) == sizeof(struct timespec)) {
00320         struct timespec ts;
00321         memcpy((char*)&ts, RSTRING_PTR(data), sizeof(ts));
00322         result = rb_time_nano_new(ts.tv_sec, ts.tv_nsec);
00323     }
00324 # endif
00325 
00326 #define add(x,y) (rb_funcall((x), '+', 1, (y)))
00327 #define mul(x,y) (rb_funcall((x), '*', 1, (y)))
00328 #define quo(x,y) (rb_funcall((x), rb_intern("quo"), 1, (y)))
00329 
00330 # ifdef SCM_BINTIME
00331     if (level == SOL_SOCKET && type == SCM_BINTIME &&
00332         RSTRING_LEN(data) == sizeof(struct bintime)) {
00333         struct bintime bt;
00334         VALUE d, timev;
00335         memcpy((char*)&bt, RSTRING_PTR(data), sizeof(bt));
00336         d = ULL2NUM(0x100000000ULL);
00337         d = mul(d,d);
00338         timev = add(TIMET2NUM(bt.sec), quo(ULL2NUM(bt.frac), d));
00339         result = rb_time_num_new(timev, Qnil);
00340     }
00341 # endif
00342 
00343     if (result == Qnil)
00344         rb_raise(rb_eTypeError, "timestamp ancillary data expected");
00345 
00346     return result;
00347 }
00348 #else
00349 #define ancillary_timestamp rb_f_notimplement
00350 #endif
00351 
00352 /*
00353  * call-seq:
00354  *   Socket::AncillaryData.int(family, cmsg_level, cmsg_type, integer) => ancillarydata
00355  *
00356  * Creates a new Socket::AncillaryData object which contains a int as data.
00357  *
00358  * The size and endian is dependent on the host.
00359  *
00360  *   p Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, STDERR.fileno)
00361  *   #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 2>
00362  */
00363 static VALUE
00364 ancillary_s_int(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE vtype, VALUE integer)
00365 {
00366     int family = rsock_family_arg(vfamily);
00367     int level = rsock_level_arg(family, vlevel);
00368     int type = rsock_cmsg_type_arg(family, level, vtype);
00369     int i = NUM2INT(integer);
00370     return ancdata_new(family, level, type, rb_str_new((char*)&i, sizeof(i)));
00371 }
00372 
00373 /*
00374  * call-seq:
00375  *   ancillarydata.int => integer
00376  *
00377  * Returns the data in _ancillarydata_ as an int.
00378  *
00379  * The size and endian is dependent on the host.
00380  *
00381  *   ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, STDERR.fileno)
00382  *   p ancdata.int #=> 2
00383  */
00384 static VALUE
00385 ancillary_int(VALUE self)
00386 {
00387     VALUE data;
00388     int i;
00389     data = ancillary_data(self);
00390     if (RSTRING_LEN(data) != sizeof(int))
00391         rb_raise(rb_eTypeError, "size differ.  expected as sizeof(int)=%d but %ld", (int)sizeof(int), (long)RSTRING_LEN(data));
00392     memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
00393     return INT2NUM(i);
00394 }
00395 
00396 #if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST) /* GNU/Linux */
00397 /*
00398  * call-seq:
00399  *   Socket::AncillaryData.ip_pktinfo(addr, ifindex) => ancdata
00400  *   Socket::AncillaryData.ip_pktinfo(addr, ifindex, spec_dst) => ancdata
00401  *
00402  * Returns new ancillary data for IP_PKTINFO.
00403  *
00404  * If spec_dst is not given, addr is used.
00405  *
00406  * IP_PKTINFO is not standard.
00407  *
00408  * Supported platform: GNU/Linux
00409  *
00410  *   addr = Addrinfo.ip("127.0.0.1")
00411  *   ifindex = 0
00412  *   spec_dst = Addrinfo.ip("127.0.0.1")
00413  *   p Socket::AncillaryData.ip_pktinfo(addr, ifindex, spec_dst)
00414  *   #=> #<Socket::AncillaryData: INET IP PKTINFO 127.0.0.1 ifindex:0 spec_dst:127.0.0.1>
00415  *
00416  */
00417 static VALUE
00418 ancillary_s_ip_pktinfo(int argc, VALUE *argv, VALUE self)
00419 {
00420     VALUE v_addr, v_ifindex, v_spec_dst;
00421     unsigned int ifindex;
00422     struct sockaddr_in sa;
00423     struct in_pktinfo pktinfo;
00424 
00425     rb_scan_args(argc, argv, "21", &v_addr, &v_ifindex, &v_spec_dst);
00426 
00427     SockAddrStringValue(v_addr);
00428     ifindex = NUM2UINT(v_ifindex);
00429     if (NIL_P(v_spec_dst))
00430         v_spec_dst = v_addr;
00431     else
00432         SockAddrStringValue(v_spec_dst);
00433 
00434     memset(&pktinfo, 0, sizeof(pktinfo));
00435 
00436     memset(&sa, 0, sizeof(sa));
00437     if (RSTRING_LEN(v_addr) != sizeof(sa))
00438         rb_raise(rb_eArgError, "addr size different to AF_INET sockaddr");
00439     memcpy(&sa, RSTRING_PTR(v_addr), sizeof(sa));
00440     if (sa.sin_family != AF_INET)
00441         rb_raise(rb_eArgError, "addr is not AF_INET sockaddr");
00442     memcpy(&pktinfo.ipi_addr, &sa.sin_addr, sizeof(pktinfo.ipi_addr));
00443 
00444     pktinfo.ipi_ifindex = ifindex;
00445 
00446     memset(&sa, 0, sizeof(sa));
00447     if (RSTRING_LEN(v_spec_dst) != sizeof(sa))
00448         rb_raise(rb_eArgError, "spec_dat size different to AF_INET sockaddr");
00449     memcpy(&sa, RSTRING_PTR(v_spec_dst), sizeof(sa));
00450     if (sa.sin_family != AF_INET)
00451         rb_raise(rb_eArgError, "spec_dst is not AF_INET sockaddr");
00452     memcpy(&pktinfo.ipi_spec_dst, &sa.sin_addr, sizeof(pktinfo.ipi_spec_dst));
00453 
00454     return ancdata_new(AF_INET, IPPROTO_IP, IP_PKTINFO, rb_str_new((char *)&pktinfo, sizeof(pktinfo)));
00455 }
00456 #else
00457 #define ancillary_s_ip_pktinfo rb_f_notimplement
00458 #endif
00459 
00460 #if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST) /* GNU/Linux */
00461 /*
00462  * call-seq:
00463  *   ancdata.ip_pktinfo => [addr, ifindex, spec_dst]
00464  *
00465  * Extracts addr, ifindex and spec_dst from IP_PKTINFO ancillary data.
00466  *
00467  * IP_PKTINFO is not standard.
00468  *
00469  * Supported platform: GNU/Linux
00470  *
00471  *   addr = Addrinfo.ip("127.0.0.1")
00472  *   ifindex = 0
00473  *   spec_dest = Addrinfo.ip("127.0.0.1")
00474  *   ancdata = Socket::AncillaryData.ip_pktinfo(addr, ifindex, spec_dest)
00475  *   p ancdata.ip_pktinfo
00476  *   #=> [#<Addrinfo: 127.0.0.1>, 0, #<Addrinfo: 127.0.0.1>]
00477  *
00478  *
00479  */
00480 static VALUE
00481 ancillary_ip_pktinfo(VALUE self)
00482 {
00483     int level, type;
00484     VALUE data;
00485     struct in_pktinfo pktinfo;
00486     struct sockaddr_in sa;
00487     VALUE v_spec_dst, v_addr;
00488 
00489     level = ancillary_level(self);
00490     type = ancillary_type(self);
00491     data = ancillary_data(self);
00492 
00493     if (level != IPPROTO_IP || type != IP_PKTINFO ||
00494         RSTRING_LEN(data) != sizeof(struct in_pktinfo)) {
00495         rb_raise(rb_eTypeError, "IP_PKTINFO ancillary data expected");
00496     }
00497 
00498     memcpy(&pktinfo, RSTRING_PTR(data), sizeof(struct in_pktinfo));
00499     memset(&sa, 0, sizeof(sa));
00500 
00501     sa.sin_family = AF_INET;
00502     memcpy(&sa.sin_addr, &pktinfo.ipi_addr, sizeof(sa.sin_addr));
00503     v_addr = rsock_addrinfo_new((struct sockaddr *)&sa, sizeof(sa), PF_INET, 0, 0, Qnil, Qnil);
00504 
00505     sa.sin_family = AF_INET;
00506     memcpy(&sa.sin_addr, &pktinfo.ipi_spec_dst, sizeof(sa.sin_addr));
00507     v_spec_dst = rsock_addrinfo_new((struct sockaddr *)&sa, sizeof(sa), PF_INET, 0, 0, Qnil, Qnil);
00508 
00509     return rb_ary_new3(3, v_addr, UINT2NUM(pktinfo.ipi_ifindex), v_spec_dst);
00510 }
00511 #else
00512 #define ancillary_ip_pktinfo rb_f_notimplement
00513 #endif
00514 
00515 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */
00516 /*
00517  * call-seq:
00518  *   Socket::AncillaryData.ipv6_pktinfo(addr, ifindex) => ancdata
00519  *
00520  * Returns new ancillary data for IPV6_PKTINFO.
00521  *
00522  * IPV6_PKTINFO is defined by RFC 3542.
00523  *
00524  *   addr = Addrinfo.ip("::1")
00525  *   ifindex = 0
00526  *   p Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
00527  *   #=> #<Socket::AncillaryData: INET6 IPV6 PKTINFO ::1 ifindex:0>
00528  *
00529  */
00530 static VALUE
00531 ancillary_s_ipv6_pktinfo(VALUE self, VALUE v_addr, VALUE v_ifindex)
00532 {
00533     unsigned int ifindex;
00534     struct sockaddr_in6 sa;
00535     struct in6_pktinfo pktinfo;
00536 
00537     SockAddrStringValue(v_addr);
00538     ifindex = NUM2UINT(v_ifindex);
00539 
00540     memset(&pktinfo, 0, sizeof(pktinfo));
00541 
00542     memset(&sa, 0, sizeof(sa));
00543     if (RSTRING_LEN(v_addr) != sizeof(sa))
00544         rb_raise(rb_eArgError, "addr size different to AF_INET6 sockaddr");
00545     memcpy(&sa, RSTRING_PTR(v_addr), sizeof(sa));
00546     if (sa.sin6_family != AF_INET6)
00547         rb_raise(rb_eArgError, "addr is not AF_INET6 sockaddr");
00548     memcpy(&pktinfo.ipi6_addr, &sa.sin6_addr, sizeof(pktinfo.ipi6_addr));
00549 
00550     pktinfo.ipi6_ifindex = ifindex;
00551 
00552     return ancdata_new(AF_INET6, IPPROTO_IPV6, IPV6_PKTINFO, rb_str_new((char *)&pktinfo, sizeof(pktinfo)));
00553 }
00554 #else
00555 #define ancillary_s_ipv6_pktinfo rb_f_notimplement
00556 #endif
00557 
00558 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */
00559 static void
00560 extract_ipv6_pktinfo(VALUE self, struct in6_pktinfo *pktinfo_ptr, struct sockaddr_in6 *sa_ptr)
00561 {
00562     int level, type;
00563     VALUE data;
00564 
00565     level = ancillary_level(self);
00566     type = ancillary_type(self);
00567     data = ancillary_data(self);
00568 
00569     if (level != IPPROTO_IPV6 || type != IPV6_PKTINFO ||
00570         RSTRING_LEN(data) != sizeof(struct in6_pktinfo)) {
00571         rb_raise(rb_eTypeError, "IPV6_PKTINFO ancillary data expected");
00572     }
00573 
00574     memcpy(pktinfo_ptr, RSTRING_PTR(data), sizeof(*pktinfo_ptr));
00575 
00576     memset(sa_ptr, 0, sizeof(*sa_ptr));
00577     SET_SA_LEN((struct sockaddr *)sa_ptr, sizeof(struct sockaddr_in6));
00578     sa_ptr->sin6_family = AF_INET6;
00579     memcpy(&sa_ptr->sin6_addr, &pktinfo_ptr->ipi6_addr, sizeof(sa_ptr->sin6_addr));
00580     if (IN6_IS_ADDR_LINKLOCAL(&sa_ptr->sin6_addr))
00581         sa_ptr->sin6_scope_id = pktinfo_ptr->ipi6_ifindex;
00582 }
00583 #endif
00584 
00585 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */
00586 /*
00587  * call-seq:
00588  *   ancdata.ipv6_pktinfo => [addr, ifindex]
00589  *
00590  * Extracts addr and ifindex from IPV6_PKTINFO ancillary data.
00591  *
00592  * IPV6_PKTINFO is defined by RFC 3542.
00593  *
00594  *   addr = Addrinfo.ip("::1")
00595  *   ifindex = 0
00596  *   ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
00597  *   p ancdata.ipv6_pktinfo #=> [#<Addrinfo: ::1>, 0]
00598  *
00599  */
00600 static VALUE
00601 ancillary_ipv6_pktinfo(VALUE self)
00602 {
00603     struct in6_pktinfo pktinfo;
00604     struct sockaddr_in6 sa;
00605     VALUE v_addr;
00606 
00607     extract_ipv6_pktinfo(self, &pktinfo, &sa);
00608     v_addr = rsock_addrinfo_new((struct sockaddr *)&sa, (socklen_t)sizeof(sa), PF_INET6, 0, 0, Qnil, Qnil);
00609     return rb_ary_new3(2, v_addr, UINT2NUM(pktinfo.ipi6_ifindex));
00610 }
00611 #else
00612 #define ancillary_ipv6_pktinfo rb_f_notimplement
00613 #endif
00614 
00615 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */
00616 /*
00617  * call-seq:
00618  *   ancdata.ipv6_pktinfo_addr => addr
00619  *
00620  * Extracts addr from IPV6_PKTINFO ancillary data.
00621  *
00622  * IPV6_PKTINFO is defined by RFC 3542.
00623  *
00624  *   addr = Addrinfo.ip("::1")
00625  *   ifindex = 0
00626  *   ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
00627  *   p ancdata.ipv6_pktinfo_addr #=> #<Addrinfo: ::1>
00628  *
00629  */
00630 static VALUE
00631 ancillary_ipv6_pktinfo_addr(VALUE self)
00632 {
00633     struct in6_pktinfo pktinfo;
00634     struct sockaddr_in6 sa;
00635     extract_ipv6_pktinfo(self, &pktinfo, &sa);
00636     return rsock_addrinfo_new((struct sockaddr *)&sa, (socklen_t)sizeof(sa), PF_INET6, 0, 0, Qnil, Qnil);
00637 }
00638 #else
00639 #define ancillary_ipv6_pktinfo_addr rb_f_notimplement
00640 #endif
00641 
00642 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */
00643 /*
00644  * call-seq:
00645  *   ancdata.ipv6_pktinfo_ifindex => addr
00646  *
00647  * Extracts ifindex from IPV6_PKTINFO ancillary data.
00648  *
00649  * IPV6_PKTINFO is defined by RFC 3542.
00650  *
00651  *   addr = Addrinfo.ip("::1")
00652  *   ifindex = 0
00653  *   ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
00654  *   p ancdata.ipv6_pktinfo_ifindex #=> 0
00655  *
00656  */
00657 static VALUE
00658 ancillary_ipv6_pktinfo_ifindex(VALUE self)
00659 {
00660     struct in6_pktinfo pktinfo;
00661     struct sockaddr_in6 sa;
00662     extract_ipv6_pktinfo(self, &pktinfo, &sa);
00663     return UINT2NUM(pktinfo.ipi6_ifindex);
00664 }
00665 #else
00666 #define ancillary_ipv6_pktinfo_ifindex rb_f_notimplement
00667 #endif
00668 
00669 #if defined(SOL_SOCKET) && defined(SCM_RIGHTS) /* 4.4BSD */
00670 static int
00671 anc_inspect_socket_rights(int level, int type, VALUE data, VALUE ret)
00672 {
00673     if (level == SOL_SOCKET && type == SCM_RIGHTS &&
00674         0 < RSTRING_LEN(data) && (RSTRING_LEN(data) % sizeof(int) == 0)) {
00675         long off;
00676         for (off = 0; off < RSTRING_LEN(data); off += sizeof(int)) {
00677             int fd;
00678             memcpy((char*)&fd, RSTRING_PTR(data)+off, sizeof(int));
00679             rb_str_catf(ret, " %d", fd);
00680         }
00681         return 1;
00682     }
00683     else {
00684         return 0;
00685     }
00686 }
00687 #endif
00688 
00689 #if defined(SCM_CREDENTIALS) /* GNU/Linux */
00690 static int
00691 anc_inspect_passcred_credentials(int level, int type, VALUE data, VALUE ret)
00692 {
00693     if (level == SOL_SOCKET && type == SCM_CREDENTIALS &&
00694         RSTRING_LEN(data) == sizeof(struct ucred)) {
00695         struct ucred cred;
00696         memcpy(&cred, RSTRING_PTR(data), sizeof(struct ucred));
00697         rb_str_catf(ret, " pid=%u uid=%u gid=%u", cred.pid, cred.uid, cred.gid);
00698         rb_str_cat2(ret, " (ucred)");
00699         return 1;
00700     }
00701     else {
00702         return 0;
00703     }
00704 }
00705 #endif
00706 
00707 #if defined(SCM_CREDS)
00708 #define INSPECT_SCM_CREDS
00709 static int
00710 anc_inspect_socket_creds(int level, int type, VALUE data, VALUE ret)
00711 {
00712     if (level != SOL_SOCKET && type != SCM_CREDS)
00713         return 0;
00714 
00715     /*
00716      * FreeBSD has struct cmsgcred and struct sockcred.
00717      * They use both SOL_SOCKET/SCM_CREDS in the ancillary message.
00718      * They are not ambiguous from the view of the caller
00719      * because struct sockcred is sent if and only if the caller sets LOCAL_CREDS socket option.
00720      * But inspect method doesn't know it.
00721      * So they are ambiguous from the view of inspect.
00722      * This function distinguish them by the size of the ancillary message.
00723      * This heuristics works well except when sc_ngroups == CMGROUP_MAX.
00724      */
00725 
00726 #if defined(HAVE_TYPE_STRUCT_CMSGCRED) /* FreeBSD */
00727     if (RSTRING_LEN(data) == sizeof(struct cmsgcred)) {
00728         struct cmsgcred cred;
00729         memcpy(&cred, RSTRING_PTR(data), sizeof(struct cmsgcred));
00730         rb_str_catf(ret, " pid=%u", cred.cmcred_pid);
00731         rb_str_catf(ret, " uid=%u", cred.cmcred_uid);
00732         rb_str_catf(ret, " euid=%u", cred.cmcred_euid);
00733         rb_str_catf(ret, " gid=%u", cred.cmcred_gid);
00734         if (cred.cmcred_ngroups) {
00735             int i;
00736             const char *sep = " groups=";
00737             for (i = 0; i < cred.cmcred_ngroups; i++) {
00738                 rb_str_catf(ret, "%s%u", sep, cred.cmcred_groups[i]);
00739                 sep = ",";
00740             }
00741         }
00742         rb_str_cat2(ret, " (cmsgcred)");
00743         return 1;
00744     }
00745 #endif
00746 #if defined(HAVE_TYPE_STRUCT_SOCKCRED) /* FreeBSD, NetBSD */
00747     if ((size_t)RSTRING_LEN(data) >= SOCKCREDSIZE(0)) {
00748         struct sockcred cred0, *cred;
00749         memcpy(&cred0, RSTRING_PTR(data), SOCKCREDSIZE(0));
00750         if ((size_t)RSTRING_LEN(data) == SOCKCREDSIZE(cred0.sc_ngroups)) {
00751             cred = (struct sockcred *)ALLOCA_N(char, SOCKCREDSIZE(cred0.sc_ngroups));
00752             memcpy(cred, RSTRING_PTR(data), SOCKCREDSIZE(cred0.sc_ngroups));
00753             rb_str_catf(ret, " uid=%u", cred->sc_uid);
00754             rb_str_catf(ret, " euid=%u", cred->sc_euid);
00755             rb_str_catf(ret, " gid=%u", cred->sc_gid);
00756             rb_str_catf(ret, " egid=%u", cred->sc_egid);
00757             if (cred0.sc_ngroups) {
00758                 int i;
00759                 const char *sep = " groups=";
00760                 for (i = 0; i < cred0.sc_ngroups; i++) {
00761                     rb_str_catf(ret, "%s%u", sep, cred->sc_groups[i]);
00762                     sep = ",";
00763                 }
00764             }
00765             rb_str_cat2(ret, " (sockcred)");
00766             return 1;
00767         }
00768     }
00769 #endif
00770     return 0;
00771 }
00772 #endif
00773 
00774 #if defined(IPPROTO_IP) && defined(IP_RECVDSTADDR) /* 4.4BSD */
00775 static int
00776 anc_inspect_ip_recvdstaddr(int level, int type, VALUE data, VALUE ret)
00777 {
00778     if (level == IPPROTO_IP && type == IP_RECVDSTADDR &&
00779         RSTRING_LEN(data) == sizeof(struct in_addr)) {
00780         struct in_addr addr;
00781         char addrbuf[INET_ADDRSTRLEN];
00782         memcpy(&addr, RSTRING_PTR(data), sizeof(addr));
00783         if (inet_ntop(AF_INET, &addr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
00784             rb_str_cat2(ret, " invalid-address");
00785         else
00786             rb_str_catf(ret, " %s", addrbuf);
00787         return 1;
00788     }
00789     else {
00790         return 0;
00791     }
00792 }
00793 #endif
00794 
00795 #if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST) /* GNU/Linux */
00796 static int
00797 anc_inspect_ip_pktinfo(int level, int type, VALUE data, VALUE ret)
00798 {
00799     if (level == IPPROTO_IP && type == IP_PKTINFO &&
00800         RSTRING_LEN(data) == sizeof(struct in_pktinfo)) {
00801         struct in_pktinfo pktinfo;
00802         char buf[INET_ADDRSTRLEN > IFNAMSIZ ? INET_ADDRSTRLEN : IFNAMSIZ];
00803         memcpy(&pktinfo, RSTRING_PTR(data), sizeof(pktinfo));
00804         if (inet_ntop(AF_INET, &pktinfo.ipi_addr, buf, sizeof(buf)) == NULL)
00805             rb_str_cat2(ret, " invalid-address");
00806         else
00807             rb_str_catf(ret, " %s", buf);
00808         if (if_indextoname(pktinfo.ipi_ifindex, buf) == NULL)
00809             rb_str_catf(ret, " ifindex:%d", pktinfo.ipi_ifindex);
00810         else
00811             rb_str_catf(ret, " %s", buf);
00812         if (inet_ntop(AF_INET, &pktinfo.ipi_spec_dst, buf, sizeof(buf)) == NULL)
00813             rb_str_cat2(ret, " spec_dst:invalid-address");
00814         else
00815             rb_str_catf(ret, " spec_dst:%s", buf);
00816         return 1;
00817     }
00818     else {
00819         return 0;
00820     }
00821 }
00822 #endif
00823 
00824 #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) && defined(HAVE_TYPE_STRUCT_IN6_PKTINFO) /* IPv6 RFC3542 */
00825 static int
00826 anc_inspect_ipv6_pktinfo(int level, int type, VALUE data, VALUE ret)
00827 {
00828     if (level == IPPROTO_IPV6 && type == IPV6_PKTINFO &&
00829         RSTRING_LEN(data) == sizeof(struct in6_pktinfo)) {
00830         struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)RSTRING_PTR(data);
00831         struct in6_addr addr;
00832         unsigned int ifindex;
00833         char addrbuf[INET6_ADDRSTRLEN], ifbuf[IFNAMSIZ];
00834         memcpy(&addr, &pktinfo->ipi6_addr, sizeof(addr));
00835         memcpy(&ifindex, &pktinfo->ipi6_ifindex, sizeof(ifindex));
00836         if (inet_ntop(AF_INET6, &addr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
00837             rb_str_cat2(ret, " invalid-address");
00838         else
00839             rb_str_catf(ret, " %s", addrbuf);
00840         if (if_indextoname(ifindex, ifbuf) == NULL)
00841             rb_str_catf(ret, " ifindex:%d", ifindex);
00842         else
00843             rb_str_catf(ret, " %s", ifbuf);
00844         return 1;
00845     }
00846     else {
00847         return 0;
00848     }
00849 }
00850 #endif
00851 
00852 #if defined(SCM_TIMESTAMP) /* GNU/Linux, FreeBSD, NetBSD, OpenBSD, MacOS X, Solaris */
00853 static int
00854 inspect_timeval_as_abstime(int level, int optname, VALUE data, VALUE ret)
00855 {
00856     if (RSTRING_LEN(data) == sizeof(struct timeval)) {
00857         struct timeval tv;
00858         time_t time;
00859         struct tm tm;
00860         char buf[32];
00861         memcpy((char*)&tv, RSTRING_PTR(data), sizeof(tv));
00862         time = tv.tv_sec;
00863         tm = *localtime(&time);
00864         strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
00865         rb_str_catf(ret, " %s.%06ld", buf, (long)tv.tv_usec);
00866         return 1;
00867     }
00868     else {
00869         return 0;
00870     }
00871 }
00872 #endif
00873 
00874 #if defined(SCM_TIMESTAMPNS) /* GNU/Linux */
00875 static int
00876 inspect_timespec_as_abstime(int level, int optname, VALUE data, VALUE ret)
00877 {
00878     if (RSTRING_LEN(data) == sizeof(struct timespec)) {
00879         struct timespec ts;
00880         struct tm tm;
00881         char buf[32];
00882         memcpy((char*)&ts, RSTRING_PTR(data), sizeof(ts));
00883         tm = *localtime(&ts.tv_sec);
00884         strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
00885         rb_str_catf(ret, " %s.%09ld", buf, (long)ts.tv_nsec);
00886         return 1;
00887     }
00888     else {
00889         return 0;
00890     }
00891 }
00892 #endif
00893 
00894 #if defined(SCM_BINTIME) /* FreeBSD */
00895 static int
00896 inspect_bintime_as_abstime(int level, int optname, VALUE data, VALUE ret)
00897 {
00898     if (RSTRING_LEN(data) == sizeof(struct bintime)) {
00899         struct bintime bt;
00900         struct tm tm;
00901         uint64_t frac_h, frac_l;
00902         uint64_t scale_h, scale_l;
00903         uint64_t tmp1, tmp2;
00904         uint64_t res_h, res_l;
00905         char buf[32];
00906         memcpy((char*)&bt, RSTRING_PTR(data), sizeof(bt));
00907         tm = *localtime(&bt.sec);
00908         strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
00909 
00910         /* res_h = frac * 10**19 / 2**64 */
00911 
00912         frac_h = bt.frac >> 32;
00913         frac_l = bt.frac & 0xffffffff;
00914 
00915         scale_h = 0x8ac72304; /* 0x8ac7230489e80000 == 10**19 */
00916         scale_l = 0x89e80000;
00917 
00918         res_h = frac_h * scale_h;
00919         res_l = frac_l * scale_l;
00920 
00921         tmp1 = frac_h * scale_l;
00922         res_h += tmp1 >> 32;
00923         tmp2 = res_l;
00924         res_l += tmp1 & 0xffffffff;
00925         if (res_l < tmp2) res_h++;
00926 
00927         tmp1 = frac_l * scale_h;
00928         res_h += tmp1 >> 32;
00929         tmp2 = res_l;
00930         res_l += tmp1 & 0xffffffff;
00931         if (res_l < tmp2) res_h++;
00932 
00933         rb_str_catf(ret, " %s.%019"PRIu64, buf, res_h);
00934         return 1;
00935     }
00936     else {
00937         return 0;
00938     }
00939 }
00940 #endif
00941 
00942 /*
00943  * call-seq:
00944  *   ancillarydata.inspect => string
00945  *
00946  * returns a string which shows ancillarydata in human-readable form.
00947  *
00948  *   p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").inspect
00949  *   #=> "#<Socket::AncillaryData: INET6 IPV6 PKTINFO \"\">"
00950  */
00951 static VALUE
00952 ancillary_inspect(VALUE self)
00953 {
00954     VALUE ret;
00955     int family, level, type;
00956     VALUE data;
00957     ID family_id, level_id, type_id;
00958     VALUE vtype;
00959     int inspected;
00960 
00961     family = ancillary_family(self);
00962     level = ancillary_level(self);
00963     type = ancillary_type(self);
00964     data = ancillary_data(self);
00965 
00966     ret = rb_sprintf("#<%s:", rb_obj_classname(self));
00967 
00968     family_id = rsock_intern_family_noprefix(family);
00969     if (family_id)
00970         rb_str_catf(ret, " %s", rb_id2name(family_id));
00971     else
00972         rb_str_catf(ret, " family:%d", family);
00973 
00974     if (level == SOL_SOCKET) {
00975         rb_str_cat2(ret, " SOCKET");
00976 
00977         type_id = rsock_intern_scm_optname(type);
00978         if (type_id)
00979             rb_str_catf(ret, " %s", rb_id2name(type_id));
00980         else
00981             rb_str_catf(ret, " cmsg_type:%d", type);
00982     }
00983     else if (IS_IP_FAMILY(family)) {
00984         level_id = rsock_intern_iplevel(level);
00985         if (level_id)
00986             rb_str_catf(ret, " %s", rb_id2name(level_id));
00987         else
00988             rb_str_catf(ret, " cmsg_level:%d", level);
00989 
00990         vtype = ip_cmsg_type_to_sym(level, type);
00991         if (SYMBOL_P(vtype))
00992             rb_str_catf(ret, " %s", rb_id2name(SYM2ID(vtype)));
00993         else
00994             rb_str_catf(ret, " cmsg_type:%d", type);
00995     }
00996     else {
00997         rb_str_catf(ret, " cmsg_level:%d", level);
00998         rb_str_catf(ret, " cmsg_type:%d", type);
00999     }
01000 
01001     inspected = 0;
01002 
01003     if (level == SOL_SOCKET)
01004         family = AF_UNSPEC;
01005 
01006     switch (family) {
01007       case AF_UNSPEC:
01008         switch (level) {
01009 #        if defined(SOL_SOCKET)
01010           case SOL_SOCKET:
01011             switch (type) {
01012 #            if defined(SCM_TIMESTAMP) /* GNU/Linux, FreeBSD, NetBSD, OpenBSD, MacOS X, Solaris */
01013               case SCM_TIMESTAMP: inspected = inspect_timeval_as_abstime(level, type, data, ret); break;
01014 #            endif
01015 #            if defined(SCM_TIMESTAMPNS) /* GNU/Linux */
01016               case SCM_TIMESTAMPNS: inspected = inspect_timespec_as_abstime(level, type, data, ret); break;
01017 #            endif
01018 #            if defined(SCM_BINTIME) /* FreeBSD */
01019               case SCM_BINTIME: inspected = inspect_bintime_as_abstime(level, type, data, ret); break;
01020 #            endif
01021 #            if defined(SCM_RIGHTS) /* 4.4BSD */
01022               case SCM_RIGHTS: inspected = anc_inspect_socket_rights(level, type, data, ret); break;
01023 #            endif
01024 #            if defined(SCM_CREDENTIALS) /* GNU/Linux */
01025               case SCM_CREDENTIALS: inspected = anc_inspect_passcred_credentials(level, type, data, ret); break;
01026 #            endif
01027 #            if defined(INSPECT_SCM_CREDS) /* NetBSD */
01028               case SCM_CREDS: inspected = anc_inspect_socket_creds(level, type, data, ret); break;
01029 #            endif
01030             }
01031             break;
01032 #        endif
01033         }
01034         break;
01035 
01036       case AF_INET:
01037 #ifdef INET6
01038       case AF_INET6:
01039 #endif
01040         switch (level) {
01041 #        if defined(IPPROTO_IP)
01042           case IPPROTO_IP:
01043             switch (type) {
01044 #            if defined(IP_RECVDSTADDR) /* 4.4BSD */
01045               case IP_RECVDSTADDR: inspected = anc_inspect_ip_recvdstaddr(level, type, data, ret); break;
01046 #            endif
01047 #            if defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST) /* GNU/Linux */
01048               case IP_PKTINFO: inspected = anc_inspect_ip_pktinfo(level, type, data, ret); break;
01049 #            endif
01050             }
01051             break;
01052 #        endif
01053 
01054 #        if defined(IPPROTO_IPV6)
01055           case IPPROTO_IPV6:
01056             switch (type) {
01057 #            if defined(IPV6_PKTINFO) /* RFC 3542 */
01058               case IPV6_PKTINFO: inspected = anc_inspect_ipv6_pktinfo(level, type, data, ret); break;
01059 #            endif
01060             }
01061             break;
01062 #        endif
01063         }
01064         break;
01065     }
01066 
01067     if (!inspected) {
01068         rb_str_cat2(ret, " ");
01069         rb_str_append(ret, rb_str_dump(data));
01070     }
01071 
01072     rb_str_cat2(ret, ">");
01073 
01074     return ret;
01075 }
01076 
01077 /*
01078  * call-seq:
01079  *   ancillarydata.cmsg_is?(level, type) => true or false
01080  *
01081  * tests the level and type of _ancillarydata_.
01082  *
01083  *   ancdata = Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "")
01084  *   ancdata.cmsg_is?(Socket::IPPROTO_IPV6, Socket::IPV6_PKTINFO) #=> true
01085  *   ancdata.cmsg_is?(:IPV6, :PKTINFO)       #=> true
01086  *   ancdata.cmsg_is?(:IP, :PKTINFO)         #=> false
01087  *   ancdata.cmsg_is?(:SOCKET, :RIGHTS)      #=> false
01088  */
01089 static VALUE
01090 ancillary_cmsg_is_p(VALUE self, VALUE vlevel, VALUE vtype)
01091 {
01092     int family = ancillary_family(self);
01093     int level = rsock_level_arg(family, vlevel);
01094     int type = rsock_cmsg_type_arg(family, level, vtype);
01095 
01096     if (ancillary_level(self) == level &&
01097         ancillary_type(self) == type)
01098         return Qtrue;
01099     else
01100         return Qfalse;
01101 }
01102 
01103 #endif
01104 
01105 #if defined(HAVE_SENDMSG)
01106 struct sendmsg_args_struct {
01107     int fd;
01108     const struct msghdr *msg;
01109     int flags;
01110 };
01111 
01112 static void *
01113 nogvl_sendmsg_func(void *ptr)
01114 {
01115     struct sendmsg_args_struct *args = ptr;
01116     return (void *)(VALUE)sendmsg(args->fd, args->msg, args->flags);
01117 }
01118 
01119 static ssize_t
01120 rb_sendmsg(int fd, const struct msghdr *msg, int flags)
01121 {
01122     struct sendmsg_args_struct args;
01123     args.fd = fd;
01124     args.msg = msg;
01125     args.flags = flags;
01126     return (ssize_t)rb_thread_call_without_gvl(nogvl_sendmsg_func, &args, RUBY_UBF_IO, 0);
01127 }
01128 
01129 static VALUE
01130 bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
01131 {
01132     rb_io_t *fptr;
01133     VALUE data, vflags, dest_sockaddr;
01134     VALUE *controls_ptr;
01135     int controls_num;
01136     struct msghdr mh;
01137     struct iovec iov;
01138 #if defined(HAVE_ST_MSG_CONTROL)
01139     volatile VALUE controls_str = 0;
01140 #endif
01141     int flags;
01142     ssize_t ss;
01143     int family;
01144 
01145     rb_secure(4);
01146     GetOpenFile(sock, fptr);
01147     family = rsock_getfamily(fptr->fd);
01148 
01149     data = vflags = dest_sockaddr = Qnil;
01150     controls_ptr = NULL;
01151     controls_num = 0;
01152 
01153     if (argc == 0)
01154         rb_raise(rb_eArgError, "mesg argument required");
01155     data = argv[0];
01156     if (1 < argc) vflags = argv[1];
01157     if (2 < argc) dest_sockaddr = argv[2];
01158     if (3 < argc) { controls_ptr = &argv[3]; controls_num = argc - 3; }
01159 
01160     StringValue(data);
01161 
01162     if (controls_num) {
01163 #if defined(HAVE_ST_MSG_CONTROL)
01164         int i;
01165         size_t last_pad = 0;
01166 #if defined(__NetBSD__)
01167         int last_level = 0;
01168         int last_type = 0;
01169 #endif
01170         controls_str = rb_str_tmp_new(0);
01171         for (i = 0; i < controls_num; i++) {
01172             VALUE elt = controls_ptr[i], v;
01173             VALUE vlevel, vtype;
01174             int level, type;
01175             VALUE cdata;
01176             long oldlen;
01177             struct cmsghdr cmh;
01178             char *cmsg;
01179             size_t cspace;
01180             v = rb_check_convert_type(elt, T_ARRAY, "Array", "to_ary");
01181             if (!NIL_P(v)) {
01182                 elt = v;
01183                 if (RARRAY_LEN(elt) != 3)
01184                     rb_raise(rb_eArgError, "an element of controls should be 3-elements array");
01185                 vlevel = rb_ary_entry(elt, 0);
01186                 vtype = rb_ary_entry(elt, 1);
01187                 cdata = rb_ary_entry(elt, 2);
01188             }
01189             else {
01190                 vlevel = rb_funcall(elt, rb_intern("level"), 0);
01191                 vtype = rb_funcall(elt, rb_intern("type"), 0);
01192                 cdata = rb_funcall(elt, rb_intern("data"), 0);
01193             }
01194             level = rsock_level_arg(family, vlevel);
01195             type = rsock_cmsg_type_arg(family, level, vtype);
01196             StringValue(cdata);
01197             oldlen = RSTRING_LEN(controls_str);
01198             cspace = CMSG_SPACE(RSTRING_LEN(cdata));
01199             rb_str_resize(controls_str, oldlen + cspace);
01200             cmsg = RSTRING_PTR(controls_str)+oldlen;
01201             memset((char *)cmsg, 0, cspace);
01202             memset((char *)&cmh, 0, sizeof(cmh));
01203             cmh.cmsg_level = level;
01204             cmh.cmsg_type = type;
01205             cmh.cmsg_len = (socklen_t)CMSG_LEN(RSTRING_LEN(cdata));
01206             MEMCPY(cmsg, &cmh, char, sizeof(cmh));
01207             MEMCPY(cmsg+((char*)CMSG_DATA(&cmh)-(char*)&cmh), RSTRING_PTR(cdata), char, RSTRING_LEN(cdata));
01208 #if defined(__NetBSD__)
01209             last_level = cmh.cmsg_level;
01210             last_type = cmh.cmsg_type;
01211 #endif
01212             last_pad = cspace - cmh.cmsg_len;
01213         }
01214         if (last_pad) {
01215             /*
01216              * This code removes the last padding from msg_controllen.
01217              *
01218              * 4.3BSD-Reno reject the padding for SCM_RIGHTS. (There was no 64bit environments in those days?)
01219              * RFC 2292 require the padding.
01220              * RFC 3542 relaxes the condition - implementation must accept both as valid.
01221              *
01222              * Actual problems:
01223              *
01224              * - NetBSD 4.0.1
01225              *   SCM_RIGHTS with padding causes EINVAL
01226              *   IPV6_PKTINFO without padding causes "page fault trap"
01227              *     http://www.netbsd.org/cgi-bin/query-pr-single.pl?number=40661
01228              *
01229              * - OpenBSD 4.4
01230              *   IPV6_PKTINFO without padding causes EINVAL
01231              *
01232              * Basically, msg_controllen should contains the padding.
01233              * So the padding is removed only if a problem really exists.
01234              */
01235 #if defined(__NetBSD__)
01236             if (last_level == SOL_SOCKET && last_type == SCM_RIGHTS)
01237                 rb_str_set_len(controls_str, RSTRING_LEN(controls_str)-last_pad);
01238 #endif
01239         }
01240 #else
01241         rb_raise(rb_eNotImpError, "control message for sendmsg is unimplemented");
01242 #endif
01243     }
01244 
01245     flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
01246 #ifdef MSG_DONTWAIT
01247     if (nonblock)
01248         flags |= MSG_DONTWAIT;
01249 #endif
01250 
01251     if (!NIL_P(dest_sockaddr))
01252         SockAddrStringValue(dest_sockaddr);
01253 
01254     rb_io_check_closed(fptr);
01255 
01256   retry:
01257     memset(&mh, 0, sizeof(mh));
01258     if (!NIL_P(dest_sockaddr)) {
01259         mh.msg_name = RSTRING_PTR(dest_sockaddr);
01260         mh.msg_namelen = RSTRING_LENINT(dest_sockaddr);
01261     }
01262     mh.msg_iovlen = 1;
01263     mh.msg_iov = &iov;
01264     iov.iov_base = RSTRING_PTR(data);
01265     iov.iov_len = RSTRING_LEN(data);
01266 #if defined(HAVE_ST_MSG_CONTROL)
01267     if (controls_str) {
01268         mh.msg_control = RSTRING_PTR(controls_str);
01269         mh.msg_controllen = RSTRING_LENINT(controls_str);
01270     }
01271     else {
01272         mh.msg_control = NULL;
01273         mh.msg_controllen = 0;
01274     }
01275 #endif
01276 
01277     rb_io_check_closed(fptr);
01278     if (nonblock)
01279         rb_io_set_nonblock(fptr);
01280 
01281     ss = rb_sendmsg(fptr->fd, &mh, flags);
01282 
01283     if (!nonblock && rb_io_wait_writable(fptr->fd)) {
01284         rb_io_check_closed(fptr);
01285         goto retry;
01286     }
01287 
01288     if (ss == -1) {
01289         if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
01290             rb_mod_sys_fail(rb_mWaitWritable, "sendmsg(2) would block");
01291         rb_sys_fail("sendmsg(2)");
01292     }
01293 
01294     return SSIZET2NUM(ss);
01295 }
01296 #endif
01297 
01298 #if defined(HAVE_SENDMSG)
01299 /*
01300  * call-seq:
01301  *    basicsocket.sendmsg(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent
01302  *
01303  * sendmsg sends a message using sendmsg(2) system call in blocking manner.
01304  *
01305  * _mesg_ is a string to send.
01306  *
01307  * _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_OOB.
01308  *
01309  * _dest_sockaddr_ is a destination socket address for connection-less socket.
01310  * It should be a sockaddr such as a result of Socket.sockaddr_in.
01311  * An Addrinfo object can be used too.
01312  *
01313  * _controls_ is a list of ancillary data.
01314  * The element of _controls_ should be Socket::AncillaryData or
01315  * 3-elements array.
01316  * The 3-element array should contains cmsg_level, cmsg_type and data.
01317  *
01318  * The return value, _numbytes_sent_ is an integer which is the number of bytes sent.
01319  *
01320  * sendmsg can be used to implement send_io as follows:
01321  *
01322  *   # use Socket::AncillaryData.
01323  *   ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, io.fileno)
01324  *   sock.sendmsg("a", 0, nil, ancdata)
01325  *
01326  *   # use 3-element array.
01327  *   ancdata = [:SOCKET, :RIGHTS, [io.fileno].pack("i!")]
01328  *   sock.sendmsg("\0", 0, nil, ancdata)
01329  *
01330  */
01331 VALUE
01332 rsock_bsock_sendmsg(int argc, VALUE *argv, VALUE sock)
01333 {
01334     return bsock_sendmsg_internal(argc, argv, sock, 0);
01335 }
01336 #endif
01337 
01338 #if defined(HAVE_SENDMSG)
01339 /*
01340  * call-seq:
01341  *    basicsocket.sendmsg_nonblock(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent
01342  *
01343  * sendmsg_nonblock sends a message using sendmsg(2) system call in non-blocking manner.
01344  *
01345  * It is similar to BasicSocket#sendmsg
01346  * but the non-blocking flag is set before the system call
01347  * and it doesn't retry the system call.
01348  *
01349  */
01350 VALUE
01351 rsock_bsock_sendmsg_nonblock(int argc, VALUE *argv, VALUE sock)
01352 {
01353     return bsock_sendmsg_internal(argc, argv, sock, 1);
01354 }
01355 #endif
01356 
01357 #if defined(HAVE_RECVMSG)
01358 struct recvmsg_args_struct {
01359     int fd;
01360     struct msghdr *msg;
01361     int flags;
01362 };
01363 
01364 ssize_t
01365 rsock_recvmsg(int socket, struct msghdr *message, int flags)
01366 {
01367 #ifdef MSG_CMSG_CLOEXEC
01368     /* MSG_CMSG_CLOEXEC is available since Linux 2.6.23.  Linux 2.6.18 silently ignore it. */
01369     flags |= MSG_CMSG_CLOEXEC;
01370 #endif
01371     return recvmsg(socket, message, flags);
01372 }
01373 
01374 static void *
01375 nogvl_recvmsg_func(void *ptr)
01376 {
01377     struct recvmsg_args_struct *args = ptr;
01378     int flags = args->flags;
01379     return (void *)rsock_recvmsg(args->fd, args->msg, flags);
01380 }
01381 
01382 static ssize_t
01383 rb_recvmsg(int fd, struct msghdr *msg, int flags)
01384 {
01385     struct recvmsg_args_struct args;
01386     args.fd = fd;
01387     args.msg = msg;
01388     args.flags = flags;
01389     return (ssize_t)rb_thread_call_without_gvl(nogvl_recvmsg_func, &args, RUBY_UBF_IO, 0);
01390 }
01391 
01392 #if defined(HAVE_ST_MSG_CONTROL)
01393 static void
01394 discard_cmsg(struct cmsghdr *cmh, char *msg_end, int msg_peek_p)
01395 {
01396 # if !defined(FD_PASSING_WORK_WITH_RECVMSG_MSG_PEEK)
01397     /*
01398      * FreeBSD 8.2.0, NetBSD 5 and MacOS X Snow Leopard doesn't
01399      * allocate fds by recvmsg with MSG_PEEK.
01400      * [ruby-dev:44189]
01401      * http://bugs.ruby-lang.org/issues/5075
01402      *
01403      * Linux 2.6.38 allocate fds by recvmsg with MSG_PEEK.
01404      */
01405     if (msg_peek_p)
01406         return;
01407 # endif
01408     if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
01409         int *fdp = (int *)CMSG_DATA(cmh);
01410         int *end = (int *)((char *)cmh + cmh->cmsg_len);
01411         while ((char *)fdp + sizeof(int) <= (char *)end &&
01412                (char *)fdp + sizeof(int) <= msg_end) {
01413             rb_fd_fix_cloexec(*fdp);
01414             close(*fdp);
01415             fdp++;
01416         }
01417     }
01418 }
01419 #endif
01420 
01421 void
01422 rsock_discard_cmsg_resource(struct msghdr *mh, int msg_peek_p)
01423 {
01424 #if defined(HAVE_ST_MSG_CONTROL)
01425     struct cmsghdr *cmh;
01426     char *msg_end;
01427 
01428     if (mh->msg_controllen == 0)
01429         return;
01430 
01431     msg_end = (char *)mh->msg_control + mh->msg_controllen;
01432 
01433     for (cmh = CMSG_FIRSTHDR(mh); cmh != NULL; cmh = CMSG_NXTHDR(mh, cmh)) {
01434         discard_cmsg(cmh, msg_end, msg_peek_p);
01435     }
01436 #endif
01437 }
01438 
01439 #if defined(HAVE_ST_MSG_CONTROL)
01440 static void
01441 make_io_for_unix_rights(VALUE ctl, struct cmsghdr *cmh, char *msg_end)
01442 {
01443     if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
01444         int *fdp, *end;
01445         VALUE ary = rb_ary_new();
01446         rb_ivar_set(ctl, rb_intern("unix_rights"), ary);
01447         fdp = (int *)CMSG_DATA(cmh);
01448         end = (int *)((char *)cmh + cmh->cmsg_len);
01449         while ((char *)fdp + sizeof(int) <= (char *)end &&
01450                (char *)fdp + sizeof(int) <= msg_end) {
01451             int fd = *fdp;
01452             struct stat stbuf;
01453             VALUE io;
01454             if (fstat(fd, &stbuf) == -1)
01455                 rb_raise(rb_eSocket, "invalid fd in SCM_RIGHTS");
01456             rb_fd_fix_cloexec(fd);
01457             if (S_ISSOCK(stbuf.st_mode))
01458                 io = rsock_init_sock(rb_obj_alloc(rb_cSocket), fd);
01459             else
01460                 io = rb_io_fdopen(fd, O_RDWR, NULL);
01461             ary = rb_attr_get(ctl, rb_intern("unix_rights"));
01462             rb_ary_push(ary, io);
01463             fdp++;
01464         }
01465         OBJ_FREEZE(ary);
01466     }
01467 }
01468 #endif
01469 
01470 static VALUE
01471 bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
01472 {
01473     rb_io_t *fptr;
01474     VALUE vmaxdatlen, vmaxctllen, vflags, vopts;
01475     int grow_buffer;
01476     size_t maxdatlen;
01477     int flags, orig_flags;
01478     int request_scm_rights;
01479     struct msghdr mh;
01480     struct iovec iov;
01481     struct sockaddr_storage namebuf;
01482     char datbuf0[4096], *datbuf;
01483     VALUE dat_str = Qnil;
01484     VALUE ret;
01485     ssize_t ss;
01486 #if defined(HAVE_ST_MSG_CONTROL)
01487     struct cmsghdr *cmh;
01488     size_t maxctllen;
01489     union {
01490         char bytes[4096];
01491         struct cmsghdr align;
01492     } ctlbuf0;
01493     char *ctlbuf;
01494     VALUE ctl_str = Qnil;
01495     int family;
01496     int gc_done = 0;
01497 #endif
01498 
01499     rb_secure(4);
01500 
01501     vopts = Qnil;
01502     if (0 < argc && RB_TYPE_P(argv[argc-1], T_HASH))
01503         vopts = argv[--argc];
01504 
01505     rb_scan_args(argc, argv, "03", &vmaxdatlen, &vflags, &vmaxctllen);
01506 
01507     maxdatlen = NIL_P(vmaxdatlen) ? sizeof(datbuf0) : NUM2SIZET(vmaxdatlen);
01508 #if defined(HAVE_ST_MSG_CONTROL)
01509     maxctllen = NIL_P(vmaxctllen) ? sizeof(ctlbuf0) : NUM2SIZET(vmaxctllen);
01510 #else
01511     if (!NIL_P(vmaxctllen))
01512         rb_raise(rb_eArgError, "control message not supported");
01513 #endif
01514     flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
01515 #ifdef MSG_DONTWAIT
01516     if (nonblock)
01517         flags |= MSG_DONTWAIT;
01518 #endif
01519     orig_flags = flags;
01520 
01521     grow_buffer = NIL_P(vmaxdatlen) || NIL_P(vmaxctllen);
01522 
01523     request_scm_rights = 0;
01524     if (!NIL_P(vopts) && RTEST(rb_hash_aref(vopts, ID2SYM(rb_intern("scm_rights")))))
01525         request_scm_rights = 1;
01526 
01527     GetOpenFile(sock, fptr);
01528     if (rb_io_read_pending(fptr)) {
01529         rb_raise(rb_eIOError, "recvmsg for buffered IO");
01530     }
01531 
01532 #if !defined(HAVE_ST_MSG_CONTROL)
01533     if (grow_buffer) {
01534         int socktype;
01535         socklen_t optlen = (socklen_t)sizeof(socktype);
01536         if (getsockopt(fptr->fd, SOL_SOCKET, SO_TYPE, (void*)&socktype, &optlen) == -1) {
01537             rb_sys_fail("getsockopt(SO_TYPE)");
01538         }
01539         if (socktype == SOCK_STREAM)
01540             grow_buffer = 0;
01541     }
01542 #endif
01543 
01544   retry:
01545     if (maxdatlen <= sizeof(datbuf0))
01546         datbuf = datbuf0;
01547     else {
01548         if (NIL_P(dat_str))
01549             dat_str = rb_str_tmp_new(maxdatlen);
01550         else
01551             rb_str_resize(dat_str, maxdatlen);
01552         datbuf = RSTRING_PTR(dat_str);
01553     }
01554 
01555 #if defined(HAVE_ST_MSG_CONTROL)
01556     if (maxctllen <= sizeof(ctlbuf0))
01557         ctlbuf = ctlbuf0.bytes;
01558     else {
01559         if (NIL_P(ctl_str))
01560             ctl_str = rb_str_tmp_new(maxctllen);
01561         else
01562             rb_str_resize(ctl_str, maxctllen);
01563         ctlbuf = RSTRING_PTR(ctl_str);
01564     }
01565 #endif
01566 
01567     memset(&mh, 0, sizeof(mh));
01568 
01569     memset(&namebuf, 0, sizeof(namebuf));
01570     mh.msg_name = (struct sockaddr *)&namebuf;
01571     mh.msg_namelen = (socklen_t)sizeof(namebuf);
01572 
01573     mh.msg_iov = &iov;
01574     mh.msg_iovlen = 1;
01575     iov.iov_base = datbuf;
01576     iov.iov_len = maxdatlen;
01577 
01578 #if defined(HAVE_ST_MSG_CONTROL)
01579     mh.msg_control = ctlbuf;
01580     mh.msg_controllen = (socklen_t)maxctllen;
01581 #endif
01582 
01583     if (grow_buffer)
01584         flags |= MSG_PEEK;
01585 
01586     rb_io_check_closed(fptr);
01587     if (nonblock)
01588         rb_io_set_nonblock(fptr);
01589 
01590     ss = rb_recvmsg(fptr->fd, &mh, flags);
01591 
01592     if (!nonblock && rb_io_wait_readable(fptr->fd)) {
01593         rb_io_check_closed(fptr);
01594         goto retry;
01595     }
01596 
01597     if (ss == -1) {
01598         if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
01599             rb_mod_sys_fail(rb_mWaitReadable, "recvmsg(2) would block");
01600 #if defined(HAVE_ST_MSG_CONTROL)
01601         if (!gc_done && (errno == EMFILE || errno == EMSGSIZE)) {
01602           /*
01603            * When SCM_RIGHTS hit the file descriptors limit:
01604            * - Linux 2.6.18 causes success with MSG_CTRUNC
01605            * - MacOS X 10.4 causes EMSGSIZE (and lost file descriptors?)
01606            * - Solaris 11 causes EMFILE
01607            */
01608           gc_and_retry:
01609             rb_gc();
01610             gc_done = 1;
01611             goto retry;
01612         }
01613 #endif
01614         rb_sys_fail("recvmsg(2)");
01615     }
01616 
01617     if (grow_buffer) {
01618         int grown = 0;
01619 #if defined(HAVE_ST_MSG_CONTROL)
01620         if (NIL_P(vmaxdatlen) && (mh.msg_flags & MSG_TRUNC)) {
01621             if (SIZE_MAX/2 < maxdatlen)
01622                 rb_raise(rb_eArgError, "max data length too big");
01623             maxdatlen *= 2;
01624             grown = 1;
01625         }
01626         if (NIL_P(vmaxctllen) && (mh.msg_flags & MSG_CTRUNC)) {
01627 #define BIG_ENOUGH_SPACE 65536
01628             if (BIG_ENOUGH_SPACE < maxctllen &&
01629                 mh.msg_controllen < (socklen_t)(maxctllen - BIG_ENOUGH_SPACE)) {
01630                 /* there are big space bug truncated.
01631                  * file descriptors limit? */
01632                 if (!gc_done) {
01633                     rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
01634                     goto gc_and_retry;
01635                 }
01636             }
01637             else {
01638                 if (SIZE_MAX/2 < maxctllen)
01639                     rb_raise(rb_eArgError, "max control message length too big");
01640                 maxctllen *= 2;
01641                 grown = 1;
01642             }
01643 #undef BIG_ENOUGH_SPACE
01644         }
01645 #else
01646         if (NIL_P(vmaxdatlen) && ss != -1 && ss == (ssize_t)iov.iov_len) {
01647             if (SIZE_MAX/2 < maxdatlen)
01648                 rb_raise(rb_eArgError, "max data length too big");
01649             maxdatlen *= 2;
01650             grown = 1;
01651         }
01652 #endif
01653         if (grown) {
01654             rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
01655             goto retry;
01656         }
01657         else {
01658             grow_buffer = 0;
01659             if (flags != orig_flags) {
01660                 rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
01661                 flags = orig_flags;
01662                 goto retry;
01663             }
01664         }
01665     }
01666 
01667     if (NIL_P(dat_str))
01668         dat_str = rb_tainted_str_new(datbuf, ss);
01669     else {
01670         rb_str_resize(dat_str, ss);
01671         OBJ_TAINT(dat_str);
01672         RBASIC(dat_str)->klass = rb_cString;
01673     }
01674 
01675     ret = rb_ary_new3(3, dat_str,
01676                          rsock_io_socket_addrinfo(sock, mh.msg_name, mh.msg_namelen),
01677 #if defined(HAVE_ST_MSG_CONTROL)
01678                          INT2NUM(mh.msg_flags)
01679 #else
01680                          Qnil
01681 #endif
01682                          );
01683 
01684 #if defined(HAVE_ST_MSG_CONTROL)
01685     family = rsock_getfamily(fptr->fd);
01686     if (mh.msg_controllen) {
01687         char *msg_end = (char *)mh.msg_control + mh.msg_controllen;
01688         for (cmh = CMSG_FIRSTHDR(&mh); cmh != NULL; cmh = CMSG_NXTHDR(&mh, cmh)) {
01689             VALUE ctl;
01690             char *ctl_end;
01691             size_t clen;
01692             if (cmh->cmsg_len == 0) {
01693                 rb_raise(rb_eTypeError, "invalid control message (cmsg_len == 0)");
01694             }
01695             ctl_end = (char*)cmh + cmh->cmsg_len;
01696             clen = (ctl_end <= msg_end ? ctl_end : msg_end) - (char*)CMSG_DATA(cmh);
01697             ctl = ancdata_new(family, cmh->cmsg_level, cmh->cmsg_type, rb_tainted_str_new((char*)CMSG_DATA(cmh), clen));
01698             if (request_scm_rights)
01699                 make_io_for_unix_rights(ctl, cmh, msg_end);
01700             else
01701                 discard_cmsg(cmh, msg_end, (flags & MSG_PEEK) != 0);
01702             rb_ary_push(ret, ctl);
01703         }
01704     }
01705 #endif
01706 
01707     return ret;
01708 }
01709 #endif
01710 
01711 #if defined(HAVE_RECVMSG)
01712 /*
01713  * call-seq:
01714  *    basicsocket.recvmsg(maxmesglen=nil, flags=0, maxcontrollen=nil, opts={}) => [mesg, sender_addrinfo, rflags, *controls]
01715  *
01716  * recvmsg receives a message using recvmsg(2) system call in blocking manner.
01717  *
01718  * _maxmesglen_ is the maximum length of mesg to receive.
01719  *
01720  * _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_PEEK.
01721  *
01722  * _maxcontrollen_ is the maximum length of controls (ancillary data) to receive.
01723  *
01724  * _opts_ is option hash.
01725  * Currently :scm_rights=>bool is the only option.
01726  *
01727  * :scm_rights option specifies that application expects SCM_RIGHTS control message.
01728  * If the value is nil or false, application don't expects SCM_RIGHTS control message.
01729  * In this case, recvmsg closes the passed file descriptors immediately.
01730  * This is the default behavior.
01731  *
01732  * If :scm_rights value is neither nil nor false, application expects SCM_RIGHTS control message.
01733  * In this case, recvmsg creates IO objects for each file descriptors for
01734  * Socket::AncillaryData#unix_rights method.
01735  *
01736  * The return value is 4-elements array.
01737  *
01738  * _mesg_ is a string of the received message.
01739  *
01740  * _sender_addrinfo_ is a sender socket address for connection-less socket.
01741  * It is an Addrinfo object.
01742  * For connection-oriented socket such as TCP, sender_addrinfo is platform dependent.
01743  *
01744  * _rflags_ is a flags on the received message which is bitwise OR of MSG_* constants such as Socket::MSG_TRUNC.
01745  * It will be nil if the system uses 4.3BSD style old recvmsg system call.
01746  *
01747  * _controls_ is ancillary data which is an array of Socket::AncillaryData objects such as:
01748  *
01749  *   #<Socket::AncillaryData: AF_UNIX SOCKET RIGHTS 7>
01750  *
01751  * _maxmesglen_ and _maxcontrollen_ can be nil.
01752  * In that case, the buffer will be grown until the message is not truncated.
01753  * Internally, MSG_PEEK is used and MSG_TRUNC/MSG_CTRUNC are checked.
01754  *
01755  * recvmsg can be used to implement recv_io as follows:
01756  *
01757  *   mesg, sender_sockaddr, rflags, *controls = sock.recvmsg(:scm_rights=>true)
01758  *   controls.each {|ancdata|
01759  *     if ancdata.cmsg_is?(:SOCKET, :RIGHTS)
01760  *       return ancdata.unix_rights[0]
01761  *     end
01762  *   }
01763  *
01764  */
01765 VALUE
01766 rsock_bsock_recvmsg(int argc, VALUE *argv, VALUE sock)
01767 {
01768     return bsock_recvmsg_internal(argc, argv, sock, 0);
01769 }
01770 #endif
01771 
01772 #if defined(HAVE_RECVMSG)
01773 /*
01774  * call-seq:
01775  *    basicsocket.recvmsg_nonblock(maxdatalen=nil, flags=0, maxcontrollen=nil, opts={}) => [data, sender_addrinfo, rflags, *controls]
01776  *
01777  * recvmsg receives a message using recvmsg(2) system call in non-blocking manner.
01778  *
01779  * It is similar to BasicSocket#recvmsg
01780  * but non-blocking flag is set before the system call
01781  * and it doesn't retry the system call.
01782  *
01783  */
01784 VALUE
01785 rsock_bsock_recvmsg_nonblock(int argc, VALUE *argv, VALUE sock)
01786 {
01787     return bsock_recvmsg_internal(argc, argv, sock, 1);
01788 }
01789 #endif
01790 
01791 void
01792 rsock_init_ancdata(void)
01793 {
01794 #if defined(HAVE_ST_MSG_CONTROL)
01795     /*
01796      * Document-class: Socket::AncillaryData
01797      *
01798      * Socket::AncillaryData represents the ancillary data (control information)
01799      * used by sendmsg and recvmsg system call.  It contains socket #family,
01800      * control message (cmsg) #level, cmsg #type and cmsg #data.
01801      */
01802     rb_cAncillaryData = rb_define_class_under(rb_cSocket, "AncillaryData", rb_cObject);
01803     rb_define_method(rb_cAncillaryData, "initialize", ancillary_initialize, 4);
01804     rb_define_method(rb_cAncillaryData, "inspect", ancillary_inspect, 0);
01805     rb_define_method(rb_cAncillaryData, "family", ancillary_family_m, 0);
01806     rb_define_method(rb_cAncillaryData, "level", ancillary_level_m, 0);
01807     rb_define_method(rb_cAncillaryData, "type", ancillary_type_m, 0);
01808     rb_define_method(rb_cAncillaryData, "data", ancillary_data, 0);
01809 
01810     rb_define_method(rb_cAncillaryData, "cmsg_is?", ancillary_cmsg_is_p, 2);
01811 
01812     rb_define_singleton_method(rb_cAncillaryData, "int", ancillary_s_int, 4);
01813     rb_define_method(rb_cAncillaryData, "int", ancillary_int, 0);
01814 
01815     rb_define_singleton_method(rb_cAncillaryData, "unix_rights", ancillary_s_unix_rights, -1);
01816     rb_define_method(rb_cAncillaryData, "unix_rights", ancillary_unix_rights, 0);
01817 
01818     rb_define_method(rb_cAncillaryData, "timestamp", ancillary_timestamp, 0);
01819 
01820     rb_define_singleton_method(rb_cAncillaryData, "ip_pktinfo", ancillary_s_ip_pktinfo, -1);
01821     rb_define_method(rb_cAncillaryData, "ip_pktinfo", ancillary_ip_pktinfo, 0);
01822 
01823     rb_define_singleton_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_s_ipv6_pktinfo, 2);
01824     rb_define_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_ipv6_pktinfo, 0);
01825     rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_addr", ancillary_ipv6_pktinfo_addr, 0);
01826     rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_ifindex", ancillary_ipv6_pktinfo_ifindex, 0);
01827 #endif
01828 }
01829