|
Ruby 1.9.2p136(2010-12-25revision30365)
|
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
1.7.3