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