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