Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# 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, :RIGHTS, [0,s1.fileno].pack("ii")]
    00241  *   _, _, _, ctl = s2.recvmsg(:scm_rights=>true)
    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, :RIGHTS, [0,s1.fileno].pack("ii")]
    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(0x100000000UL);
    00337         d = mul(d,d);
    00338         timev = add(TIMET2NUM(bt.sec), quo(ULL2NUM(bt.frac), d));
    00339         result = rb_time_num_new(timev, Qnil);
    00340     }
    00341 # endif
    00342
    00343     if (result == Qnil)
    00344         rb_raise(rb_eTypeError, "timestamp ancillary data expected");
    00345
    00346     return result;
    00347 }
    00348 #else
    00349 #define ancillary_timestamp rb_f_notimplement
    00350 #endif
    00351
    00352 /*
    00353  * 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 VALUE
    01113 nogvl_sendmsg_func(void *ptr)
    01114 {
    01115     struct sendmsg_args_struct *args = ptr;
    01116     return sendmsg(args->fd, args->msg, args->flags);
    01117 }
    01118
    01119 static ssize_t
    01120 rb_sendmsg(int fd, const struct msghdr *msg, int flags)
    01121 {
    01122     struct sendmsg_args_struct args;
    01123     args.fd = fd;
    01124     args.msg = msg;
    01125     args.flags = flags;
    01126     return rb_thread_blocking_region(nogvl_sendmsg_func, &args, RUBY_UBF_IO, 0);
    01127 }
    01128
    01129 static VALUE
    01130 bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
    01131 {
    01132     rb_io_t *fptr;
    01133     VALUE data, vflags, dest_sockaddr;
    01134     VALUE *controls_ptr;
    01135     int controls_num;
    01136     struct msghdr mh;
    01137     struct iovec iov;
    01138 #if defined(HAVE_ST_MSG_CONTROL)
    01139     volatile VALUE controls_str = 0;
    01140 #endif
    01141     int flags;
    01142     ssize_t ss;
    01143     int family;
    01144
    01145     rb_secure(4);
    01146     GetOpenFile(sock, fptr);
    01147     family = rsock_getfamily(fptr->fd);
    01148
    01149     data = vflags = dest_sockaddr = Qnil;
    01150     controls_ptr = NULL;
    01151     controls_num = 0;
    01152
    01153     if (argc == 0)
    01154         rb_raise(rb_eArgError, "mesg argument required");
    01155     data = argv[0];
    01156     if (1 < argc) vflags = argv[1];
    01157     if (2 < argc) dest_sockaddr = argv[2];
    01158     if (3 < argc) { controls_ptr = &argv[3]; controls_num = argc - 3; }
    01159
    01160     StringValue(data);
    01161
    01162     if (controls_num) {
    01163 #if defined(HAVE_ST_MSG_CONTROL)
    01164         int i;
    01165         size_t last_pad = 0;
    01166         int last_level = 0;
    01167         int last_type = 0;
    01168         controls_str = rb_str_tmp_new(0);
    01169         for (i = 0; i < controls_num; i++) {
    01170             VALUE elt = controls_ptr[i], v;
    01171             VALUE vlevel, vtype;
    01172             int level, type;
    01173             VALUE cdata;
    01174             long oldlen;
    01175             struct cmsghdr cmh;
    01176             char *cmsg;
    01177             size_t cspace;
    01178             v = rb_check_convert_type(elt, T_ARRAY, "Array", "to_ary");
    01179             if (!NIL_P(v)) {
    01180                 elt = v;
    01181                 if (RARRAY_LEN(elt) != 3)
    01182                     rb_raise(rb_eArgError, "an element of controls should be 3-elements array");
    01183                 vlevel = rb_ary_entry(elt, 0);
    01184                 vtype = rb_ary_entry(elt, 1);
    01185                 cdata = rb_ary_entry(elt, 2);
    01186             }
    01187             else {
    01188                 vlevel = rb_funcall(elt, rb_intern("level"), 0);
    01189                 vtype = rb_funcall(elt, rb_intern("type"), 0);
    01190                 cdata = rb_funcall(elt, rb_intern("data"), 0);
    01191             }
    01192             level = rsock_level_arg(family, vlevel);
    01193             type = rsock_cmsg_type_arg(family, level, vtype);
    01194             StringValue(cdata);
    01195             oldlen = RSTRING_LEN(controls_str);
    01196             cspace = CMSG_SPACE(RSTRING_LEN(cdata));
    01197             rb_str_resize(controls_str, oldlen + cspace);
    01198             cmsg = RSTRING_PTR(controls_str)+oldlen;
    01199             memset((char *)cmsg, 0, cspace);
    01200             memset((char *)&cmh, 0, sizeof(cmh));
    01201             cmh.cmsg_level = level;
    01202             cmh.cmsg_type = type;
    01203             cmh.cmsg_len = (socklen_t)CMSG_LEN(RSTRING_LEN(cdata));
    01204             MEMCPY(cmsg, &cmh, char, sizeof(cmh));
    01205             MEMCPY(cmsg+((char*)CMSG_DATA(&cmh)-(char*)&cmh), RSTRING_PTR(cdata), char, RSTRING_LEN(cdata));
    01206             last_level = cmh.cmsg_level;
    01207             last_type = cmh.cmsg_type;
    01208             last_pad = cspace - cmh.cmsg_len;
    01209         }
    01210         if (last_pad) {
    01211             /*
    01212              * This code removes the last padding from msg_controllen.
    01213              *
    01214              * 4.3BSD-Reno reject the padding for SCM_RIGHTS. (There was no 64bit environments in those days?)
    01215              * RFC 2292 require the padding.
    01216              * RFC 3542 relaxes the condition - implementation must accept both as valid.
    01217              *
    01218              * Actual problems:
    01219              *
    01220              * - NetBSD 4.0.1
    01221              *   SCM_RIGHTS with padding causes EINVAL
    01222              *   IPV6_PKTINFO without padding causes "page fault trap"
    01223              *     http://www.netbsd.org/cgi-bin/query-pr-single.pl?number=40661
    01224              *
    01225              * - OpenBSD 4.4
    01226              *   IPV6_PKTINFO without padding causes EINVAL
    01227              *
    01228              * Basically, msg_controllen should contains the padding.
    01229              * So the padding is removed only if a problem really exists.
    01230              */
    01231 #if defined(__NetBSD__)
    01232             if (last_level == SOL_SOCKET && last_type == SCM_RIGHTS)
    01233                 rb_str_set_len(controls_str, RSTRING_LEN(controls_str)-last_pad);
    01234 #endif
    01235         }
    01236 #else
    01237         rb_raise(rb_eNotImpError, "control message for sendmsg is unimplemented");
    01238 #endif
    01239     }
    01240
    01241     flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
    01242 #ifdef MSG_DONTWAIT
    01243     if (nonblock)
    01244         flags |= MSG_DONTWAIT;
    01245 #endif
    01246
    01247     if (!NIL_P(dest_sockaddr))
    01248         SockAddrStringValue(dest_sockaddr);
    01249
    01250     rb_io_check_closed(fptr);
    01251
    01252   retry:
    01253     memset(&mh, 0, sizeof(mh));
    01254     if (!NIL_P(dest_sockaddr)) {
    01255         mh.msg_name = RSTRING_PTR(dest_sockaddr);
    01256         mh.msg_namelen = RSTRING_LENINT(dest_sockaddr);
    01257     }
    01258     mh.msg_iovlen = 1;
    01259     mh.msg_iov = &iov;
    01260     iov.iov_base = RSTRING_PTR(data);
    01261     iov.iov_len = RSTRING_LEN(data);
    01262 #if defined(HAVE_ST_MSG_CONTROL)
    01263     if (controls_str) {
    01264         mh.msg_control = RSTRING_PTR(controls_str);
    01265         mh.msg_controllen = RSTRING_LENINT(controls_str);
    01266     }
    01267     else {
    01268         mh.msg_control = NULL;
    01269         mh.msg_controllen = 0;
    01270     }
    01271 #endif
    01272
    01273     rb_io_check_closed(fptr);
    01274     if (nonblock)
    01275         rb_io_set_nonblock(fptr);
    01276
    01277     ss = rb_sendmsg(fptr->fd, &mh, flags);
    01278
    01279     if (!nonblock && rb_io_wait_writable(fptr->fd)) {
    01280         rb_io_check_closed(fptr);
    01281         goto retry;
    01282     }
    01283
    01284     if (ss == -1) {
    01285         if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
    01286             rb_mod_sys_fail(rb_mWaitWritable, "sendmsg(2) would block");
    01287         rb_sys_fail("sendmsg(2)");
    01288     }
    01289
    01290     return SSIZET2NUM(ss);
    01291 }
    01292 #endif
    01293
    01294 #if defined(HAVE_SENDMSG)
    01295 /*
    01296  * call-seq:
    01297  *    basicsocket.sendmsg(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent
    01298  *
    01299  * sendmsg sends a message using sendmsg(2) system call in blocking manner.
    01300  *
    01301  * _mesg_ is a string to send.
    01302  *
    01303  * _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_OOB.
    01304  *
    01305  * _dest_sockaddr_ is a destination socket address for connection-less socket.
    01306  * It should be a sockaddr such as a result of Socket.sockaddr_in.
    01307  * An Addrinfo object can be used too.
    01308  *
    01309  * _controls_ is a list of ancillary data.
    01310  * The element of _controls_ should be Socket::AncillaryData or
    01311  * 3-elements array.
    01312  * The 3-element array should contains cmsg_level, cmsg_type and data.
    01313  *
    01314  * The return value, _numbytes_sent_ is an integer which is the number of bytes sent.
    01315  *
    01316  * sendmsg can be used to implement send_io as follows:
    01317  *
    01318  *   # use Socket::AncillaryData.
    01319  *   ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, io.fileno)
    01320  *   sock.sendmsg("a", 0, nil, ancdata)
    01321  *
    01322  *   # use 3-element array.
    01323  *   ancdata = [:SOCKET, :RIGHTS, [io.fileno].pack("i!")]
    01324  *   sock.sendmsg("\0", 0, nil, ancdata)
    01325  *
    01326  */
    01327 VALUE
    01328 rsock_bsock_sendmsg(int argc, VALUE *argv, VALUE sock)
    01329 {
    01330     return bsock_sendmsg_internal(argc, argv, sock, 0);
    01331 }
    01332 #endif
    01333
    01334 #if defined(HAVE_SENDMSG)
    01335 /*
    01336  * call-seq:
    01337  *    basicsocket.sendmsg_nonblock(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent
    01338  *
    01339  * sendmsg_nonblock sends a message using sendmsg(2) system call in non-blocking manner.
    01340  *
    01341  * It is similar to BasicSocket#sendmsg
    01342  * but the non-blocking flag is set before the system call
    01343  * and it doesn't retry the system call.
    01344  *
    01345  */
    01346 VALUE
    01347 rsock_bsock_sendmsg_nonblock(int argc, VALUE *argv, VALUE sock)
    01348 {
    01349     return bsock_sendmsg_internal(argc, argv, sock, 1);
    01350 }
    01351 #endif
    01352
    01353 #if defined(HAVE_RECVMSG)
    01354 struct recvmsg_args_struct {
    01355     int fd;
    01356     struct msghdr *msg;
    01357     int flags;
    01358 };
    01359
    01360 static VALUE
    01361 nogvl_recvmsg_func(void *ptr)
    01362 {
    01363     struct recvmsg_args_struct *args = ptr;
    01364     return recvmsg(args->fd, args->msg, args->flags);
    01365 }
    01366
    01367 static ssize_t
    01368 rb_recvmsg(int fd, struct msghdr *msg, int flags)
    01369 {
    01370     struct recvmsg_args_struct args;
    01371     args.fd = fd;
    01372     args.msg = msg;
    01373     args.flags = flags;
    01374     return rb_thread_blocking_region(nogvl_recvmsg_func, &args, RUBY_UBF_IO, 0);
    01375 }
    01376
    01377 #if defined(HAVE_ST_MSG_CONTROL)
    01378 static void
    01379 discard_cmsg(struct cmsghdr *cmh, char *msg_end)
    01380 {
    01381     if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
    01382         int *fdp = (int *)CMSG_DATA(cmh);
    01383         int *end = (int *)((char *)cmh + cmh->cmsg_len);
    01384         while ((char *)fdp + sizeof(int) <= (char *)end &&
    01385                (char *)fdp + sizeof(int) <= msg_end) {
    01386             close(*fdp);
    01387             fdp++;
    01388         }
    01389     }
    01390 }
    01391 #endif
    01392
    01393 void
    01394 rsock_discard_cmsg_resource(struct msghdr *mh)
    01395 {
    01396 #if defined(HAVE_ST_MSG_CONTROL)
    01397     struct cmsghdr *cmh;
    01398     char *msg_end;
    01399
    01400     if (mh->msg_controllen == 0)
    01401         return;
    01402
    01403     msg_end = (char *)mh->msg_control + mh->msg_controllen;
    01404
    01405     for (cmh = CMSG_FIRSTHDR(mh); cmh != NULL; cmh = CMSG_NXTHDR(mh, cmh)) {
    01406         discard_cmsg(cmh, msg_end);
    01407     }
    01408 #endif
    01409 }
    01410
    01411 #if defined(HAVE_ST_MSG_CONTROL)
    01412 static void
    01413 make_io_for_unix_rights(VALUE ctl, struct cmsghdr *cmh, char *msg_end)
    01414 {
    01415     if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
    01416         int *fdp, *end;
    01417         VALUE ary = rb_ary_new();
    01418         rb_ivar_set(ctl, rb_intern("unix_rights"), ary);
    01419         fdp = (int *)CMSG_DATA(cmh);
    01420         end = (int *)((char *)cmh + cmh->cmsg_len);
    01421         while ((char *)fdp + sizeof(int) <= (char *)end &&
    01422                (char *)fdp + sizeof(int) <= msg_end) {
    01423             int fd = *fdp;
    01424             struct stat stbuf;
    01425             VALUE io;
    01426             if (fstat(fd, &stbuf) == -1)
    01427                 rb_raise(rb_eSocket, "invalid fd in SCM_RIGHTS");
    01428             if (S_ISSOCK(stbuf.st_mode))
    01429                 io = rsock_init_sock(rb_obj_alloc(rb_cSocket), fd);
    01430             else
    01431                 io = rb_io_fdopen(fd, O_RDWR, NULL);
    01432             ary = rb_attr_get(ctl, rb_intern("unix_rights"));
    01433             rb_ary_push(ary, io);
    01434             fdp++;
    01435         }
    01436         OBJ_FREEZE(ary);
    01437     }
    01438 }
    01439 #endif
    01440
    01441 static VALUE
    01442 bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
    01443 {
    01444     rb_io_t *fptr;
    01445     VALUE vmaxdatlen, vmaxctllen, vflags, vopts;
    01446     int grow_buffer;
    01447     size_t maxdatlen;
    01448     int flags, orig_flags;
    01449     int request_scm_rights;
    01450     struct msghdr mh;
    01451     struct iovec iov;
    01452     struct sockaddr_storage namebuf;
    01453     char datbuf0[4096], *datbuf;
    01454     VALUE dat_str = Qnil;
    01455     VALUE ret;
    01456     ssize_t ss;
    01457 #if defined(HAVE_ST_MSG_CONTROL)
    01458     struct cmsghdr *cmh;
    01459     size_t maxctllen;
    01460     union {
    01461         char bytes[4096];
    01462         struct cmsghdr align;
    01463     } ctlbuf0;
    01464     char *ctlbuf;
    01465     VALUE ctl_str = Qnil;
    01466     int family;
    01467     int gc_done = 0;
    01468 #endif
    01469
    01470     rb_secure(4);
    01471
    01472     vopts = Qnil;
    01473     if (0 < argc && TYPE(argv[argc-1]) == T_HASH)
    01474         vopts = argv[--argc];
    01475
    01476     rb_scan_args(argc, argv, "03", &vmaxdatlen, &vflags, &vmaxctllen);
    01477
    01478     maxdatlen = NIL_P(vmaxdatlen) ? sizeof(datbuf0) : NUM2SIZET(vmaxdatlen);
    01479 #if defined(HAVE_ST_MSG_CONTROL)
    01480     maxctllen = NIL_P(vmaxctllen) ? sizeof(ctlbuf0) : NUM2SIZET(vmaxctllen);
    01481 #else
    01482     if (!NIL_P(vmaxctllen))
    01483         rb_raise(rb_eArgError, "control message not supported");
    01484 #endif
    01485     flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
    01486 #ifdef MSG_DONTWAIT
    01487     if (nonblock)
    01488         flags |= MSG_DONTWAIT;
    01489 #endif
    01490     orig_flags = flags;
    01491
    01492     grow_buffer = NIL_P(vmaxdatlen) || NIL_P(vmaxctllen);
    01493
    01494     request_scm_rights = 0;
    01495     if (!NIL_P(vopts) && RTEST(rb_hash_aref(vopts, ID2SYM(rb_intern("scm_rights")))))
    01496         request_scm_rights = 1;
    01497
    01498     GetOpenFile(sock, fptr);
    01499     if (rb_io_read_pending(fptr)) {
    01500         rb_raise(rb_eIOError, "recvmsg for buffered IO");
    01501     }
    01502
    01503 #if !defined(HAVE_ST_MSG_CONTROL)
    01504     if (grow_buffer) {
    01505         int socktype;
    01506         socklen_t optlen = (socklen_t)sizeof(socktype);
    01507         if (getsockopt(fptr->fd, SOL_SOCKET, SO_TYPE, (void*)&socktype, &optlen) == -1) {
    01508             rb_sys_fail("getsockopt(SO_TYPE)");
    01509         }
    01510         if (socktype == SOCK_STREAM)
    01511             grow_buffer = 0;
    01512     }
    01513 #endif
    01514
    01515   retry:
    01516     if (maxdatlen <= sizeof(datbuf0))
    01517         datbuf = datbuf0;
    01518     else {
    01519         if (NIL_P(dat_str))
    01520             dat_str = rb_str_tmp_new(maxdatlen);
    01521         else
    01522             rb_str_resize(dat_str, maxdatlen);
    01523         datbuf = RSTRING_PTR(dat_str);
    01524     }
    01525
    01526 #if defined(HAVE_ST_MSG_CONTROL)
    01527     if (maxctllen <= sizeof(ctlbuf0))
    01528         ctlbuf = ctlbuf0.bytes;
    01529     else {
    01530         if (NIL_P(ctl_str))
    01531             ctl_str = rb_str_tmp_new(maxctllen);
    01532         else
    01533             rb_str_resize(ctl_str, maxctllen);
    01534         ctlbuf = RSTRING_PTR(ctl_str);
    01535     }
    01536 #endif
    01537
    01538     memset(&mh, 0, sizeof(mh));
    01539
    01540     memset(&namebuf, 0, sizeof(namebuf));
    01541     mh.msg_name = (struct sockaddr *)&namebuf;
    01542     mh.msg_namelen = (socklen_t)sizeof(namebuf);
    01543
    01544     mh.msg_iov = &iov;
    01545     mh.msg_iovlen = 1;
    01546     iov.iov_base = datbuf;
    01547     iov.iov_len = maxdatlen;
    01548
    01549 #if defined(HAVE_ST_MSG_CONTROL)
    01550     mh.msg_control = ctlbuf;
    01551     mh.msg_controllen = (socklen_t)maxctllen;
    01552 #endif
    01553
    01554     if (grow_buffer)
    01555         flags |= MSG_PEEK;
    01556
    01557     rb_io_check_closed(fptr);
    01558     if (nonblock)
    01559         rb_io_set_nonblock(fptr);
    01560
    01561     ss = rb_recvmsg(fptr->fd, &mh, flags);
    01562
    01563     if (!nonblock && rb_io_wait_readable(fptr->fd)) {
    01564         rb_io_check_closed(fptr);
    01565         goto retry;
    01566     }
    01567
    01568     if (ss == -1) {
    01569         if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
    01570             rb_mod_sys_fail(rb_mWaitReadable, "recvmsg(2) would block");
    01571 #if defined(HAVE_ST_MSG_CONTROL)
    01572         if (!gc_done && (errno == EMFILE || errno == EMSGSIZE)) {
    01573           /*
    01574            * When SCM_RIGHTS hit the file descriptors limit:
    01575            * - Linux 2.6.18 causes success with MSG_CTRUNC
    01576            * - MacOS X 10.4 causes EMSGSIZE (and lost file descriptors?)
    01577            * - Solaris 11 causes EMFILE
    01578            */
    01579           gc_and_retry:
    01580             rb_gc();
    01581             gc_done = 1;
    01582             goto retry;
    01583         }
    01584 #endif
    01585         rb_sys_fail("recvmsg(2)");
    01586     }
    01587
    01588     if (grow_buffer) {
    01589         int grown = 0;
    01590 #if defined(HAVE_ST_MSG_CONTROL)
    01591         if (NIL_P(vmaxdatlen) && (mh.msg_flags & MSG_TRUNC)) {
    01592             if (SIZE_MAX/2 < maxdatlen)
    01593                 rb_raise(rb_eArgError, "max data length too big");
    01594             maxdatlen *= 2;
    01595             grown = 1;
    01596         }
    01597         if (NIL_P(vmaxctllen) && (mh.msg_flags & MSG_CTRUNC)) {
    01598 #define BIG_ENOUGH_SPACE 65536
    01599             if (BIG_ENOUGH_SPACE < maxctllen &&
    01600                 mh.msg_controllen < maxctllen - BIG_ENOUGH_SPACE) {
    01601                 /* there are big space bug truncated.
    01602                  * file descriptors limit? */
    01603                 if (!gc_done) {
    01604                     rsock_discard_cmsg_resource(&mh);
    01605                     goto gc_and_retry;
    01606                 }
    01607             }
    01608             else {
    01609                 if (SIZE_MAX/2 < maxctllen)
    01610                     rb_raise(rb_eArgError, "max control message length too big");
    01611                 maxctllen *= 2;
    01612                 grown = 1;
    01613             }
    01614 #undef BIG_ENOUGH_SPACE
    01615         }
    01616 #else
    01617         if (NIL_P(vmaxdatlen) && ss != -1 && ss == (ssize_t)iov.iov_len) {
    01618             if (SIZE_MAX/2 < maxdatlen)
    01619                 rb_raise(rb_eArgError, "max data length too big");
    01620             maxdatlen *= 2;
    01621             grown = 1;
    01622         }
    01623 #endif
    01624         if (grown) {
    01625             rsock_discard_cmsg_resource(&mh);
    01626             goto retry;
    01627         }
    01628         else {
    01629             grow_buffer = 0;
    01630             if (flags != orig_flags) {
    01631                 flags = orig_flags;
    01632                 rsock_discard_cmsg_resource(&mh);
    01633                 goto retry;
    01634             }
    01635         }
    01636     }
    01637
    01638     if (NIL_P(dat_str))
    01639         dat_str = rb_tainted_str_new(datbuf, ss);
    01640     else {
    01641         rb_str_resize(dat_str, ss);
    01642         OBJ_TAINT(dat_str);
    01643         RBASIC(dat_str)->klass = rb_cString;
    01644     }
    01645
    01646     ret = rb_ary_new3(3, dat_str,
    01647                          rsock_io_socket_addrinfo(sock, mh.msg_name, mh.msg_namelen),
    01648 #if defined(HAVE_ST_MSG_CONTROL)
    01649                          INT2NUM(mh.msg_flags)
    01650 #else
    01651                          Qnil
    01652 #endif
    01653                          );
    01654
    01655 #if defined(HAVE_ST_MSG_CONTROL)
    01656     family = rsock_getfamily(fptr->fd);
    01657     if (mh.msg_controllen) {
    01658         char *msg_end = (char *)mh.msg_control + mh.msg_controllen;
    01659         for (cmh = CMSG_FIRSTHDR(&mh); cmh != NULL; cmh = CMSG_NXTHDR(&mh, cmh)) {
    01660             VALUE ctl;
    01661             char *ctl_end;
    01662             size_t clen;
    01663             if (cmh->cmsg_len == 0) {
    01664                 rb_raise(rb_eTypeError, "invalid control message (cmsg_len == 0)");
    01665             }
    01666             ctl_end = (char*)cmh + cmh->cmsg_len;
    01667             clen = (ctl_end <= msg_end ? ctl_end : msg_end) - (char*)CMSG_DATA(cmh);
    01668             ctl = ancdata_new(family, cmh->cmsg_level, cmh->cmsg_type, rb_tainted_str_new((char*)CMSG_DATA(cmh), clen));
    01669             if (request_scm_rights)
    01670                 make_io_for_unix_rights(ctl, cmh, msg_end);
    01671             else
    01672                 discard_cmsg(cmh, msg_end);
    01673             rb_ary_push(ret, ctl);
    01674         }
    01675     }
    01676 #endif
    01677
    01678     return ret;
    01679 }
    01680 #endif
    01681
    01682 #if defined(HAVE_RECVMSG)
    01683 /*
    01684  * call-seq:
    01685  *    basicsocket.recvmsg(maxmesglen=nil, flags=0, maxcontrollen=nil, opts={}) => [mesg, sender_addrinfo, rflags, *controls]
    01686  *
    01687  * recvmsg receives a message using recvmsg(2) system call in blocking manner.
    01688  *
    01689  * _maxmesglen_ is the maximum length of mesg to receive.
    01690  *
    01691  * _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_PEEK.
    01692  *
    01693  * _maxcontrollen_ is the maximum length of controls (ancillary data) to receive.
    01694  *
    01695  * _opts_ is option hash.
    01696  * Currently :scm_rights=>bool is the only option.
    01697  *
    01698  * :scm_rights option specifies that application expects SCM_RIGHTS control message.
    01699  * If the value is nil or false, application don't expects SCM_RIGHTS control message.
    01700  * In this case, recvmsg closes the passed file descriptors immediately.
    01701  * This is the default behavior.
    01702  *
    01703  * If :scm_rights value is neither nil nor false, application expects SCM_RIGHTS control message.
    01704  * In this case, recvmsg creates IO objects for each file descriptors for
    01705  * Socket::AncillaryData#unix_rights method.
    01706  *
    01707  * The return value is 4-elements array.
    01708  *
    01709  * _mesg_ is a string of the received message.
    01710  *
    01711  * _sender_addrinfo_ is a sender socket address for connection-less socket.
    01712  * It is an Addrinfo object.
    01713  * For connection-oriented socket such as TCP, sender_addrinfo is platform dependent.
    01714  *
    01715  * _rflags_ is a flags on the received message which is bitwise OR of MSG_* constants such as Socket::MSG_TRUNC.
    01716  * It will be nil if the system uses 4.3BSD style old recvmsg system call.
    01717  *
    01718  * _controls_ is ancillary data which is an array of Socket::AncillaryData objects such as:
    01719  *
    01720  *   #<Socket::AncillaryData: AF_UNIX SOCKET RIGHTS 7>
    01721  *
    01722  * _maxmesglen_ and _maxcontrollen_ can be nil.
    01723  * In that case, the buffer will be grown until the message is not truncated.
    01724  * Internally, MSG_PEEK is used and MSG_TRUNC/MSG_CTRUNC are checked.
    01725  *
    01726  * recvmsg can be used to implement recv_io as follows:
    01727  *
    01728  *   mesg, sender_sockaddr, rflags, *controls = sock.recvmsg(:scm_rights=>true)
    01729  *   controls.each {|ancdata|
    01730  *     if ancdata.cmsg_is?(:SOCKET, :RIGHTS)
    01731  *       return ancdata.unix_rights[0]
    01732  *     end
    01733  *   }
    01734  *
    01735  */
    01736 VALUE
    01737 rsock_bsock_recvmsg(int argc, VALUE *argv, VALUE sock)
    01738 {
    01739     return bsock_recvmsg_internal(argc, argv, sock, 0);
    01740 }
    01741 #endif
    01742
    01743 #if defined(HAVE_RECVMSG)
    01744 /*
    01745  * call-seq:
    01746  *    basicsocket.recvmsg_nonblock(maxdatalen=nil, flags=0, maxcontrollen=nil, opts={}) => [data, sender_addrinfo, rflags, *controls]
    01747  *
    01748  * recvmsg receives a message using recvmsg(2) system call in non-blocking manner.
    01749  *
    01750  * It is similar to BasicSocket#recvmsg
    01751  * but non-blocking flag is set before the system call
    01752  * and it doesn't retry the system call.
    01753  *
    01754  */
    01755 VALUE
    01756 rsock_bsock_recvmsg_nonblock(int argc, VALUE *argv, VALUE sock)
    01757 {
    01758     return bsock_recvmsg_internal(argc, argv, sock, 1);
    01759 }
    01760 #endif
    01761
    01762 /*
    01763  * Document-class: ::Socket::AncillaryData
    01764  *
    01765  * Socket::AncillaryData represents the ancillary data (control information)
    01766  * used by sendmsg and recvmsg system call.
    01767  * It contains socket family, cmsg level, cmsg type and cmsg data.
    01768  */
    01769 void
    01770 rsock_init_ancdata(void)
    01771 {
    01772 #if defined(HAVE_ST_MSG_CONTROL)
    01773     rb_cAncillaryData = rb_define_class_under(rb_cSocket, "AncillaryData", rb_cObject);
    01774     rb_define_method(rb_cAncillaryData, "initialize", ancillary_initialize, 4);
    01775     rb_define_method(rb_cAncillaryData, "inspect", ancillary_inspect, 0);
    01776     rb_define_method(rb_cAncillaryData, "family", ancillary_family_m, 0);
    01777     rb_define_method(rb_cAncillaryData, "level", ancillary_level_m, 0);
    01778     rb_define_method(rb_cAncillaryData, "type", ancillary_type_m, 0);
    01779     rb_define_method(rb_cAncillaryData, "data", ancillary_data, 0);
    01780
    01781     rb_define_method(rb_cAncillaryData, "cmsg_is?", ancillary_cmsg_is_p, 2);
    01782
    01783     rb_define_singleton_method(rb_cAncillaryData, "int", ancillary_s_int, 4);
    01784     rb_define_method(rb_cAncillaryData, "int", ancillary_int, 0);
    01785
    01786     rb_define_singleton_method(rb_cAncillaryData, "unix_rights", ancillary_s_unix_rights, -1);
    01787     rb_define_method(rb_cAncillaryData, "unix_rights", ancillary_unix_rights, 0);
    01788
    01789     rb_define_method(rb_cAncillaryData, "timestamp", ancillary_timestamp, 0);
    01790
    01791     rb_define_singleton_method(rb_cAncillaryData, "ip_pktinfo", ancillary_s_ip_pktinfo, -1);
    01792     rb_define_method(rb_cAncillaryData, "ip_pktinfo", ancillary_ip_pktinfo, 0);
    01793
    01794     rb_define_singleton_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_s_ipv6_pktinfo, 2);
    01795     rb_define_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_ipv6_pktinfo, 0);
    01796     rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_addr", ancillary_ipv6_pktinfo_addr, 0);
    01797     rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_ifindex", ancillary_ipv6_pktinfo_ifindex, 0);
    01798 #endif
    01799 }
    01800