PageRenderTime 68ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/benchmarks/rdoc/ruby_trunk/ext/socket/ancdata.c

http://github.com/acangiano/ruby-benchmark-suite
C | 1809 lines | 1226 code | 165 blank | 418 comment | 288 complexity | 41207159542becb81c7d94dabcf3ec49 MD5 | raw file
Possible License(s): MIT, BSD-3-Clause, CC-BY-SA-3.0, LGPL-2.0, ISC, LGPL-2.1, GPL-2.0
  1. #include "rubysocket.h"
  2. #include <time.h>
  3. #if defined(HAVE_ST_MSG_CONTROL)
  4. static VALUE rb_cAncillaryData;
  5. static VALUE
  6. constant_to_sym(int constant, ID (*intern_const)(int))
  7. {
  8. ID name = intern_const(constant);
  9. if (name) {
  10. return ID2SYM(name);
  11. }
  12. return INT2NUM(constant);
  13. }
  14. static VALUE
  15. ip_cmsg_type_to_sym(int level, int cmsg_type)
  16. {
  17. switch (level) {
  18. case SOL_SOCKET:
  19. return constant_to_sym(cmsg_type, rsock_intern_scm_optname);
  20. case IPPROTO_IP:
  21. return constant_to_sym(cmsg_type, rsock_intern_ip_optname);
  22. #ifdef IPPROTO_IPV6
  23. case IPPROTO_IPV6:
  24. return constant_to_sym(cmsg_type, rsock_intern_ipv6_optname);
  25. #endif
  26. case IPPROTO_TCP:
  27. return constant_to_sym(cmsg_type, rsock_intern_tcp_optname);
  28. case IPPROTO_UDP:
  29. return constant_to_sym(cmsg_type, rsock_intern_udp_optname);
  30. default:
  31. return INT2NUM(cmsg_type);
  32. }
  33. }
  34. /*
  35. * call-seq:
  36. * Socket::AncillaryData.new(family, cmsg_level, cmsg_type, cmsg_data) -> ancillarydata
  37. *
  38. * _family_ should be an integer, a string or a symbol.
  39. * - Socket::AF_INET, "AF_INET", "INET", :AF_INET, :INET
  40. * - Socket::AF_UNIX, "AF_UNIX", "UNIX", :AF_UNIX, :UNIX
  41. * - etc.
  42. *
  43. * _cmsg_level_ should be an integer, a string or a symbol.
  44. * - Socket::SOL_SOCKET, "SOL_SOCKET", "SOCKET", :SOL_SOCKET and :SOCKET
  45. * - Socket::IPPROTO_IP, "IP" and :IP
  46. * - Socket::IPPROTO_IPV6, "IPV6" and :IPV6
  47. * - Socket::IPPROTO_TCP, "TCP" and :TCP
  48. * - etc.
  49. *
  50. * _cmsg_type_ should be an integer, a string or a symbol.
  51. * If a string/symbol is specified, it is interpreted depend on _cmsg_level_.
  52. * - Socket::SCM_RIGHTS, "SCM_RIGHTS", "RIGHTS", :SCM_RIGHTS, :RIGHTS for SOL_SOCKET
  53. * - Socket::IP_RECVTTL, "RECVTTL" and :RECVTTL for IPPROTO_IP
  54. * - Socket::IPV6_PKTINFO, "PKTINFO" and :PKTINFO for IPPROTO_IPV6
  55. * - etc.
  56. *
  57. * _cmsg_data_ should be a string.
  58. *
  59. * p Socket::AncillaryData.new(:INET, :TCP, :NODELAY, "")
  60. * #=> #<Socket::AncillaryData: INET TCP NODELAY "">
  61. *
  62. * p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "")
  63. * #=> #<Socket::AncillaryData: INET6 IPV6 PKTINFO "">
  64. *
  65. */
  66. static VALUE
  67. ancillary_initialize(VALUE self, VALUE vfamily, VALUE vlevel, VALUE vtype, VALUE data)
  68. {
  69. int family = rsock_family_arg(vfamily);
  70. int level = rsock_level_arg(family, vlevel);
  71. int type = rsock_cmsg_type_arg(family, level, vtype);
  72. StringValue(data);
  73. rb_ivar_set(self, rb_intern("family"), INT2NUM(family));
  74. rb_ivar_set(self, rb_intern("level"), INT2NUM(level));
  75. rb_ivar_set(self, rb_intern("type"), INT2NUM(type));
  76. rb_ivar_set(self, rb_intern("data"), data);
  77. return self;
  78. }
  79. static VALUE
  80. ancdata_new(int family, int level, int type, VALUE data)
  81. {
  82. NEWOBJ(obj, struct RObject);
  83. OBJSETUP(obj, rb_cAncillaryData, T_OBJECT);
  84. StringValue(data);
  85. ancillary_initialize((VALUE)obj, INT2NUM(family), INT2NUM(level), INT2NUM(type), data);
  86. return (VALUE)obj;
  87. }
  88. static int
  89. ancillary_family(VALUE self)
  90. {
  91. VALUE v = rb_attr_get(self, rb_intern("family"));
  92. return NUM2INT(v);
  93. }
  94. /*
  95. * call-seq:
  96. * ancillarydata.family => integer
  97. *
  98. * returns the socket family as an integer.
  99. *
  100. * p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").family
  101. * #=> 10
  102. */
  103. static VALUE
  104. ancillary_family_m(VALUE self)
  105. {
  106. return INT2NUM(ancillary_family(self));
  107. }
  108. static int
  109. ancillary_level(VALUE self)
  110. {
  111. VALUE v = rb_attr_get(self, rb_intern("level"));
  112. return NUM2INT(v);
  113. }
  114. /*
  115. * call-seq:
  116. * ancillarydata.level => integer
  117. *
  118. * returns the cmsg level as an integer.
  119. *
  120. * p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").level
  121. * #=> 41
  122. */
  123. static VALUE
  124. ancillary_level_m(VALUE self)
  125. {
  126. return INT2NUM(ancillary_level(self));
  127. }
  128. static int
  129. ancillary_type(VALUE self)
  130. {
  131. VALUE v = rb_attr_get(self, rb_intern("type"));
  132. return NUM2INT(v);
  133. }
  134. /*
  135. * call-seq:
  136. * ancillarydata.type => integer
  137. *
  138. * returns the cmsg type as an integer.
  139. *
  140. * p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").type
  141. * #=> 2
  142. */
  143. static VALUE
  144. ancillary_type_m(VALUE self)
  145. {
  146. return INT2NUM(ancillary_type(self));
  147. }
  148. /*
  149. * call-seq:
  150. * ancillarydata.data => string
  151. *
  152. * returns the cmsg data as a string.
  153. *
  154. * p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").data
  155. * #=> ""
  156. */
  157. static VALUE
  158. ancillary_data(VALUE self)
  159. {
  160. VALUE v = rb_attr_get(self, rb_intern("data"));
  161. StringValue(v);
  162. return v;
  163. }
  164. #ifdef SCM_RIGHTS
  165. /*
  166. * call-seq:
  167. * Socket::AncillaryData.unix_rights(io1, io2, ...) => ancillarydata
  168. *
  169. * Creates a new Socket::AncillaryData object which contains file descriptors as data.
  170. *
  171. * p Socket::AncillaryData.unix_rights(STDERR)
  172. * #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 2>
  173. */
  174. static VALUE
  175. ancillary_s_unix_rights(int argc, VALUE *argv, VALUE klass)
  176. {
  177. VALUE result, str, ary;
  178. int i;
  179. ary = rb_ary_new();
  180. for (i = 0 ; i < argc; i++) {
  181. VALUE obj = argv[i];
  182. if (TYPE(obj) != T_FILE) {
  183. rb_raise(rb_eTypeError, "IO expected");
  184. }
  185. rb_ary_push(ary, obj);
  186. }
  187. str = rb_str_buf_new(sizeof(int) * argc);
  188. for (i = 0 ; i < argc; i++) {
  189. VALUE obj = RARRAY_PTR(ary)[i];
  190. rb_io_t *fptr;
  191. int fd;
  192. GetOpenFile(obj, fptr);
  193. fd = fptr->fd;
  194. rb_str_buf_cat(str, (char *)&fd, sizeof(int));
  195. }
  196. result = ancdata_new(AF_UNIX, SOL_SOCKET, SCM_RIGHTS, str);
  197. rb_ivar_set(result, rb_intern("unix_rights"), ary);
  198. return result;
  199. }
  200. #else
  201. #define ancillary_s_unix_rights rb_f_notimplement
  202. #endif
  203. #ifdef SCM_RIGHTS
  204. /*
  205. * call-seq:
  206. * ancillarydata.unix_rights => array-of-IOs or nil
  207. *
  208. * returns the array of IO objects for SCM_RIGHTS control message in UNIX domain socket.
  209. *
  210. * The class of the IO objects in the array is IO or Socket.
  211. *
  212. * The array is attached to _ancillarydata_ when it is instantiated.
  213. * For example, BasicSocket#recvmsg attach the array when
  214. * receives a SCM_RIGHTS control message and :scm_rights=>true option is given.
  215. *
  216. * # recvmsg needs :scm_rights=>true for unix_rights
  217. * s1, s2 = UNIXSocket.pair
  218. * p s1 #=> #<UNIXSocket:fd 3>
  219. * s1.sendmsg "stdin and a socket", 0, nil, [:SOCKET, :RIGHTS, [0,s1.fileno].pack("ii")]
  220. * _, _, _, ctl = s2.recvmsg(:scm_rights=>true)
  221. * p ctl.unix_rights #=> [#<IO:fd 6>, #<Socket:fd 7>]
  222. * p File.identical?(STDIN, ctl.unix_rights[0]) #=> true
  223. * p File.identical?(s1, ctl.unix_rights[1]) #=> true
  224. *
  225. * # If :scm_rights=>true is not given, unix_rights returns nil
  226. * s1, s2 = UNIXSocket.pair
  227. * s1.sendmsg "stdin and a socket", 0, nil, [:SOCKET, :RIGHTS, [0,s1.fileno].pack("ii")]
  228. * _, _, _, ctl = s2.recvmsg
  229. * p ctl #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 6 7>
  230. * p ctl.unix_rights #=> nil
  231. *
  232. */
  233. static VALUE
  234. ancillary_unix_rights(VALUE self)
  235. {
  236. int level, type;
  237. level = ancillary_level(self);
  238. type = ancillary_type(self);
  239. if (level != SOL_SOCKET || type != SCM_RIGHTS)
  240. rb_raise(rb_eTypeError, "SCM_RIGHTS ancillary data expected");
  241. VALUE v = rb_attr_get(self, rb_intern("unix_rights"));
  242. return v;
  243. }
  244. #else
  245. #define ancillary_unix_rights rb_f_notimplement
  246. #endif
  247. #if defined(SCM_TIMESTAMP) || defined(SCM_TIMESTAMPNS) || defined(SCM_BINTIME)
  248. /*
  249. * call-seq:
  250. * ancillarydata.timestamp => time
  251. *
  252. * returns the timestamp as a time object.
  253. *
  254. * _ancillarydata_ should be one of following type:
  255. * - SOL_SOCKET/SCM_TIMESTAMP (micro second) GNU/Linux, FreeBSD, NetBSD, OpenBSD, Solaris, MacOS X
  256. * - SOL_SOCKET/SCM_TIMESTAMPNS (nano second) GNU/Linux
  257. * - SOL_SOCKET/SCM_BINTIME (2**(-64) second) FreeBSD
  258. *
  259. * Addrinfo.udp("127.0.0.1", 0).bind {|s1|
  260. * Addrinfo.udp("127.0.0.1", 0).bind {|s2|
  261. * s1.setsockopt(:SOCKET, :TIMESTAMP, true)
  262. * s2.send "a", 0, s1.local_address
  263. * ctl = s1.recvmsg.last
  264. * p ctl #=> #<Socket::AncillaryData: INET SOCKET TIMESTAMP 2009-02-24 17:35:46.775581>
  265. * t = ctl.timestamp
  266. * p t #=> 2009-02-24 17:35:46 +0900
  267. * p t.usec #=> 775581
  268. * p t.nsec #=> 775581000
  269. * }
  270. * }
  271. *
  272. */
  273. static VALUE
  274. ancillary_timestamp(VALUE self)
  275. {
  276. int level, type;
  277. VALUE data;
  278. VALUE result = Qnil;
  279. level = ancillary_level(self);
  280. type = ancillary_type(self);
  281. data = ancillary_data(self);
  282. # ifdef SCM_TIMESTAMP
  283. if (level == SOL_SOCKET && type == SCM_TIMESTAMP &&
  284. RSTRING_LEN(data) == sizeof(struct timeval)) {
  285. struct timeval tv;
  286. memcpy((char*)&tv, RSTRING_PTR(data), sizeof(tv));
  287. result = rb_time_new(tv.tv_sec, tv.tv_usec);
  288. }
  289. # endif
  290. # ifdef SCM_TIMESTAMPNS
  291. if (level == SOL_SOCKET && type == SCM_TIMESTAMPNS &&
  292. RSTRING_LEN(data) == sizeof(struct timespec)) {
  293. struct timespec ts;
  294. memcpy((char*)&ts, RSTRING_PTR(data), sizeof(ts));
  295. result = rb_time_nano_new(ts.tv_sec, ts.tv_nsec);
  296. }
  297. # endif
  298. #define add(x,y) (rb_funcall((x), '+', 1, (y)))
  299. #define mul(x,y) (rb_funcall((x), '*', 1, (y)))
  300. #define quo(x,y) (rb_funcall((x), rb_intern("quo"), 1, (y)))
  301. # ifdef SCM_BINTIME
  302. if (level == SOL_SOCKET && type == SCM_BINTIME &&
  303. RSTRING_LEN(data) == sizeof(struct bintime)) {
  304. struct bintime bt;
  305. VALUE d, timev;
  306. memcpy((char*)&bt, RSTRING_PTR(data), sizeof(bt));
  307. d = ULL2NUM(0x100000000UL);
  308. d = mul(d,d);
  309. timev = add(TIMET2NUM(bt.sec), quo(ULL2NUM(bt.frac), d));
  310. result = rb_time_num_new(timev, Qnil);
  311. }
  312. # endif
  313. if (result == Qnil)
  314. rb_raise(rb_eTypeError, "timestamp ancillary data expected");
  315. return result;
  316. }
  317. #else
  318. #define ancillary_timestamp rb_f_notimplement
  319. #endif
  320. /*
  321. * call-seq:
  322. * Socket::AncillaryData.int(family, cmsg_level, cmsg_type, integer) => ancillarydata
  323. *
  324. * Creates a new Socket::AncillaryData object which contains a int as data.
  325. *
  326. * The size and endian is dependent on the host.
  327. *
  328. * p Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, STDERR.fileno)
  329. * #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 2>
  330. */
  331. static VALUE
  332. ancillary_s_int(VALUE klass, VALUE vfamily, VALUE vlevel, VALUE vtype, VALUE integer)
  333. {
  334. int family = rsock_family_arg(vfamily);
  335. int level = rsock_level_arg(family, vlevel);
  336. int type = rsock_cmsg_type_arg(family, level, vtype);
  337. int i = NUM2INT(integer);
  338. return ancdata_new(family, level, type, rb_str_new((char*)&i, sizeof(i)));
  339. }
  340. /*
  341. * call-seq:
  342. * ancillarydata.int => integer
  343. *
  344. * Returns the data in _ancillarydata_ as an int.
  345. *
  346. * The size and endian is dependent on the host.
  347. *
  348. * ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, STDERR.fileno)
  349. * p ancdata.int #=> 2
  350. */
  351. static VALUE
  352. ancillary_int(VALUE self)
  353. {
  354. VALUE data;
  355. int i;
  356. data = ancillary_data(self);
  357. if (RSTRING_LEN(data) != sizeof(int))
  358. rb_raise(rb_eTypeError, "size differ. expected as sizeof(int)=%d but %ld", (int)sizeof(int), (long)RSTRING_LEN(data));
  359. memcpy((char*)&i, RSTRING_PTR(data), sizeof(int));
  360. return INT2NUM(i);
  361. }
  362. #if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_TYPE_STRUCT_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) /* GNU/Linux */
  363. /*
  364. * call-seq:
  365. * Socket::AncillaryData.ip_pktinfo(addr, ifindex) => ancdata
  366. * Socket::AncillaryData.ip_pktinfo(addr, ifindex, spec_dst) => ancdata
  367. *
  368. * Returns new ancillary data for IP_PKTINFO.
  369. *
  370. * If spec_dst is not given, addr is used.
  371. *
  372. * IP_PKTINFO is not standard.
  373. *
  374. * Supported platform: GNU/Linux
  375. *
  376. * addr = Addrinfo.ip("127.0.0.1")
  377. * ifindex = 0
  378. * spec_dst = Addrinfo.ip("127.0.0.1")
  379. * p Socket::AncillaryData.ip_pktinfo(addr, ifindex, spec_dst)
  380. * #=> #<Socket::AncillaryData: INET IP PKTINFO 127.0.0.1 ifindex:0 spec_dst:127.0.0.1>
  381. *
  382. */
  383. static VALUE
  384. ancillary_s_ip_pktinfo(int argc, VALUE *argv, VALUE self)
  385. {
  386. VALUE v_addr, v_ifindex, v_spec_dst;
  387. unsigned int ifindex;
  388. struct sockaddr_in sa;
  389. struct in_pktinfo pktinfo;
  390. rb_scan_args(argc, argv, "21", &v_addr, &v_ifindex, &v_spec_dst);
  391. SockAddrStringValue(v_addr);
  392. ifindex = NUM2UINT(v_ifindex);
  393. if (NIL_P(v_spec_dst))
  394. v_spec_dst = v_addr;
  395. else
  396. SockAddrStringValue(v_spec_dst);
  397. memset(&pktinfo, 0, sizeof(pktinfo));
  398. memset(&sa, 0, sizeof(sa));
  399. if (RSTRING_LEN(v_addr) != sizeof(sa))
  400. rb_raise(rb_eArgError, "addr size different to AF_INET sockaddr");
  401. memcpy(&sa, RSTRING_PTR(v_addr), sizeof(sa));
  402. if (sa.sin_family != AF_INET)
  403. rb_raise(rb_eArgError, "addr is not AF_INET sockaddr");
  404. memcpy(&pktinfo.ipi_addr, &sa.sin_addr, sizeof(pktinfo.ipi_addr));
  405. pktinfo.ipi_ifindex = ifindex;
  406. memset(&sa, 0, sizeof(sa));
  407. if (RSTRING_LEN(v_spec_dst) != sizeof(sa))
  408. rb_raise(rb_eArgError, "spec_dat size different to AF_INET sockaddr");
  409. memcpy(&sa, RSTRING_PTR(v_spec_dst), sizeof(sa));
  410. if (sa.sin_family != AF_INET)
  411. rb_raise(rb_eArgError, "spec_dst is not AF_INET sockaddr");
  412. memcpy(&pktinfo.ipi_spec_dst, &sa.sin_addr, sizeof(pktinfo.ipi_spec_dst));
  413. return ancdata_new(AF_INET, IPPROTO_IP, IP_PKTINFO, rb_str_new((char *)&pktinfo, sizeof(pktinfo)));
  414. }
  415. #else
  416. #define ancillary_s_ip_pktinfo rb_f_notimplement
  417. #endif
  418. #if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_TYPE_STRUCT_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) /* GNU/Linux */
  419. /*
  420. * call-seq:
  421. * ancdata.ip_pktinfo => [addr, ifindex, spec_dst]
  422. *
  423. * Extracts addr, ifindex and spec_dst from IP_PKTINFO ancillary data.
  424. *
  425. * IP_PKTINFO is not standard.
  426. *
  427. * Supported platform: GNU/Linux
  428. *
  429. * addr = Addrinfo.ip("127.0.0.1")
  430. * ifindex = 0
  431. * spec_dest = Addrinfo.ip("127.0.0.1")
  432. * ancdata = Socket::AncillaryData.ip_pktinfo(addr, ifindex, spec_dest)
  433. * p ancdata.ip_pktinfo
  434. * #=> [#<Addrinfo: 127.0.0.1>, 0, #<Addrinfo: 127.0.0.1>]
  435. *
  436. *
  437. */
  438. static VALUE
  439. ancillary_ip_pktinfo(VALUE self)
  440. {
  441. int level, type;
  442. VALUE data;
  443. struct in_pktinfo pktinfo;
  444. struct sockaddr_in sa;
  445. VALUE v_spec_dst, v_addr;
  446. level = ancillary_level(self);
  447. type = ancillary_type(self);
  448. data = ancillary_data(self);
  449. if (level != IPPROTO_IP || type != IP_PKTINFO ||
  450. RSTRING_LEN(data) != sizeof(struct in_pktinfo)) {
  451. rb_raise(rb_eTypeError, "IP_PKTINFO ancillary data expected");
  452. }
  453. memcpy(&pktinfo, RSTRING_PTR(data), sizeof(struct in_pktinfo));
  454. memset(&sa, 0, sizeof(sa));
  455. sa.sin_family = AF_INET;
  456. memcpy(&sa.sin_addr, &pktinfo.ipi_addr, sizeof(sa.sin_addr));
  457. v_addr = rsock_addrinfo_new((struct sockaddr *)&sa, sizeof(sa), PF_INET, 0, 0, Qnil, Qnil);
  458. sa.sin_family = AF_INET;
  459. memcpy(&sa.sin_addr, &pktinfo.ipi_spec_dst, sizeof(sa.sin_addr));
  460. v_spec_dst = rsock_addrinfo_new((struct sockaddr *)&sa, sizeof(sa), PF_INET, 0, 0, Qnil, Qnil);
  461. return rb_ary_new3(3, v_addr, UINT2NUM(pktinfo.ipi_ifindex), v_spec_dst);
  462. }
  463. #else
  464. #define ancillary_ip_pktinfo rb_f_notimplement
  465. #endif
  466. #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */
  467. /*
  468. * call-seq:
  469. * Socket::AncillaryData.ipv6_pktinfo(addr, ifindex) => ancdata
  470. *
  471. * Returns new ancillary data for IPV6_PKTINFO.
  472. *
  473. * IPV6_PKTINFO is defined by RFC 3542.
  474. *
  475. * addr = Addrinfo.ip("::1")
  476. * ifindex = 0
  477. * p Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
  478. * #=> #<Socket::AncillaryData: INET6 IPV6 PKTINFO ::1 ifindex:0>
  479. *
  480. */
  481. static VALUE
  482. ancillary_s_ipv6_pktinfo(VALUE self, VALUE v_addr, VALUE v_ifindex)
  483. {
  484. unsigned int ifindex;
  485. struct sockaddr_in6 sa;
  486. struct in6_pktinfo pktinfo;
  487. SockAddrStringValue(v_addr);
  488. ifindex = NUM2UINT(v_ifindex);
  489. memset(&pktinfo, 0, sizeof(pktinfo));
  490. memset(&sa, 0, sizeof(sa));
  491. if (RSTRING_LEN(v_addr) != sizeof(sa))
  492. rb_raise(rb_eArgError, "addr size different to AF_INET6 sockaddr");
  493. memcpy(&sa, RSTRING_PTR(v_addr), sizeof(sa));
  494. if (sa.sin6_family != AF_INET6)
  495. rb_raise(rb_eArgError, "addr is not AF_INET6 sockaddr");
  496. memcpy(&pktinfo.ipi6_addr, &sa.sin6_addr, sizeof(pktinfo.ipi6_addr));
  497. pktinfo.ipi6_ifindex = ifindex;
  498. return ancdata_new(AF_INET6, IPPROTO_IPV6, IPV6_PKTINFO, rb_str_new((char *)&pktinfo, sizeof(pktinfo)));
  499. }
  500. #else
  501. #define ancillary_s_ipv6_pktinfo rb_f_notimplement
  502. #endif
  503. #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */
  504. static void
  505. extract_ipv6_pktinfo(VALUE self, struct in6_pktinfo *pktinfo_ptr, struct sockaddr_in6 *sa_ptr)
  506. {
  507. int level, type;
  508. VALUE data;
  509. level = ancillary_level(self);
  510. type = ancillary_type(self);
  511. data = ancillary_data(self);
  512. if (level != IPPROTO_IPV6 || type != IPV6_PKTINFO ||
  513. RSTRING_LEN(data) != sizeof(struct in6_pktinfo)) {
  514. rb_raise(rb_eTypeError, "IPV6_PKTINFO ancillary data expected");
  515. }
  516. memcpy(pktinfo_ptr, RSTRING_PTR(data), sizeof(*pktinfo_ptr));
  517. memset(sa_ptr, 0, sizeof(*sa_ptr));
  518. SET_SA_LEN((struct sockaddr *)sa_ptr, sizeof(struct sockaddr_in6));
  519. sa_ptr->sin6_family = AF_INET6;
  520. memcpy(&sa_ptr->sin6_addr, &pktinfo_ptr->ipi6_addr, sizeof(sa_ptr->sin6_addr));
  521. if (IN6_IS_ADDR_LINKLOCAL(&sa_ptr->sin6_addr))
  522. sa_ptr->sin6_scope_id = pktinfo_ptr->ipi6_ifindex;
  523. }
  524. #endif
  525. #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */
  526. /*
  527. * call-seq:
  528. * ancdata.ipv6_pktinfo => [addr, ifindex]
  529. *
  530. * Extracts addr and ifindex from IPV6_PKTINFO ancillary data.
  531. *
  532. * IPV6_PKTINFO is defined by RFC 3542.
  533. *
  534. * addr = Addrinfo.ip("::1")
  535. * ifindex = 0
  536. * ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
  537. * p ancdata.ipv6_pktinfo #=> [#<Addrinfo: ::1>, 0]
  538. *
  539. */
  540. static VALUE
  541. ancillary_ipv6_pktinfo(VALUE self)
  542. {
  543. struct in6_pktinfo pktinfo;
  544. struct sockaddr_in6 sa;
  545. VALUE v_addr;
  546. extract_ipv6_pktinfo(self, &pktinfo, &sa);
  547. v_addr = rsock_addrinfo_new((struct sockaddr *)&sa, sizeof(sa), PF_INET6, 0, 0, Qnil, Qnil);
  548. return rb_ary_new3(2, v_addr, UINT2NUM(pktinfo.ipi6_ifindex));
  549. }
  550. #else
  551. #define ancillary_ipv6_pktinfo rb_f_notimplement
  552. #endif
  553. #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */
  554. /*
  555. * call-seq:
  556. * ancdata.ipv6_pktinfo_addr => addr
  557. *
  558. * Extracts addr from IPV6_PKTINFO ancillary data.
  559. *
  560. * IPV6_PKTINFO is defined by RFC 3542.
  561. *
  562. * addr = Addrinfo.ip("::1")
  563. * ifindex = 0
  564. * ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
  565. * p ancdata.ipv6_pktinfo_addr #=> #<Addrinfo: ::1>
  566. *
  567. */
  568. static VALUE
  569. ancillary_ipv6_pktinfo_addr(VALUE self)
  570. {
  571. struct in6_pktinfo pktinfo;
  572. struct sockaddr_in6 sa;
  573. extract_ipv6_pktinfo(self, &pktinfo, &sa);
  574. return rsock_addrinfo_new((struct sockaddr *)&sa, sizeof(sa), PF_INET6, 0, 0, Qnil, Qnil);
  575. }
  576. #else
  577. #define ancillary_ipv6_pktinfo_addr rb_f_notimplement
  578. #endif
  579. #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */
  580. /*
  581. * call-seq:
  582. * ancdata.ipv6_pktinfo_ifindex => addr
  583. *
  584. * Extracts ifindex from IPV6_PKTINFO ancillary data.
  585. *
  586. * IPV6_PKTINFO is defined by RFC 3542.
  587. *
  588. * addr = Addrinfo.ip("::1")
  589. * ifindex = 0
  590. * ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
  591. * p ancdata.ipv6_pktinfo_ifindex #=> 0
  592. *
  593. */
  594. static VALUE
  595. ancillary_ipv6_pktinfo_ifindex(VALUE self)
  596. {
  597. struct in6_pktinfo pktinfo;
  598. struct sockaddr_in6 sa;
  599. extract_ipv6_pktinfo(self, &pktinfo, &sa);
  600. return UINT2NUM(pktinfo.ipi6_ifindex);
  601. }
  602. #else
  603. #define ancillary_ipv6_pktinfo_ifindex rb_f_notimplement
  604. #endif
  605. #if defined(SOL_SOCKET) && defined(SCM_RIGHTS) /* 4.4BSD */
  606. static int
  607. anc_inspect_socket_rights(int level, int type, VALUE data, VALUE ret)
  608. {
  609. if (level == SOL_SOCKET && type == SCM_RIGHTS &&
  610. 0 < RSTRING_LEN(data) && (RSTRING_LEN(data) % sizeof(int) == 0)) {
  611. long off;
  612. for (off = 0; off < RSTRING_LEN(data); off += sizeof(int)) {
  613. int fd;
  614. memcpy((char*)&fd, RSTRING_PTR(data)+off, sizeof(int));
  615. rb_str_catf(ret, " %d", fd);
  616. }
  617. return 1;
  618. }
  619. else {
  620. return 0;
  621. }
  622. }
  623. #endif
  624. #if defined(SCM_CREDENTIALS) /* GNU/Linux */
  625. static int
  626. anc_inspect_passcred_credentials(int level, int type, VALUE data, VALUE ret)
  627. {
  628. if (level == SOL_SOCKET && type == SCM_CREDENTIALS &&
  629. RSTRING_LEN(data) == sizeof(struct ucred)) {
  630. struct ucred cred;
  631. memcpy(&cred, RSTRING_PTR(data), sizeof(struct ucred));
  632. rb_str_catf(ret, " pid=%u uid=%u gid=%u", cred.pid, cred.uid, cred.gid);
  633. rb_str_cat2(ret, " (ucred)");
  634. return 1;
  635. }
  636. else {
  637. return 0;
  638. }
  639. }
  640. #endif
  641. #if defined(SCM_CREDS)
  642. #define INSPECT_SCM_CREDS
  643. static int
  644. anc_inspect_socket_creds(int level, int type, VALUE data, VALUE ret)
  645. {
  646. if (level != SOL_SOCKET && type != SCM_CREDS)
  647. return 0;
  648. /*
  649. * FreeBSD has struct cmsgcred and struct sockcred.
  650. * They use both SOL_SOCKET/SCM_CREDS in the ancillary message.
  651. * They are not ambiguous from the view of the caller
  652. * because struct sockcred is sent if and only if the caller sets LOCAL_CREDS socket option.
  653. * But inspect method doesn't know it.
  654. * So they are ambiguous from the view of inspect.
  655. * This function distinguish them by the size of the ancillary message.
  656. * This heuristics works well except when sc_ngroups == CMGROUP_MAX.
  657. */
  658. #if defined(HAVE_TYPE_STRUCT_CMSGCRED) /* FreeBSD */
  659. if (RSTRING_LEN(data) == sizeof(struct cmsgcred)) {
  660. struct cmsgcred cred;
  661. memcpy(&cred, RSTRING_PTR(data), sizeof(struct cmsgcred));
  662. rb_str_catf(ret, " pid=%u", cred.cmcred_pid);
  663. rb_str_catf(ret, " uid=%u", cred.cmcred_uid);
  664. rb_str_catf(ret, " euid=%u", cred.cmcred_euid);
  665. rb_str_catf(ret, " gid=%u", cred.cmcred_gid);
  666. if (cred.cmcred_ngroups) {
  667. int i;
  668. const char *sep = " groups=";
  669. for (i = 0; i < cred.cmcred_ngroups; i++) {
  670. rb_str_catf(ret, "%s%u", sep, cred.cmcred_groups[i]);
  671. sep = ",";
  672. }
  673. }
  674. rb_str_cat2(ret, " (cmsgcred)");
  675. return 1;
  676. }
  677. #endif
  678. #if defined(HAVE_TYPE_STRUCT_SOCKCRED) /* FreeBSD, NetBSD */
  679. if ((size_t)RSTRING_LEN(data) >= SOCKCREDSIZE(0)) {
  680. struct sockcred cred0, *cred;
  681. memcpy(&cred0, RSTRING_PTR(data), SOCKCREDSIZE(0));
  682. if ((size_t)RSTRING_LEN(data) == SOCKCREDSIZE(cred0.sc_ngroups)) {
  683. cred = (struct sockcred *)ALLOCA_N(char, SOCKCREDSIZE(cred0.sc_ngroups));
  684. memcpy(cred, RSTRING_PTR(data), SOCKCREDSIZE(cred0.sc_ngroups));
  685. rb_str_catf(ret, " uid=%u", cred->sc_uid);
  686. rb_str_catf(ret, " euid=%u", cred->sc_euid);
  687. rb_str_catf(ret, " gid=%u", cred->sc_gid);
  688. rb_str_catf(ret, " egid=%u", cred->sc_egid);
  689. if (cred0.sc_ngroups) {
  690. int i;
  691. const char *sep = " groups=";
  692. for (i = 0; i < cred0.sc_ngroups; i++) {
  693. rb_str_catf(ret, "%s%u", sep, cred->sc_groups[i]);
  694. sep = ",";
  695. }
  696. }
  697. rb_str_cat2(ret, " (sockcred)");
  698. return 1;
  699. }
  700. }
  701. #endif
  702. return 0;
  703. }
  704. #endif
  705. #if defined(IPPROTO_IP) && defined(IP_RECVDSTADDR) /* 4.4BSD */
  706. static int
  707. anc_inspect_ip_recvdstaddr(int level, int type, VALUE data, VALUE ret)
  708. {
  709. if (level == IPPROTO_IP && type == IP_RECVDSTADDR &&
  710. RSTRING_LEN(data) == sizeof(struct in_addr)) {
  711. struct in_addr addr;
  712. char addrbuf[INET_ADDRSTRLEN];
  713. memcpy(&addr, RSTRING_PTR(data), sizeof(addr));
  714. if (inet_ntop(AF_INET, &addr, addrbuf, sizeof(addrbuf)) == NULL)
  715. rb_str_cat2(ret, " invalid-address");
  716. else
  717. rb_str_catf(ret, " %s", addrbuf);
  718. return 1;
  719. }
  720. else {
  721. return 0;
  722. }
  723. }
  724. #endif
  725. #if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_TYPE_STRUCT_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) /* GNU/Linux */
  726. static int
  727. anc_inspect_ip_pktinfo(int level, int type, VALUE data, VALUE ret)
  728. {
  729. if (level == IPPROTO_IP && type == IP_PKTINFO &&
  730. RSTRING_LEN(data) == sizeof(struct in_pktinfo)) {
  731. struct in_pktinfo pktinfo;
  732. char buf[INET_ADDRSTRLEN > IFNAMSIZ ? INET_ADDRSTRLEN : IFNAMSIZ];
  733. memcpy(&pktinfo, RSTRING_PTR(data), sizeof(pktinfo));
  734. if (inet_ntop(AF_INET, &pktinfo.ipi_addr, buf, sizeof(buf)) == NULL)
  735. rb_str_cat2(ret, " invalid-address");
  736. else
  737. rb_str_catf(ret, " %s", buf);
  738. if (if_indextoname(pktinfo.ipi_ifindex, buf) == NULL)
  739. rb_str_catf(ret, " ifindex:%d", pktinfo.ipi_ifindex);
  740. else
  741. rb_str_catf(ret, " %s", buf);
  742. if (inet_ntop(AF_INET, &pktinfo.ipi_spec_dst, buf, sizeof(buf)) == NULL)
  743. rb_str_cat2(ret, " spec_dst:invalid-address");
  744. else
  745. rb_str_catf(ret, " spec_dst:%s", buf);
  746. return 1;
  747. }
  748. else {
  749. return 0;
  750. }
  751. }
  752. #endif
  753. #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) && defined(HAVE_TYPE_STRUCT_IN6_PKTINFO) /* IPv6 RFC3542 */
  754. static int
  755. anc_inspect_ipv6_pktinfo(int level, int type, VALUE data, VALUE ret)
  756. {
  757. if (level == IPPROTO_IPV6 && type == IPV6_PKTINFO &&
  758. RSTRING_LEN(data) == sizeof(struct in6_pktinfo)) {
  759. struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)RSTRING_PTR(data);
  760. struct in6_addr addr;
  761. unsigned int ifindex;
  762. char addrbuf[INET6_ADDRSTRLEN], ifbuf[IFNAMSIZ];
  763. memcpy(&addr, &pktinfo->ipi6_addr, sizeof(addr));
  764. memcpy(&ifindex, &pktinfo->ipi6_ifindex, sizeof(ifindex));
  765. if (inet_ntop(AF_INET6, &addr, addrbuf, sizeof(addrbuf)) == NULL)
  766. rb_str_cat2(ret, " invalid-address");
  767. else
  768. rb_str_catf(ret, " %s", addrbuf);
  769. if (if_indextoname(ifindex, ifbuf) == NULL)
  770. rb_str_catf(ret, " ifindex:%d", ifindex);
  771. else
  772. rb_str_catf(ret, " %s", ifbuf);
  773. return 1;
  774. }
  775. else {
  776. return 0;
  777. }
  778. }
  779. #endif
  780. #if defined(SCM_TIMESTAMP) /* GNU/Linux, FreeBSD, NetBSD, OpenBSD, MacOS X, Solaris */
  781. static int
  782. inspect_timeval_as_abstime(int level, int optname, VALUE data, VALUE ret)
  783. {
  784. if (RSTRING_LEN(data) == sizeof(struct timeval)) {
  785. struct timeval tv;
  786. time_t time;
  787. struct tm tm;
  788. char buf[32];
  789. memcpy((char*)&tv, RSTRING_PTR(data), sizeof(tv));
  790. time = tv.tv_sec;
  791. tm = *localtime(&time);
  792. strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
  793. rb_str_catf(ret, " %s.%06ld", buf, (long)tv.tv_usec);
  794. return 1;
  795. }
  796. else {
  797. return 0;
  798. }
  799. }
  800. #endif
  801. #if defined(SCM_TIMESTAMPNS) /* GNU/Linux */
  802. static int
  803. inspect_timespec_as_abstime(int level, int optname, VALUE data, VALUE ret)
  804. {
  805. if (RSTRING_LEN(data) == sizeof(struct timespec)) {
  806. struct timespec ts;
  807. struct tm tm;
  808. char buf[32];
  809. memcpy((char*)&ts, RSTRING_PTR(data), sizeof(ts));
  810. tm = *localtime(&ts.tv_sec);
  811. strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
  812. rb_str_catf(ret, " %s.%09ld", buf, (long)ts.tv_nsec);
  813. return 1;
  814. }
  815. else {
  816. return 0;
  817. }
  818. }
  819. #endif
  820. #if defined(SCM_BINTIME) /* FreeBSD */
  821. static int
  822. inspect_bintime_as_abstime(int level, int optname, VALUE data, VALUE ret)
  823. {
  824. if (RSTRING_LEN(data) == sizeof(struct bintime)) {
  825. struct bintime bt;
  826. struct tm tm;
  827. uint64_t frac_h, frac_l;
  828. uint64_t scale_h, scale_l;
  829. uint64_t tmp1, tmp2;
  830. uint64_t res_h, res_l;
  831. char buf[32];
  832. memcpy((char*)&bt, RSTRING_PTR(data), sizeof(bt));
  833. tm = *localtime(&bt.sec);
  834. strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
  835. /* res_h = frac * 10**19 / 2**64 */
  836. frac_h = bt.frac >> 32;
  837. frac_l = bt.frac & 0xffffffff;
  838. scale_h = 0x8ac72304; /* 0x8ac7230489e80000 == 10**19 */
  839. scale_l = 0x89e80000;
  840. res_h = frac_h * scale_h;
  841. res_l = frac_l * scale_l;
  842. tmp1 = frac_h * scale_l;
  843. res_h += tmp1 >> 32;
  844. tmp2 = res_l;
  845. res_l += tmp1 & 0xffffffff;
  846. if (res_l < tmp2) res_h++;
  847. tmp1 = frac_l * scale_h;
  848. res_h += tmp1 >> 32;
  849. tmp2 = res_l;
  850. res_l += tmp1 & 0xffffffff;
  851. if (res_l < tmp2) res_h++;
  852. rb_str_catf(ret, " %s.%019"PRIu64, buf, res_h);
  853. return 1;
  854. }
  855. else {
  856. return 0;
  857. }
  858. }
  859. #endif
  860. /*
  861. * call-seq:
  862. * ancillarydata.inspect => string
  863. *
  864. * returns a string which shows ancillarydata in human-readable form.
  865. *
  866. * p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").inspect
  867. * #=> "#<Socket::AncillaryData: INET6 IPV6 PKTINFO \"\">"
  868. */
  869. static VALUE
  870. ancillary_inspect(VALUE self)
  871. {
  872. VALUE ret;
  873. int family, level, type;
  874. VALUE data;
  875. ID family_id, level_id, type_id;
  876. VALUE vtype;
  877. int inspected;
  878. family = ancillary_family(self);
  879. level = ancillary_level(self);
  880. type = ancillary_type(self);
  881. data = ancillary_data(self);
  882. ret = rb_sprintf("#<%s:", rb_obj_classname(self));
  883. family_id = rsock_intern_family_noprefix(family);
  884. if (family_id)
  885. rb_str_catf(ret, " %s", rb_id2name(family_id));
  886. else
  887. rb_str_catf(ret, " family:%d", family);
  888. if (level == SOL_SOCKET) {
  889. rb_str_cat2(ret, " SOCKET");
  890. type_id = rsock_intern_scm_optname(type);
  891. if (type_id)
  892. rb_str_catf(ret, " %s", rb_id2name(type_id));
  893. else
  894. rb_str_catf(ret, " cmsg_type:%d", type);
  895. }
  896. else if (IS_IP_FAMILY(family)) {
  897. level_id = rsock_intern_iplevel(level);
  898. if (level_id)
  899. rb_str_catf(ret, " %s", rb_id2name(level_id));
  900. else
  901. rb_str_catf(ret, " cmsg_level:%d", level);
  902. vtype = ip_cmsg_type_to_sym(level, type);
  903. if (SYMBOL_P(vtype))
  904. rb_str_catf(ret, " %s", rb_id2name(SYM2ID(vtype)));
  905. else
  906. rb_str_catf(ret, " cmsg_type:%d", type);
  907. }
  908. else {
  909. rb_str_catf(ret, " cmsg_level:%d", level);
  910. rb_str_catf(ret, " cmsg_type:%d", type);
  911. }
  912. inspected = 0;
  913. if (level == SOL_SOCKET)
  914. family = AF_UNSPEC;
  915. switch (family) {
  916. case AF_UNSPEC:
  917. switch (level) {
  918. # if defined(SOL_SOCKET)
  919. case SOL_SOCKET:
  920. switch (type) {
  921. # if defined(SCM_TIMESTAMP) /* GNU/Linux, FreeBSD, NetBSD, OpenBSD, MacOS X, Solaris */
  922. case SCM_TIMESTAMP: inspected = inspect_timeval_as_abstime(level, type, data, ret); break;
  923. # endif
  924. # if defined(SCM_TIMESTAMPNS) /* GNU/Linux */
  925. case SCM_TIMESTAMPNS: inspected = inspect_timespec_as_abstime(level, type, data, ret); break;
  926. # endif
  927. # if defined(SCM_BINTIME) /* FreeBSD */
  928. case SCM_BINTIME: inspected = inspect_bintime_as_abstime(level, type, data, ret); break;
  929. # endif
  930. # if defined(SCM_RIGHTS) /* 4.4BSD */
  931. case SCM_RIGHTS: inspected = anc_inspect_socket_rights(level, type, data, ret); break;
  932. # endif
  933. # if defined(SCM_CREDENTIALS) /* GNU/Linux */
  934. case SCM_CREDENTIALS: inspected = anc_inspect_passcred_credentials(level, type, data, ret); break;
  935. # endif
  936. # if defined(INSPECT_SCM_CREDS) /* NetBSD */
  937. case SCM_CREDS: inspected = anc_inspect_socket_creds(level, type, data, ret); break;
  938. # endif
  939. }
  940. break;
  941. # endif
  942. }
  943. break;
  944. case AF_INET:
  945. #ifdef INET6
  946. case AF_INET6:
  947. #endif
  948. switch (level) {
  949. # if defined(IPPROTO_IP)
  950. case IPPROTO_IP:
  951. switch (type) {
  952. # if defined(IP_RECVDSTADDR) /* 4.4BSD */
  953. case IP_RECVDSTADDR: inspected = anc_inspect_ip_recvdstaddr(level, type, data, ret); break;
  954. # endif
  955. # if defined(IP_PKTINFO) && defined(HAVE_TYPE_STRUCT_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) /* GNU/Linux */
  956. case IP_PKTINFO: inspected = anc_inspect_ip_pktinfo(level, type, data, ret); break;
  957. # endif
  958. }
  959. break;
  960. # endif
  961. # if defined(IPPROTO_IPV6)
  962. case IPPROTO_IPV6:
  963. switch (type) {
  964. # if defined(IPV6_PKTINFO) /* RFC 3542 */
  965. case IPV6_PKTINFO: inspected = anc_inspect_ipv6_pktinfo(level, type, data, ret); break;
  966. # endif
  967. }
  968. break;
  969. # endif
  970. }
  971. break;
  972. }
  973. if (!inspected) {
  974. data = rb_str_dump(data);
  975. rb_str_catf(ret, " %s", StringValueCStr(data));
  976. }
  977. rb_str_cat2(ret, ">");
  978. return ret;
  979. }
  980. /*
  981. * call-seq:
  982. * ancillarydata.cmsg_is?(level, type) => true or false
  983. *
  984. * tests the level and type of _ancillarydata_.
  985. *
  986. * ancdata = Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "")
  987. * ancdata.cmsg_is?(Socket::IPPROTO_IPV6, Socket::IPV6_PKTINFO) #=> true
  988. * ancdata.cmsg_is?(:IPV6, :PKTINFO) #=> true
  989. * ancdata.cmsg_is?(:IP, :PKTINFO) #=> false
  990. * ancdata.cmsg_is?(:SOCKET, :RIGHTS) #=> false
  991. */
  992. static VALUE
  993. ancillary_cmsg_is_p(VALUE self, VALUE vlevel, VALUE vtype)
  994. {
  995. int family = ancillary_family(self);
  996. int level = rsock_level_arg(family, vlevel);
  997. int type = rsock_cmsg_type_arg(family, level, vtype);
  998. if (ancillary_level(self) == level &&
  999. ancillary_type(self) == type)
  1000. return Qtrue;
  1001. else
  1002. return Qfalse;
  1003. }
  1004. #endif
  1005. #if defined(HAVE_SENDMSG)
  1006. struct sendmsg_args_struct {
  1007. int fd;
  1008. const struct msghdr *msg;
  1009. int flags;
  1010. };
  1011. static VALUE
  1012. nogvl_sendmsg_func(void *ptr)
  1013. {
  1014. struct sendmsg_args_struct *args = ptr;
  1015. return sendmsg(args->fd, args->msg, args->flags);
  1016. }
  1017. static ssize_t
  1018. rb_sendmsg(int fd, const struct msghdr *msg, int flags)
  1019. {
  1020. struct sendmsg_args_struct args;
  1021. args.fd = fd;
  1022. args.msg = msg;
  1023. args.flags = flags;
  1024. return rb_thread_blocking_region(nogvl_sendmsg_func, &args, RUBY_UBF_IO, 0);
  1025. }
  1026. static VALUE
  1027. bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
  1028. {
  1029. rb_io_t *fptr;
  1030. VALUE data, vflags, dest_sockaddr;
  1031. VALUE *controls_ptr;
  1032. int controls_num;
  1033. struct msghdr mh;
  1034. struct iovec iov;
  1035. #if defined(HAVE_ST_MSG_CONTROL)
  1036. volatile VALUE controls_str = 0;
  1037. #endif
  1038. int flags;
  1039. ssize_t ss;
  1040. int family;
  1041. rb_secure(4);
  1042. GetOpenFile(sock, fptr);
  1043. family = rsock_getfamily(fptr->fd);
  1044. data = vflags = dest_sockaddr = Qnil;
  1045. controls_ptr = NULL;
  1046. controls_num = 0;
  1047. if (argc == 0)
  1048. rb_raise(rb_eArgError, "mesg argument required");
  1049. data = argv[0];
  1050. if (1 < argc) vflags = argv[1];
  1051. if (2 < argc) dest_sockaddr = argv[2];
  1052. if (3 < argc) { controls_ptr = &argv[3]; controls_num = argc - 3; }
  1053. StringValue(data);
  1054. if (controls_num) {
  1055. #if defined(HAVE_ST_MSG_CONTROL)
  1056. int i;
  1057. int last_pad = 0;
  1058. int last_level = 0;
  1059. int last_type = 0;
  1060. controls_str = rb_str_tmp_new(0);
  1061. for (i = 0; i < controls_num; i++) {
  1062. VALUE elt = controls_ptr[i], v;
  1063. VALUE vlevel, vtype;
  1064. int level, type;
  1065. VALUE cdata;
  1066. long oldlen;
  1067. struct cmsghdr cmh;
  1068. char *cmsg;
  1069. size_t cspace;
  1070. v = rb_check_convert_type(elt, T_ARRAY, "Array", "to_ary");
  1071. if (!NIL_P(v)) {
  1072. elt = v;
  1073. if (RARRAY_LEN(elt) != 3)
  1074. rb_raise(rb_eArgError, "an element of controls should be 3-elements array");
  1075. vlevel = rb_ary_entry(elt, 0);
  1076. vtype = rb_ary_entry(elt, 1);
  1077. cdata = rb_ary_entry(elt, 2);
  1078. }
  1079. else {
  1080. vlevel = rb_funcall(elt, rb_intern("level"), 0);
  1081. vtype = rb_funcall(elt, rb_intern("type"), 0);
  1082. cdata = rb_funcall(elt, rb_intern("data"), 0);
  1083. }
  1084. level = rsock_level_arg(family, vlevel);
  1085. type = rsock_cmsg_type_arg(family, level, vtype);
  1086. StringValue(cdata);
  1087. oldlen = RSTRING_LEN(controls_str);
  1088. cspace = CMSG_SPACE(RSTRING_LEN(cdata));
  1089. rb_str_resize(controls_str, oldlen + cspace);
  1090. cmsg = RSTRING_PTR(controls_str)+oldlen;
  1091. memset((char *)cmsg, 0, cspace);
  1092. memset((char *)&cmh, 0, sizeof(cmh));
  1093. cmh.cmsg_level = level;
  1094. cmh.cmsg_type = type;
  1095. cmh.cmsg_len = CMSG_LEN(RSTRING_LEN(cdata));
  1096. MEMCPY(cmsg, &cmh, char, sizeof(cmh));
  1097. MEMCPY(cmsg+((char*)CMSG_DATA(&cmh)-(char*)&cmh), RSTRING_PTR(cdata), char, RSTRING_LEN(cdata));
  1098. last_level = cmh.cmsg_level;
  1099. last_type = cmh.cmsg_type;
  1100. last_pad = cspace - cmh.cmsg_len;
  1101. }
  1102. if (last_pad) {
  1103. /*
  1104. * This code removes the last padding from msg_controllen.
  1105. *
  1106. * 4.3BSD-Reno reject the padding for SCM_RIGHTS. (There was no 64bit environments in those days?)
  1107. * RFC 2292 require the padding.
  1108. * RFC 3542 relaxes the condition - implementation must accept both as valid.
  1109. *
  1110. * Actual problems:
  1111. *
  1112. * - NetBSD 4.0.1
  1113. * SCM_RIGHTS with padding causes EINVAL
  1114. * IPV6_PKTINFO without padding causes "page fault trap"
  1115. * http://www.netbsd.org/cgi-bin/query-pr-single.pl?number=40661
  1116. *
  1117. * - OpenBSD 4.4
  1118. * IPV6_PKTINFO without padding causes EINVAL
  1119. *
  1120. * Basically, msg_controllen should contains the padding.
  1121. * So the padding is removed only if a problem really exists.
  1122. */
  1123. #if defined(__NetBSD__)
  1124. if (last_level == SOL_SOCKET && last_type == SCM_RIGHTS)
  1125. rb_str_set_len(controls_str, RSTRING_LEN(controls_str)-last_pad);
  1126. #endif
  1127. }
  1128. #else
  1129. rb_raise(rb_eNotImpError, "control message for sendmsg is unimplemented");
  1130. #endif
  1131. }
  1132. flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
  1133. #ifdef MSG_DONTWAIT
  1134. if (nonblock)
  1135. flags |= MSG_DONTWAIT;
  1136. #endif
  1137. if (!NIL_P(dest_sockaddr))
  1138. SockAddrStringValue(dest_sockaddr);
  1139. rb_io_check_closed(fptr);
  1140. retry:
  1141. memset(&mh, 0, sizeof(mh));
  1142. if (!NIL_P(dest_sockaddr)) {
  1143. mh.msg_name = RSTRING_PTR(dest_sockaddr);
  1144. mh.msg_namelen = RSTRING_LEN(dest_sockaddr);
  1145. }
  1146. mh.msg_iovlen = 1;
  1147. mh.msg_iov = &iov;
  1148. iov.iov_base = RSTRING_PTR(data);
  1149. iov.iov_len = RSTRING_LEN(data);
  1150. #if defined(HAVE_ST_MSG_CONTROL)
  1151. if (controls_str) {
  1152. mh.msg_control = RSTRING_PTR(controls_str);
  1153. mh.msg_controllen = RSTRING_LEN(controls_str);
  1154. }
  1155. else {
  1156. mh.msg_control = NULL;
  1157. mh.msg_controllen = 0;
  1158. }
  1159. #endif
  1160. rb_io_check_closed(fptr);
  1161. if (nonblock)
  1162. rb_io_set_nonblock(fptr);
  1163. ss = rb_sendmsg(fptr->fd, &mh, flags);
  1164. if (!nonblock && rb_io_wait_writable(fptr->fd)) {
  1165. rb_io_check_closed(fptr);
  1166. goto retry;
  1167. }
  1168. if (ss == -1) {
  1169. if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
  1170. rb_mod_sys_fail(rb_mWaitWritable, "sendmsg(2) would block");
  1171. rb_sys_fail("sendmsg(2)");
  1172. }
  1173. return SSIZET2NUM(ss);
  1174. }
  1175. #endif
  1176. #if defined(HAVE_SENDMSG)
  1177. /*
  1178. * call-seq:
  1179. * basicsocket.sendmsg(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent
  1180. *
  1181. * sendmsg sends a message using sendmsg(2) system call in blocking manner.
  1182. *
  1183. * _mesg_ is a string to send.
  1184. *
  1185. * _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_OOB.
  1186. *
  1187. * _dest_sockaddr_ is a destination socket address for connection-less socket.
  1188. * It should be a sockaddr such as a result of Socket.sockaddr_in.
  1189. * An Addrinfo object can be used too.
  1190. *
  1191. * _controls_ is a list of ancillary data.
  1192. * The element of _controls_ should be Socket::AncillaryData or
  1193. * 3-elements array.
  1194. * The 3-element array should contains cmsg_level, cmsg_type and data.
  1195. *
  1196. * The return value, _numbytes_sent_ is an integer which is the number of bytes sent.
  1197. *
  1198. * sendmsg can be used to implement send_io as follows:
  1199. *
  1200. * # use Socket::AncillaryData.
  1201. * ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, io.fileno)
  1202. * sock.sendmsg("a", 0, nil, ancdata)
  1203. *
  1204. * # use 3-element array.
  1205. * ancdata = [:SOCKET, :RIGHTS, [io.fileno].pack("i!")]
  1206. * sock.sendmsg("\0", 0, nil, ancdata)
  1207. *
  1208. */
  1209. static VALUE
  1210. bsock_sendmsg(int argc, VALUE *argv, VALUE sock)
  1211. {
  1212. return bsock_sendmsg_internal(argc, argv, sock, 0);
  1213. }
  1214. #else
  1215. #define bsock_sendmsg rb_f_notimplement
  1216. #endif
  1217. #if defined(HAVE_SENDMSG)
  1218. /*
  1219. * call-seq:
  1220. * basicsocket.sendmsg_nonblock(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent
  1221. *
  1222. * sendmsg_nonblock sends a message using sendmsg(2) system call in non-blocking manner.
  1223. *
  1224. * It is similar to BasicSocket#sendmsg
  1225. * but the non-blocking flag is set before the system call
  1226. * and it doesn't retry the system call.
  1227. *
  1228. */
  1229. static VALUE
  1230. bsock_sendmsg_nonblock(int argc, VALUE *argv, VALUE sock)
  1231. {
  1232. return bsock_sendmsg_internal(argc, argv, sock, 1);
  1233. }
  1234. #else
  1235. #define bsock_sendmsg_nonblock rb_f_notimplement
  1236. #endif
  1237. #if defined(HAVE_RECVMSG)
  1238. struct recvmsg_args_struct {
  1239. int fd;
  1240. struct msghdr *msg;
  1241. int flags;
  1242. };
  1243. static VALUE
  1244. nogvl_recvmsg_func(void *ptr)
  1245. {
  1246. struct recvmsg_args_struct *args = ptr;
  1247. return recvmsg(args->fd, args->msg, args->flags);
  1248. }
  1249. static ssize_t
  1250. rb_recvmsg(int fd, struct msghdr *msg, int flags)
  1251. {
  1252. struct recvmsg_args_struct args;
  1253. args.fd = fd;
  1254. args.msg = msg;
  1255. args.flags = flags;
  1256. return rb_thread_blocking_region(nogvl_recvmsg_func, &args, RUBY_UBF_IO, 0);
  1257. }
  1258. #if defined(HAVE_ST_MSG_CONTROL)
  1259. static void
  1260. discard_cmsg(struct cmsghdr *cmh, char *msg_end)
  1261. {
  1262. if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
  1263. int *fdp = (int *)CMSG_DATA(cmh);
  1264. int *end = (int *)((char *)cmh + cmh->cmsg_len);
  1265. while ((char *)fdp + sizeof(int) <= (char *)end &&
  1266. (char *)fdp + sizeof(int) <= msg_end) {
  1267. close(*fdp);
  1268. fdp++;
  1269. }
  1270. }
  1271. }
  1272. #endif
  1273. void
  1274. rsock_discard_cmsg_resource(struct msghdr *mh)
  1275. {
  1276. #if defined(HAVE_ST_MSG_CONTROL)
  1277. struct cmsghdr *cmh;
  1278. char *msg_end;
  1279. if (mh->msg_controllen == 0)
  1280. return;
  1281. msg_end = (char *)mh->msg_control + mh->msg_controllen;
  1282. for (cmh = CMSG_FIRSTHDR(mh); cmh != NULL; cmh = CMSG_NXTHDR(mh, cmh)) {
  1283. discard_cmsg(cmh, msg_end);
  1284. }
  1285. #endif
  1286. }
  1287. #if defined(HAVE_ST_MSG_CONTROL)
  1288. static void
  1289. make_io_for_unix_rights(VALUE ctl, struct cmsghdr *cmh, char *msg_end)
  1290. {
  1291. if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
  1292. int *fdp, *end;
  1293. VALUE ary = rb_ary_new();
  1294. rb_ivar_set(ctl, rb_intern("unix_rights"), ary);
  1295. fdp = (int *)CMSG_DATA(cmh);
  1296. end = (int *)((char *)cmh + cmh->cmsg_len);
  1297. while ((char *)fdp + sizeof(int) <= (char *)end &&
  1298. (char *)fdp + sizeof(int) <= msg_end) {
  1299. int fd = *fdp;
  1300. struct stat stbuf;
  1301. VALUE io;
  1302. if (fstat(fd, &stbuf) == -1)
  1303. rb_raise(rb_eSocket, "invalid fd in SCM_RIGHTS");
  1304. if (S_ISSOCK(stbuf.st_mode))
  1305. io = rsock_init_sock(rb_obj_alloc(rb_cSocket), fd);
  1306. else
  1307. io = rb_io_fdopen(fd, O_RDWR, NULL);
  1308. ary = rb_attr_get(ctl, rb_intern("unix_rights"));
  1309. rb_ary_push(ary, io);
  1310. fdp++;
  1311. }
  1312. OBJ_FREEZE(ary);
  1313. }
  1314. }
  1315. #endif
  1316. static VALUE
  1317. bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
  1318. {
  1319. rb_io_t *fptr;
  1320. VALUE vmaxdatlen, vmaxctllen, vflags, vopts;
  1321. int grow_buffer;
  1322. size_t maxdatlen;
  1323. int flags, orig_flags;
  1324. int request_scm_rights;
  1325. struct msghdr mh;
  1326. struct iovec iov;
  1327. struct sockaddr_storage namebuf;
  1328. char datbuf0[4096], *datbuf;
  1329. VALUE dat_str = Qnil;
  1330. VALUE ret;
  1331. ssize_t ss;
  1332. #if defined(HAVE_ST_MSG_CONTROL)
  1333. struct cmsghdr *cmh;
  1334. size_t maxctllen;
  1335. union {
  1336. char bytes[4096];
  1337. struct cmsghdr align;
  1338. } ctlbuf0;
  1339. char *ctlbuf;
  1340. VALUE ctl_str = Qnil;
  1341. int family;
  1342. int gc_done = 0;
  1343. #endif
  1344. rb_secure(4);
  1345. vopts = Qnil;
  1346. if (0 < argc && TYPE(argv[argc-1]) == T_HASH)
  1347. vopts = argv[--argc];
  1348. rb_scan_args(argc, argv, "03", &vmaxdatlen, &vflags, &vmaxctllen);
  1349. maxdatlen = NIL_P(vmaxdatlen) ? sizeof(datbuf0) : NUM2SIZET(vmaxdatlen);
  1350. #if defined(HAVE_ST_MSG_CONTROL)
  1351. maxctllen = NIL_P(vmaxctllen) ? sizeof(ctlbuf0) : NUM2SIZET(vmaxctllen);
  1352. #else
  1353. if (!NIL_P(vmaxctllen))
  1354. rb_raise(rb_eArgError, "control message not supported");
  1355. #endif
  1356. flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
  1357. #ifdef MSG_DONTWAIT
  1358. if (nonblock)
  1359. flags |= MSG_DONTWAIT;
  1360. #endif
  1361. orig_flags = flags;
  1362. grow_buffer = NIL_P(vmaxdatlen) || NIL_P(vmaxctllen);
  1363. request_scm_rights = 0;
  1364. if (!NIL_P(vopts) && RTEST(rb_hash_aref(vopts, ID2SYM(rb_intern("scm_rights")))))
  1365. request_scm_rights = 1;
  1366. GetOpenFile(sock, fptr);
  1367. if (rb_io_read_pending(fptr)) {
  1368. rb_raise(rb_eIOError, "recvmsg for buffered IO");
  1369. }
  1370. #if !defined(HAVE_ST_MSG_CONTROL)
  1371. if (grow_buffer) {
  1372. int socktype, optlen = sizeof(socktype);
  1373. if (getsockopt(fptr->fd, SOL_SOCKET, SO_TYPE, (void*)&socktype, &optlen) == -1) {
  1374. rb_sys_fail("getsockopt(SO_TYPE)");
  1375. }
  1376. if (socktype == SOCK_STREAM)
  1377. grow_buffer = 0;
  1378. }
  1379. #endif
  1380. retry:
  1381. if (maxdatlen <= sizeof(datbuf0))
  1382. datbuf = datbuf0;
  1383. else {
  1384. if (NIL_P(dat_str))
  1385. dat_str = rb_str_tmp_new(maxdatlen);
  1386. else
  1387. rb_str_resize(dat_str, maxdatlen);
  1388. datbuf = RSTRING_PTR(dat_str);
  1389. }
  1390. #if defined(HAVE_ST_MSG_CONTROL)
  1391. if (maxctllen <= sizeof(ctlbuf0))
  1392. ctlbuf = ctlbuf0.bytes;
  1393. else {
  1394. if (NIL_P(ctl_str))
  1395. ctl_str = rb_str_tmp_new(maxctllen);
  1396. else
  1397. rb_str_resize(ctl_str, maxctllen);
  1398. ctlbuf = RSTRING_PTR(ctl_str);
  1399. }
  1400. #endif
  1401. memset(&mh, 0, sizeof(mh));
  1402. memset(&namebuf, 0, sizeof(namebuf));
  1403. mh.msg_name = (struct sockaddr *)&namebuf;
  1404. mh.msg_namelen = sizeof(namebuf);
  1405. mh.msg_iov = &iov;
  1406. mh.msg_iovlen = 1;
  1407. iov.iov_base = datbuf;
  1408. iov.iov_len = maxdatlen;
  1409. #if defined(HAVE_ST_MSG_CONTROL)
  1410. mh.msg_control = ctlbuf;
  1411. mh.msg_controllen = maxctllen;
  1412. #endif
  1413. if (grow_buffer)
  1414. flags |= MSG_PEEK;
  1415. rb_io_check_closed(fptr);
  1416. if (nonblock)
  1417. rb_io_set_nonblock(fptr);
  1418. ss = rb_recvmsg(fptr->fd, &mh, flags);
  1419. if (!nonblock && rb_io_wait_readable(fptr->fd)) {
  1420. rb_io_check_closed(fptr);
  1421. goto retry;
  1422. }
  1423. if (ss == -1) {
  1424. if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
  1425. rb_mod_sys_fail(rb_mWaitReadable, "recvmsg(2) would block");
  1426. #if defined(HAVE_ST_MSG_CONTROL)
  1427. if (!gc_done && (errno == EMFILE || errno == EMSGSIZE)) {
  1428. /*
  1429. * When SCM_RIGHTS hit the file descriptors limit:
  1430. * - Linux 2.6.18 causes success with MSG_CTRUNC
  1431. * - MacOS X 10.4 causes EMSGSIZE (and lost file descriptors?)
  1432. * - Solaris 11 causes EMFILE
  1433. */
  1434. gc_and_retry:
  1435. rb_gc();
  1436. gc_done = 1;
  1437. goto retry;
  1438. }
  1439. #endif
  1440. rb_sys_fail("recvmsg(2)");
  1441. }
  1442. if (grow_buffer) {
  1443. int grown = 0;
  1444. #if defined(HAVE_ST_MSG_CONTROL)
  1445. if (NIL_P(vmaxdatlen) && (mh.msg_flags & MSG_TRUNC)) {
  1446. if (SIZE_MAX/2 < maxdatlen)
  1447. rb_raise(rb_eArgError, "max data length too big");
  1448. maxdatlen *= 2;
  1449. grown = 1;
  1450. }
  1451. if (NIL_P(vmaxctllen) && (mh.msg_flags & MSG_CTRUNC)) {
  1452. #define BIG_ENOUGH_SPACE 65536
  1453. if (BIG_ENOUGH_SPACE < maxctllen &&
  1454. mh.msg_controllen < maxctllen - BIG_ENOUGH_SPACE) {
  1455. /* there are big space bug truncated.
  1456. * file descriptors limit? */
  1457. if (!gc_done) {
  1458. rsock_discard_cmsg_resource(&mh);
  1459. goto gc_and_retry;
  1460. }
  1461. }
  1462. else {
  1463. if (SIZE_MAX/2 < maxctllen)
  1464. rb_raise(rb_eArgError, "max control message length too big");
  1465. maxctllen *= 2;
  1466. grown = 1;
  1467. }
  1468. #undef BIG_ENOUGH_SPACE
  1469. }
  1470. #else
  1471. if (NIL_P(vmaxdatlen) && ss != -1 && ss == iov.iov_len) {
  1472. if (SIZE_MAX/2 < maxdatlen)
  1473. rb_raise(rb_eArgError, "max data length too big");
  1474. maxdatlen *= 2;
  1475. grown = 1;
  1476. }
  1477. #endif
  1478. if (grown) {
  1479. rsock_discard_cmsg_resource(&mh);
  1480. goto retry;
  1481. }
  1482. else {
  1483. grow_buffer = 0;
  1484. if (flags != orig_flags) {
  1485. flags = orig_flags;
  1486. rsock_discard_cmsg_resource(&mh);
  1487. goto retry;
  1488. }
  1489. }
  1490. }
  1491. if (NIL_P(dat_str))
  1492. dat_str = rb_tainted_str_new(datbuf, ss);
  1493. else {
  1494. rb_str_resize(dat_str, ss);
  1495. OBJ_TAINT(dat_str);
  1496. RBASIC(dat_str)->klass = rb_cString;
  1497. }
  1498. ret = rb_ary_new3(3, dat_str,
  1499. rsock_io_socket_addrinfo(sock, mh.msg_name, mh.msg_namelen),
  1500. #if defined(HAVE_ST_MSG_CONTROL)
  1501. INT2NUM(mh.msg_flags)
  1502. #else
  1503. Qnil
  1504. #endif
  1505. );
  1506. #if defined(HAVE_ST_MSG_CONTROL)
  1507. family = rsock_getfamily(fptr->fd);
  1508. if (mh.msg_controllen) {
  1509. char *msg_end = (char *)mh.msg_control + mh.msg_controllen;
  1510. for (cmh = CMSG_FIRSTHDR(&mh); cmh != NULL; cmh = CMSG_NXTHDR(&mh, cmh)) {
  1511. VALUE ctl;
  1512. char *ctl_end;
  1513. size_t clen;
  1514. if (cmh->cmsg_len == 0) {
  1515. rb_raise(rb_eTypeError, "invalid control message (cmsg_len == 0)");
  1516. }
  1517. ctl_end = (char*)cmh + cmh->cmsg_len;
  1518. clen = (ctl_end <= msg_end ? ctl_end : msg_end) - (char*)CMSG_DATA(cmh);
  1519. ctl = ancdata_new(family, cmh->cmsg_level, cmh->cmsg_type, rb_tainted_str_new((char*)CMSG_DATA(cmh), clen));
  1520. if (request_scm_rights)
  1521. make_io_for_unix_rights(ctl, cmh, msg_end);
  1522. else
  1523. discard_cmsg(cmh, msg_end);
  1524. rb_ary_push(ret, ctl);
  1525. }
  1526. }
  1527. #endif
  1528. return ret;
  1529. }
  1530. #endif
  1531. #if defined(HAVE_RECVMSG)
  1532. /*
  1533. * call-seq:
  1534. * basicsocket.recvmsg(maxmesglen=nil, flags=0, maxcontrollen=nil, opts={}) => [mesg, sender_addrinfo, rflags, *controls]
  1535. *
  1536. * recvmsg receives a message using recvmsg(2) system call in blocking manner.
  1537. *
  1538. * _maxmesglen_ is the maximum length of mesg to receive.
  1539. *
  1540. * _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_PEEK.
  1541. *
  1542. * _maxcontrollen_ is the maximum length of controls (ancillary data) to receive.
  1543. *
  1544. * _opts_ is option hash.
  1545. * Currently :scm_rights=>bool is the only option.
  1546. *
  1547. * :scm_rights option specifies that application expects SCM_RIGHTS control message.
  1548. * If the value is nil or false, application don't expects SCM_RIGHTS control message.
  1549. * In this case, recvmsg closes the passed file descriptors immediately.
  1550. * This is the default behavior.
  1551. *
  1552. * If :scm_rights value is neither nil nor false, application expects SCM_RIGHTS control message.
  1553. * In this case, recvmsg creates IO objects for each file descriptors for
  1554. * Socket::AncillaryData#unix_rights method.
  1555. *
  1556. * The return value is 4-elements array.
  1557. *
  1558. * _mesg_ is a string of the received message.
  1559. *
  1560. * _sender_addrinfo_ is a sender socket address for connection-less socket.
  1561. * It is an Addrinfo object.
  1562. * For connection-oriented socket such as TCP, sender_addrinfo is platform dependent.
  1563. *
  1564. * _rflags_ is a flags on the received message which is bitwise OR of MSG_* constants such as Socket::MSG_TRUNC.
  1565. * It will be nil if the system uses 4.3BSD style old recvmsg system call.
  1566. *
  1567. * _controls_ is ancillary data which is an array of Socket::AncillaryData objects such as:
  1568. *
  1569. * #<Socket::AncillaryData: AF_UNIX SOCKET RIGHTS 7>
  1570. *
  1571. * _maxmesglen_ and _maxcontrollen_ can be nil.
  1572. * In that case, the buffer will be grown until the message is not truncated.
  1573. * Internally, MSG_PEEK is used and MSG_TRUNC/MSG_CTRUNC are checked.
  1574. *
  1575. * recvmsg can be used to implement recv_io as follows:
  1576. *
  1577. * mesg, sender_sockaddr, rflags, *controls = sock.recvmsg(:scm_rights=>true)
  1578. * controls.each {|ancdata|
  1579. * if ancdata.cmsg_is?(:SOCKET, :RIGHTS)
  1580. * return ancdata.unix_rights[0]
  1581. * end
  1582. * }
  1583. *
  1584. */
  1585. static VALUE
  1586. bsock_recvmsg(int argc, VALUE *argv, VALUE sock)
  1587. {
  1588. return bsock_recvmsg_internal(argc, argv, sock, 0);
  1589. }
  1590. #else
  1591. #define bsock_recvmsg rb_f_notimplement
  1592. #endif
  1593. #if defined(HAVE_RECVMSG)
  1594. /*
  1595. * call-seq:
  1596. * basicsocket.recvmsg_nonblock(maxdatalen=nil, flags=0, maxcontrollen=nil, opts={}) => [data, sender_addrinfo, rflags, *controls]
  1597. *
  1598. * recvmsg receives a message using recvmsg(2) system call in non-blocking manner.
  1599. *
  1600. * It is similar to BasicSocket#recvmsg
  1601. * but non-blocking flag is set before the system call
  1602. * and it doesn't retry the system call.
  1603. *
  1604. */
  1605. static VALUE
  1606. bsock_recvmsg_nonblock(int argc, VALUE *argv, VALUE sock)
  1607. {
  1608. return bsock_recvmsg_internal(argc, argv, sock, 1);
  1609. }
  1610. #else
  1611. #define bsock_recvmsg_nonblock rb_f_notimplement
  1612. #endif
  1613. void
  1614. Init_ancdata(void)
  1615. {
  1616. /* for rdoc */
  1617. /* rb_cBasicSocket = rb_define_class("BasicSocket", rb_cIO); */
  1618. /* rb_cSocket = rb_define_class("Socket", rb_cBasicSocket); */
  1619. rb_define_method(rb_cBasicSocket, "sendmsg", bsock_sendmsg, -1);
  1620. rb_define_method(rb_cBasicSocket, "sendmsg_nonblock", bsock_sendmsg_nonblock, -1);
  1621. rb_define_method(rb_cBasicSocket, "recvmsg", bsock_recvmsg, -1);
  1622. rb_define_method(rb_cBasicSocket, "recvmsg_nonblock", bsock_recvmsg_nonblock, -1);
  1623. #if defined(HAVE_ST_MSG_CONTROL)
  1624. rb_cAncillaryData = rb_define_class_under(rb_cSocket, "AncillaryData", rb_cObject);
  1625. rb_define_method(rb_cAncillaryData, "initialize", ancillary_initialize, 4);
  1626. rb_define_method(rb_cAncillaryData, "inspect", ancillary_inspect, 0);
  1627. rb_define_method(rb_cAncillaryData, "family", ancillary_family_m, 0);
  1628. rb_define_method(rb_cAncillaryData, "level", ancillary_level_m, 0);
  1629. rb_define_method(rb_cAncillaryData, "type", ancillary_type_m, 0);
  1630. rb_define_method(rb_cAncillaryData, "data", ancillary_data, 0);
  1631. rb_define_method(rb_cAncillaryData, "cmsg_is?", ancillary_cmsg_is_p, 2);
  1632. rb_define_singleton_method(rb_cAncillaryData, "int", ancillary_s_int, 4);
  1633. rb_define_method(rb_cAncillaryData, "int", ancillary_int, 0);
  1634. rb_define_singleton_method(rb_cAncillaryData, "unix_rights", ancillary_s_unix_rights, -1);
  1635. rb_define_method(rb_cAncillaryData, "unix_rights", ancillary_unix_rights, 0);
  1636. rb_define_method(rb_cAncillaryData, "timestamp", ancillary_timestamp, 0);
  1637. rb_define_singleton_method(rb_cAncillaryData, "ip_pktinfo", ancillary_s_ip_pktinfo, -1);
  1638. rb_define_method(rb_cAncillaryData, "ip_pktinfo", ancillary_ip_pktinfo, 0);
  1639. rb_define_singleton_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_s_ipv6_pktinfo, 2);
  1640. rb_define_method(rb_cAncillaryData, "ipv6_pktinfo", ancillary_ipv6_pktinfo, 0);
  1641. rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_addr", ancillary_ipv6_pktinfo_addr, 0);
  1642. rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_ifindex", ancillary_ipv6_pktinfo_ifindex, 0);
  1643. #endif
  1644. }