PageRenderTime 57ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/ext/socket/ancdata.c

http://github.com/ruby/ruby
C | 1736 lines | 1250 code | 159 blank | 327 comment | 292 complexity | 4ca4d9f7245f4b81a793368412fa651e MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, AGPL-3.0

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file