PageRenderTime 1245ms CodeModel.GetById 26ms RepoModel.GetById 3ms app.codeStats 1ms

/ext/socket/ancdata.c

https://github.com/ahwuyeah/ruby
C | 1838 lines | 1244 code | 162 blank | 432 comment | 295 complexity | 493d03bf4d1214150b1506140d9c1d1c MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-3.0, Unlicense, GPL-2.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. #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
  5. static VALUE rb_cAncillaryData;
  6. static VALUE
  7. constant_to_sym(int constant, ID (*intern_const)(int))
  8. {
  9. ID name = intern_const(constant);
  10. if (name) {
  11. return ID2SYM(name);
  12. }
  13. return INT2NUM(constant);
  14. }
  15. static VALUE
  16. ip_cmsg_type_to_sym(int level, int cmsg_type)
  17. {
  18. switch (level) {
  19. case SOL_SOCKET:
  20. return constant_to_sym(cmsg_type, rsock_intern_scm_optname);
  21. case IPPROTO_IP:
  22. return constant_to_sym(cmsg_type, rsock_intern_ip_optname);
  23. #ifdef IPPROTO_IPV6
  24. case IPPROTO_IPV6:
  25. return constant_to_sym(cmsg_type, rsock_intern_ipv6_optname);
  26. #endif
  27. case IPPROTO_TCP:
  28. return constant_to_sym(cmsg_type, rsock_intern_tcp_optname);
  29. case IPPROTO_UDP:
  30. return constant_to_sym(cmsg_type, rsock_intern_udp_optname);
  31. default:
  32. return INT2NUM(cmsg_type);
  33. }
  34. }
  35. /*
  36. * call-seq:
  37. * Socket::AncillaryData.new(family, cmsg_level, cmsg_type, cmsg_data) -> ancillarydata
  38. *
  39. * _family_ should be an integer, a string or a symbol.
  40. * - Socket::AF_INET, "AF_INET", "INET", :AF_INET, :INET
  41. * - Socket::AF_UNIX, "AF_UNIX", "UNIX", :AF_UNIX, :UNIX
  42. * - etc.
  43. *
  44. * _cmsg_level_ should be an integer, a string or a symbol.
  45. * - Socket::SOL_SOCKET, "SOL_SOCKET", "SOCKET", :SOL_SOCKET and :SOCKET
  46. * - Socket::IPPROTO_IP, "IP" and :IP
  47. * - Socket::IPPROTO_IPV6, "IPV6" and :IPV6
  48. * - Socket::IPPROTO_TCP, "TCP" and :TCP
  49. * - etc.
  50. *
  51. * _cmsg_type_ should be an integer, a string or a symbol.
  52. * If a string/symbol is specified, it is interpreted depend on _cmsg_level_.
  53. * - Socket::SCM_RIGHTS, "SCM_RIGHTS", "RIGHTS", :SCM_RIGHTS, :RIGHTS for SOL_SOCKET
  54. * - Socket::IP_RECVTTL, "RECVTTL" and :RECVTTL for IPPROTO_IP
  55. * - Socket::IPV6_PKTINFO, "PKTINFO" and :PKTINFO for IPPROTO_IPV6
  56. * - etc.
  57. *
  58. * _cmsg_data_ should be a string.
  59. *
  60. * p Socket::AncillaryData.new(:INET, :TCP, :NODELAY, "")
  61. * #=> #<Socket::AncillaryData: INET TCP NODELAY "">
  62. *
  63. * p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "")
  64. * #=> #<Socket::AncillaryData: INET6 IPV6 PKTINFO "">
  65. *
  66. */
  67. static VALUE
  68. ancillary_initialize(VALUE self, VALUE vfamily, VALUE vlevel, VALUE vtype, VALUE data)
  69. {
  70. int family = rsock_family_arg(vfamily);
  71. int level = rsock_level_arg(family, vlevel);
  72. int type = rsock_cmsg_type_arg(family, level, vtype);
  73. StringValue(data);
  74. rb_ivar_set(self, rb_intern("family"), INT2NUM(family));
  75. rb_ivar_set(self, rb_intern("level"), INT2NUM(level));
  76. rb_ivar_set(self, rb_intern("type"), INT2NUM(type));
  77. rb_ivar_set(self, rb_intern("data"), data);
  78. return self;
  79. }
  80. static VALUE
  81. ancdata_new(int family, int level, int type, VALUE data)
  82. {
  83. NEWOBJ_OF(obj, struct RObject, 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 (!RB_TYPE_P(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::AncillaryData.unix_rights(STDIN, s1)
  220. * _, _, _, ctl = s2.recvmsg(:scm_rights=>true)
  221. * p ctl #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 6 7>
  222. * p ctl.unix_rights #=> [#<IO:fd 6>, #<Socket:fd 7>]
  223. * p File.identical?(STDIN, ctl.unix_rights[0]) #=> true
  224. * p File.identical?(s1, ctl.unix_rights[1]) #=> true
  225. *
  226. * # If :scm_rights=>true is not given, unix_rights returns nil
  227. * s1, s2 = UNIXSocket.pair
  228. * s1.sendmsg "stdin and a socket", 0, nil, Socket::AncillaryData.unix_rights(STDIN, s1)
  229. * _, _, _, ctl = s2.recvmsg
  230. * p ctl #=> #<Socket::AncillaryData: UNIX SOCKET RIGHTS 6 7>
  231. * p ctl.unix_rights #=> nil
  232. *
  233. */
  234. static VALUE
  235. ancillary_unix_rights(VALUE self)
  236. {
  237. int level, type;
  238. level = ancillary_level(self);
  239. type = ancillary_type(self);
  240. if (level != SOL_SOCKET || type != SCM_RIGHTS)
  241. rb_raise(rb_eTypeError, "SCM_RIGHTS ancillary data expected");
  242. return rb_attr_get(self, rb_intern("unix_rights"));
  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 (microsecond) GNU/Linux, FreeBSD, NetBSD, OpenBSD, Solaris, MacOS X
  256. * - SOL_SOCKET/SCM_TIMESTAMPNS (nanosecond) 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(0x100000000ULL);
  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_STRUCT_IN_PKTINFO_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_STRUCT_IN_PKTINFO_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. INIT_SOCKADDR((struct sockaddr *)sa_ptr, AF_INET6, sizeof(*sa_ptr));
  518. memcpy(&sa_ptr->sin6_addr, &pktinfo_ptr->ipi6_addr, sizeof(sa_ptr->sin6_addr));
  519. if (IN6_IS_ADDR_LINKLOCAL(&sa_ptr->sin6_addr))
  520. sa_ptr->sin6_scope_id = pktinfo_ptr->ipi6_ifindex;
  521. }
  522. #endif
  523. #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */
  524. /*
  525. * call-seq:
  526. * ancdata.ipv6_pktinfo => [addr, ifindex]
  527. *
  528. * Extracts addr and ifindex from IPV6_PKTINFO ancillary data.
  529. *
  530. * IPV6_PKTINFO is defined by RFC 3542.
  531. *
  532. * addr = Addrinfo.ip("::1")
  533. * ifindex = 0
  534. * ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
  535. * p ancdata.ipv6_pktinfo #=> [#<Addrinfo: ::1>, 0]
  536. *
  537. */
  538. static VALUE
  539. ancillary_ipv6_pktinfo(VALUE self)
  540. {
  541. struct in6_pktinfo pktinfo;
  542. struct sockaddr_in6 sa;
  543. VALUE v_addr;
  544. extract_ipv6_pktinfo(self, &pktinfo, &sa);
  545. v_addr = rsock_addrinfo_new((struct sockaddr *)&sa, (socklen_t)sizeof(sa), PF_INET6, 0, 0, Qnil, Qnil);
  546. return rb_ary_new3(2, v_addr, UINT2NUM(pktinfo.ipi6_ifindex));
  547. }
  548. #else
  549. #define ancillary_ipv6_pktinfo rb_f_notimplement
  550. #endif
  551. #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */
  552. /*
  553. * call-seq:
  554. * ancdata.ipv6_pktinfo_addr => addr
  555. *
  556. * Extracts addr from IPV6_PKTINFO ancillary data.
  557. *
  558. * IPV6_PKTINFO is defined by RFC 3542.
  559. *
  560. * addr = Addrinfo.ip("::1")
  561. * ifindex = 0
  562. * ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
  563. * p ancdata.ipv6_pktinfo_addr #=> #<Addrinfo: ::1>
  564. *
  565. */
  566. static VALUE
  567. ancillary_ipv6_pktinfo_addr(VALUE self)
  568. {
  569. struct in6_pktinfo pktinfo;
  570. struct sockaddr_in6 sa;
  571. extract_ipv6_pktinfo(self, &pktinfo, &sa);
  572. return rsock_addrinfo_new((struct sockaddr *)&sa, (socklen_t)sizeof(sa), PF_INET6, 0, 0, Qnil, Qnil);
  573. }
  574. #else
  575. #define ancillary_ipv6_pktinfo_addr rb_f_notimplement
  576. #endif
  577. #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) /* IPv6 RFC3542 */
  578. /*
  579. * call-seq:
  580. * ancdata.ipv6_pktinfo_ifindex => addr
  581. *
  582. * Extracts ifindex from IPV6_PKTINFO ancillary data.
  583. *
  584. * IPV6_PKTINFO is defined by RFC 3542.
  585. *
  586. * addr = Addrinfo.ip("::1")
  587. * ifindex = 0
  588. * ancdata = Socket::AncillaryData.ipv6_pktinfo(addr, ifindex)
  589. * p ancdata.ipv6_pktinfo_ifindex #=> 0
  590. *
  591. */
  592. static VALUE
  593. ancillary_ipv6_pktinfo_ifindex(VALUE self)
  594. {
  595. struct in6_pktinfo pktinfo;
  596. struct sockaddr_in6 sa;
  597. extract_ipv6_pktinfo(self, &pktinfo, &sa);
  598. return UINT2NUM(pktinfo.ipi6_ifindex);
  599. }
  600. #else
  601. #define ancillary_ipv6_pktinfo_ifindex rb_f_notimplement
  602. #endif
  603. #if defined(SOL_SOCKET) && defined(SCM_RIGHTS) /* 4.4BSD */
  604. static int
  605. anc_inspect_socket_rights(int level, int type, VALUE data, VALUE ret)
  606. {
  607. if (level == SOL_SOCKET && type == SCM_RIGHTS &&
  608. 0 < RSTRING_LEN(data) && (RSTRING_LEN(data) % sizeof(int) == 0)) {
  609. long off;
  610. for (off = 0; off < RSTRING_LEN(data); off += sizeof(int)) {
  611. int fd;
  612. memcpy((char*)&fd, RSTRING_PTR(data)+off, sizeof(int));
  613. rb_str_catf(ret, " %d", fd);
  614. }
  615. return 1;
  616. }
  617. else {
  618. return 0;
  619. }
  620. }
  621. #endif
  622. #if defined(SCM_CREDENTIALS) /* GNU/Linux */
  623. static int
  624. anc_inspect_passcred_credentials(int level, int type, VALUE data, VALUE ret)
  625. {
  626. if (level == SOL_SOCKET && type == SCM_CREDENTIALS &&
  627. RSTRING_LEN(data) == sizeof(struct ucred)) {
  628. struct ucred cred;
  629. memcpy(&cred, RSTRING_PTR(data), sizeof(struct ucred));
  630. rb_str_catf(ret, " pid=%u uid=%u gid=%u", cred.pid, cred.uid, cred.gid);
  631. rb_str_cat2(ret, " (ucred)");
  632. return 1;
  633. }
  634. else {
  635. return 0;
  636. }
  637. }
  638. #endif
  639. #if defined(SCM_CREDS)
  640. #define INSPECT_SCM_CREDS
  641. static int
  642. anc_inspect_socket_creds(int level, int type, VALUE data, VALUE ret)
  643. {
  644. if (level != SOL_SOCKET && type != SCM_CREDS)
  645. return 0;
  646. /*
  647. * FreeBSD has struct cmsgcred and struct sockcred.
  648. * They use both SOL_SOCKET/SCM_CREDS in the ancillary message.
  649. * They are not ambiguous from the view of the caller
  650. * because struct sockcred is sent if and only if the caller sets LOCAL_CREDS socket option.
  651. * But inspect method doesn't know it.
  652. * So they are ambiguous from the view of inspect.
  653. * This function distinguish them by the size of the ancillary message.
  654. * This heuristics works well except when sc_ngroups == CMGROUP_MAX.
  655. */
  656. #if defined(HAVE_TYPE_STRUCT_CMSGCRED) /* FreeBSD */
  657. if (RSTRING_LEN(data) == sizeof(struct cmsgcred)) {
  658. struct cmsgcred cred;
  659. memcpy(&cred, RSTRING_PTR(data), sizeof(struct cmsgcred));
  660. rb_str_catf(ret, " pid=%u", cred.cmcred_pid);
  661. rb_str_catf(ret, " uid=%u", cred.cmcred_uid);
  662. rb_str_catf(ret, " euid=%u", cred.cmcred_euid);
  663. rb_str_catf(ret, " gid=%u", cred.cmcred_gid);
  664. if (cred.cmcred_ngroups) {
  665. int i;
  666. const char *sep = " groups=";
  667. for (i = 0; i < cred.cmcred_ngroups; i++) {
  668. rb_str_catf(ret, "%s%u", sep, cred.cmcred_groups[i]);
  669. sep = ",";
  670. }
  671. }
  672. rb_str_cat2(ret, " (cmsgcred)");
  673. return 1;
  674. }
  675. #endif
  676. #if defined(HAVE_TYPE_STRUCT_SOCKCRED) /* FreeBSD, NetBSD */
  677. if ((size_t)RSTRING_LEN(data) >= SOCKCREDSIZE(0)) {
  678. struct sockcred cred0, *cred;
  679. memcpy(&cred0, RSTRING_PTR(data), SOCKCREDSIZE(0));
  680. if ((size_t)RSTRING_LEN(data) == SOCKCREDSIZE(cred0.sc_ngroups)) {
  681. cred = (struct sockcred *)ALLOCA_N(char, SOCKCREDSIZE(cred0.sc_ngroups));
  682. memcpy(cred, RSTRING_PTR(data), SOCKCREDSIZE(cred0.sc_ngroups));
  683. rb_str_catf(ret, " uid=%u", cred->sc_uid);
  684. rb_str_catf(ret, " euid=%u", cred->sc_euid);
  685. rb_str_catf(ret, " gid=%u", cred->sc_gid);
  686. rb_str_catf(ret, " egid=%u", cred->sc_egid);
  687. if (cred0.sc_ngroups) {
  688. int i;
  689. const char *sep = " groups=";
  690. for (i = 0; i < cred0.sc_ngroups; i++) {
  691. rb_str_catf(ret, "%s%u", sep, cred->sc_groups[i]);
  692. sep = ",";
  693. }
  694. }
  695. rb_str_cat2(ret, " (sockcred)");
  696. return 1;
  697. }
  698. }
  699. #endif
  700. return 0;
  701. }
  702. #endif
  703. #if defined(IPPROTO_IP) && defined(IP_RECVDSTADDR) /* 4.4BSD */
  704. static int
  705. anc_inspect_ip_recvdstaddr(int level, int type, VALUE data, VALUE ret)
  706. {
  707. if (level == IPPROTO_IP && type == IP_RECVDSTADDR &&
  708. RSTRING_LEN(data) == sizeof(struct in_addr)) {
  709. struct in_addr addr;
  710. char addrbuf[INET_ADDRSTRLEN];
  711. memcpy(&addr, RSTRING_PTR(data), sizeof(addr));
  712. if (inet_ntop(AF_INET, &addr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
  713. rb_str_cat2(ret, " invalid-address");
  714. else
  715. rb_str_catf(ret, " %s", addrbuf);
  716. return 1;
  717. }
  718. else {
  719. return 0;
  720. }
  721. }
  722. #endif
  723. #if defined(IPPROTO_IP) && defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST) /* GNU/Linux */
  724. static int
  725. anc_inspect_ip_pktinfo(int level, int type, VALUE data, VALUE ret)
  726. {
  727. if (level == IPPROTO_IP && type == IP_PKTINFO &&
  728. RSTRING_LEN(data) == sizeof(struct in_pktinfo)) {
  729. struct in_pktinfo pktinfo;
  730. char buf[INET_ADDRSTRLEN > IFNAMSIZ ? INET_ADDRSTRLEN : IFNAMSIZ];
  731. memcpy(&pktinfo, RSTRING_PTR(data), sizeof(pktinfo));
  732. if (inet_ntop(AF_INET, &pktinfo.ipi_addr, buf, sizeof(buf)) == NULL)
  733. rb_str_cat2(ret, " invalid-address");
  734. else
  735. rb_str_catf(ret, " %s", buf);
  736. if (if_indextoname(pktinfo.ipi_ifindex, buf) == NULL)
  737. rb_str_catf(ret, " ifindex:%d", pktinfo.ipi_ifindex);
  738. else
  739. rb_str_catf(ret, " %s", buf);
  740. if (inet_ntop(AF_INET, &pktinfo.ipi_spec_dst, buf, sizeof(buf)) == NULL)
  741. rb_str_cat2(ret, " spec_dst:invalid-address");
  742. else
  743. rb_str_catf(ret, " spec_dst:%s", buf);
  744. return 1;
  745. }
  746. else {
  747. return 0;
  748. }
  749. }
  750. #endif
  751. #if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO) && defined(HAVE_TYPE_STRUCT_IN6_PKTINFO) /* IPv6 RFC3542 */
  752. static int
  753. anc_inspect_ipv6_pktinfo(int level, int type, VALUE data, VALUE ret)
  754. {
  755. if (level == IPPROTO_IPV6 && type == IPV6_PKTINFO &&
  756. RSTRING_LEN(data) == sizeof(struct in6_pktinfo)) {
  757. struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)RSTRING_PTR(data);
  758. struct in6_addr addr;
  759. unsigned int ifindex;
  760. char addrbuf[INET6_ADDRSTRLEN], ifbuf[IFNAMSIZ];
  761. memcpy(&addr, &pktinfo->ipi6_addr, sizeof(addr));
  762. memcpy(&ifindex, &pktinfo->ipi6_ifindex, sizeof(ifindex));
  763. if (inet_ntop(AF_INET6, &addr, addrbuf, (socklen_t)sizeof(addrbuf)) == NULL)
  764. rb_str_cat2(ret, " invalid-address");
  765. else
  766. rb_str_catf(ret, " %s", addrbuf);
  767. if (if_indextoname(ifindex, ifbuf) == NULL)
  768. rb_str_catf(ret, " ifindex:%d", ifindex);
  769. else
  770. rb_str_catf(ret, " %s", ifbuf);
  771. return 1;
  772. }
  773. else {
  774. return 0;
  775. }
  776. }
  777. #endif
  778. #if defined(SCM_TIMESTAMP) /* GNU/Linux, FreeBSD, NetBSD, OpenBSD, MacOS X, Solaris */
  779. static int
  780. inspect_timeval_as_abstime(int level, int optname, VALUE data, VALUE ret)
  781. {
  782. if (RSTRING_LEN(data) == sizeof(struct timeval)) {
  783. struct timeval tv;
  784. time_t time;
  785. struct tm tm;
  786. char buf[32];
  787. memcpy((char*)&tv, RSTRING_PTR(data), sizeof(tv));
  788. time = tv.tv_sec;
  789. tm = *localtime(&time);
  790. strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
  791. rb_str_catf(ret, " %s.%06ld", buf, (long)tv.tv_usec);
  792. return 1;
  793. }
  794. else {
  795. return 0;
  796. }
  797. }
  798. #endif
  799. #if defined(SCM_TIMESTAMPNS) /* GNU/Linux */
  800. static int
  801. inspect_timespec_as_abstime(int level, int optname, VALUE data, VALUE ret)
  802. {
  803. if (RSTRING_LEN(data) == sizeof(struct timespec)) {
  804. struct timespec ts;
  805. struct tm tm;
  806. char buf[32];
  807. memcpy((char*)&ts, RSTRING_PTR(data), sizeof(ts));
  808. tm = *localtime(&ts.tv_sec);
  809. strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
  810. rb_str_catf(ret, " %s.%09ld", buf, (long)ts.tv_nsec);
  811. return 1;
  812. }
  813. else {
  814. return 0;
  815. }
  816. }
  817. #endif
  818. #if defined(SCM_BINTIME) /* FreeBSD */
  819. static int
  820. inspect_bintime_as_abstime(int level, int optname, VALUE data, VALUE ret)
  821. {
  822. if (RSTRING_LEN(data) == sizeof(struct bintime)) {
  823. struct bintime bt;
  824. struct tm tm;
  825. uint64_t frac_h, frac_l;
  826. uint64_t scale_h, scale_l;
  827. uint64_t tmp1, tmp2;
  828. uint64_t res_h, res_l;
  829. char buf[32];
  830. memcpy((char*)&bt, RSTRING_PTR(data), sizeof(bt));
  831. tm = *localtime(&bt.sec);
  832. strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
  833. /* res_h = frac * 10**19 / 2**64 */
  834. frac_h = bt.frac >> 32;
  835. frac_l = bt.frac & 0xffffffff;
  836. scale_h = 0x8ac72304; /* 0x8ac7230489e80000 == 10**19 */
  837. scale_l = 0x89e80000;
  838. res_h = frac_h * scale_h;
  839. res_l = frac_l * scale_l;
  840. tmp1 = frac_h * scale_l;
  841. res_h += tmp1 >> 32;
  842. tmp2 = res_l;
  843. res_l += tmp1 & 0xffffffff;
  844. if (res_l < tmp2) res_h++;
  845. tmp1 = frac_l * scale_h;
  846. res_h += tmp1 >> 32;
  847. tmp2 = res_l;
  848. res_l += tmp1 & 0xffffffff;
  849. if (res_l < tmp2) res_h++;
  850. rb_str_catf(ret, " %s.%019"PRIu64, buf, res_h);
  851. return 1;
  852. }
  853. else {
  854. return 0;
  855. }
  856. }
  857. #endif
  858. /*
  859. * call-seq:
  860. * ancillarydata.inspect => string
  861. *
  862. * returns a string which shows ancillarydata in human-readable form.
  863. *
  864. * p Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "").inspect
  865. * #=> "#<Socket::AncillaryData: INET6 IPV6 PKTINFO \"\">"
  866. */
  867. static VALUE
  868. ancillary_inspect(VALUE self)
  869. {
  870. VALUE ret;
  871. int family, level, type;
  872. VALUE data;
  873. ID family_id, level_id, type_id;
  874. VALUE vtype;
  875. int inspected;
  876. family = ancillary_family(self);
  877. level = ancillary_level(self);
  878. type = ancillary_type(self);
  879. data = ancillary_data(self);
  880. ret = rb_sprintf("#<%s:", rb_obj_classname(self));
  881. family_id = rsock_intern_family_noprefix(family);
  882. if (family_id)
  883. rb_str_catf(ret, " %s", rb_id2name(family_id));
  884. else
  885. rb_str_catf(ret, " family:%d", family);
  886. if (level == SOL_SOCKET) {
  887. rb_str_cat2(ret, " SOCKET");
  888. type_id = rsock_intern_scm_optname(type);
  889. if (type_id)
  890. rb_str_catf(ret, " %s", rb_id2name(type_id));
  891. else
  892. rb_str_catf(ret, " cmsg_type:%d", type);
  893. }
  894. else if (IS_IP_FAMILY(family)) {
  895. level_id = rsock_intern_iplevel(level);
  896. if (level_id)
  897. rb_str_catf(ret, " %s", rb_id2name(level_id));
  898. else
  899. rb_str_catf(ret, " cmsg_level:%d", level);
  900. vtype = ip_cmsg_type_to_sym(level, type);
  901. if (SYMBOL_P(vtype))
  902. rb_str_catf(ret, " %s", rb_id2name(SYM2ID(vtype)));
  903. else
  904. rb_str_catf(ret, " cmsg_type:%d", type);
  905. }
  906. else {
  907. rb_str_catf(ret, " cmsg_level:%d", level);
  908. rb_str_catf(ret, " cmsg_type:%d", type);
  909. }
  910. inspected = 0;
  911. if (level == SOL_SOCKET)
  912. family = AF_UNSPEC;
  913. switch (family) {
  914. case AF_UNSPEC:
  915. switch (level) {
  916. # if defined(SOL_SOCKET)
  917. case SOL_SOCKET:
  918. switch (type) {
  919. # if defined(SCM_TIMESTAMP) /* GNU/Linux, FreeBSD, NetBSD, OpenBSD, MacOS X, Solaris */
  920. case SCM_TIMESTAMP: inspected = inspect_timeval_as_abstime(level, type, data, ret); break;
  921. # endif
  922. # if defined(SCM_TIMESTAMPNS) /* GNU/Linux */
  923. case SCM_TIMESTAMPNS: inspected = inspect_timespec_as_abstime(level, type, data, ret); break;
  924. # endif
  925. # if defined(SCM_BINTIME) /* FreeBSD */
  926. case SCM_BINTIME: inspected = inspect_bintime_as_abstime(level, type, data, ret); break;
  927. # endif
  928. # if defined(SCM_RIGHTS) /* 4.4BSD */
  929. case SCM_RIGHTS: inspected = anc_inspect_socket_rights(level, type, data, ret); break;
  930. # endif
  931. # if defined(SCM_CREDENTIALS) /* GNU/Linux */
  932. case SCM_CREDENTIALS: inspected = anc_inspect_passcred_credentials(level, type, data, ret); break;
  933. # endif
  934. # if defined(INSPECT_SCM_CREDS) /* NetBSD */
  935. case SCM_CREDS: inspected = anc_inspect_socket_creds(level, type, data, ret); break;
  936. # endif
  937. }
  938. break;
  939. # endif
  940. }
  941. break;
  942. case AF_INET:
  943. #ifdef INET6
  944. case AF_INET6:
  945. #endif
  946. switch (level) {
  947. # if defined(IPPROTO_IP)
  948. case IPPROTO_IP:
  949. switch (type) {
  950. # if defined(IP_RECVDSTADDR) /* 4.4BSD */
  951. case IP_RECVDSTADDR: inspected = anc_inspect_ip_recvdstaddr(level, type, data, ret); break;
  952. # endif
  953. # if defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST) /* GNU/Linux */
  954. case IP_PKTINFO: inspected = anc_inspect_ip_pktinfo(level, type, data, ret); break;
  955. # endif
  956. }
  957. break;
  958. # endif
  959. # if defined(IPPROTO_IPV6)
  960. case IPPROTO_IPV6:
  961. switch (type) {
  962. # if defined(IPV6_PKTINFO) && defined(HAVE_TYPE_STRUCT_IN6_PKTINFO) /* RFC 3542 */
  963. case IPV6_PKTINFO: inspected = anc_inspect_ipv6_pktinfo(level, type, data, ret); break;
  964. # endif
  965. }
  966. break;
  967. # endif
  968. }
  969. break;
  970. }
  971. if (!inspected) {
  972. rb_str_cat2(ret, " ");
  973. rb_str_append(ret, rb_str_dump(data));
  974. }
  975. rb_str_cat2(ret, ">");
  976. return ret;
  977. }
  978. /*
  979. * call-seq:
  980. * ancillarydata.cmsg_is?(level, type) => true or false
  981. *
  982. * tests the level and type of _ancillarydata_.
  983. *
  984. * ancdata = Socket::AncillaryData.new(:INET6, :IPV6, :PKTINFO, "")
  985. * ancdata.cmsg_is?(Socket::IPPROTO_IPV6, Socket::IPV6_PKTINFO) #=> true
  986. * ancdata.cmsg_is?(:IPV6, :PKTINFO) #=> true
  987. * ancdata.cmsg_is?(:IP, :PKTINFO) #=> false
  988. * ancdata.cmsg_is?(:SOCKET, :RIGHTS) #=> false
  989. */
  990. static VALUE
  991. ancillary_cmsg_is_p(VALUE self, VALUE vlevel, VALUE vtype)
  992. {
  993. int family = ancillary_family(self);
  994. int level = rsock_level_arg(family, vlevel);
  995. int type = rsock_cmsg_type_arg(family, level, vtype);
  996. if (ancillary_level(self) == level &&
  997. ancillary_type(self) == type)
  998. return Qtrue;
  999. else
  1000. return Qfalse;
  1001. }
  1002. #endif
  1003. #if defined(HAVE_SENDMSG)
  1004. struct sendmsg_args_struct {
  1005. int fd;
  1006. const struct msghdr *msg;
  1007. int flags;
  1008. };
  1009. static void *
  1010. nogvl_sendmsg_func(void *ptr)
  1011. {
  1012. struct sendmsg_args_struct *args = ptr;
  1013. return (void *)(VALUE)sendmsg(args->fd, args->msg, args->flags);
  1014. }
  1015. static ssize_t
  1016. rb_sendmsg(int fd, const struct msghdr *msg, int flags)
  1017. {
  1018. struct sendmsg_args_struct args;
  1019. args.fd = fd;
  1020. args.msg = msg;
  1021. args.flags = flags;
  1022. return (ssize_t)rb_thread_call_without_gvl(nogvl_sendmsg_func, &args, RUBY_UBF_IO, 0);
  1023. }
  1024. static VALUE
  1025. bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
  1026. {
  1027. rb_io_t *fptr;
  1028. VALUE data, vflags, dest_sockaddr;
  1029. int controls_num;
  1030. struct msghdr mh;
  1031. struct iovec iov;
  1032. #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
  1033. volatile VALUE controls_str = 0;
  1034. VALUE *controls_ptr = NULL;
  1035. int family;
  1036. #endif
  1037. int flags;
  1038. ssize_t ss;
  1039. GetOpenFile(sock, fptr);
  1040. #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
  1041. family = rsock_getfamily(fptr->fd);
  1042. #endif
  1043. data = vflags = dest_sockaddr = Qnil;
  1044. if (argc == 0)
  1045. rb_raise(rb_eArgError, "mesg argument required");
  1046. data = argv[0];
  1047. if (1 < argc) vflags = argv[1];
  1048. if (2 < argc) dest_sockaddr = argv[2];
  1049. controls_num = 3 < argc ? argc - 3 : 0;
  1050. #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
  1051. if (3 < argc) { controls_ptr = &argv[3]; }
  1052. #endif
  1053. StringValue(data);
  1054. if (controls_num) {
  1055. #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
  1056. int i;
  1057. size_t last_pad = 0;
  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. #else
  1133. rb_raise(rb_eNotImpError, "control message for sendmsg is unimplemented");
  1134. #endif
  1135. }
  1136. flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
  1137. #ifdef MSG_DONTWAIT
  1138. if (nonblock)
  1139. flags |= MSG_DONTWAIT;
  1140. #endif
  1141. if (!NIL_P(dest_sockaddr))
  1142. SockAddrStringValue(dest_sockaddr);
  1143. rb_io_check_closed(fptr);
  1144. retry:
  1145. memset(&mh, 0, sizeof(mh));
  1146. if (!NIL_P(dest_sockaddr)) {
  1147. mh.msg_name = RSTRING_PTR(dest_sockaddr);
  1148. mh.msg_namelen = RSTRING_SOCKLEN(dest_sockaddr);
  1149. }
  1150. mh.msg_iovlen = 1;
  1151. mh.msg_iov = &iov;
  1152. iov.iov_base = RSTRING_PTR(data);
  1153. iov.iov_len = RSTRING_LEN(data);
  1154. #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
  1155. if (controls_str) {
  1156. mh.msg_control = RSTRING_PTR(controls_str);
  1157. mh.msg_controllen = RSTRING_SOCKLEN(controls_str);
  1158. }
  1159. else {
  1160. mh.msg_control = NULL;
  1161. mh.msg_controllen = 0;
  1162. }
  1163. #endif
  1164. rb_io_check_closed(fptr);
  1165. if (nonblock)
  1166. rb_io_set_nonblock(fptr);
  1167. ss = rb_sendmsg(fptr->fd, &mh, flags);
  1168. if (ss == -1) {
  1169. if (!nonblock && rb_io_wait_writable(fptr->fd)) {
  1170. rb_io_check_closed(fptr);
  1171. goto retry;
  1172. }
  1173. if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
  1174. rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, "sendmsg(2) would block");
  1175. rb_sys_fail("sendmsg(2)");
  1176. }
  1177. return SSIZET2NUM(ss);
  1178. }
  1179. #endif
  1180. #if defined(HAVE_SENDMSG)
  1181. /*
  1182. * call-seq:
  1183. * basicsocket.sendmsg(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent
  1184. *
  1185. * sendmsg sends a message using sendmsg(2) system call in blocking manner.
  1186. *
  1187. * _mesg_ is a string to send.
  1188. *
  1189. * _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_OOB.
  1190. *
  1191. * _dest_sockaddr_ is a destination socket address for connection-less socket.
  1192. * It should be a sockaddr such as a result of Socket.sockaddr_in.
  1193. * An Addrinfo object can be used too.
  1194. *
  1195. * _controls_ is a list of ancillary data.
  1196. * The element of _controls_ should be Socket::AncillaryData or
  1197. * 3-elements array.
  1198. * The 3-element array should contains cmsg_level, cmsg_type and data.
  1199. *
  1200. * The return value, _numbytes_sent_ is an integer which is the number of bytes sent.
  1201. *
  1202. * sendmsg can be used to implement send_io as follows:
  1203. *
  1204. * # use Socket::AncillaryData.
  1205. * ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, io.fileno)
  1206. * sock.sendmsg("a", 0, nil, ancdata)
  1207. *
  1208. * # use 3-element array.
  1209. * ancdata = [:SOCKET, :RIGHTS, [io.fileno].pack("i!")]
  1210. * sock.sendmsg("\0", 0, nil, ancdata)
  1211. *
  1212. */
  1213. VALUE
  1214. rsock_bsock_sendmsg(int argc, VALUE *argv, VALUE sock)
  1215. {
  1216. return bsock_sendmsg_internal(argc, argv, sock, 0);
  1217. }
  1218. #endif
  1219. #if defined(HAVE_SENDMSG)
  1220. /*
  1221. * call-seq:
  1222. * basicsocket.sendmsg_nonblock(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent
  1223. *
  1224. * sendmsg_nonblock sends a message using sendmsg(2) system call in non-blocking manner.
  1225. *
  1226. * It is similar to BasicSocket#sendmsg
  1227. * but the non-blocking flag is set before the system call
  1228. * and it doesn't retry the system call.
  1229. *
  1230. */
  1231. VALUE
  1232. rsock_bsock_sendmsg_nonblock(int argc, VALUE *argv, VALUE sock)
  1233. {
  1234. return bsock_sendmsg_internal(argc, argv, sock, 1);
  1235. }
  1236. #endif
  1237. #if defined(HAVE_RECVMSG)
  1238. struct recvmsg_args_struct {
  1239. int fd;
  1240. struct msghdr *msg;
  1241. int flags;
  1242. };
  1243. ssize_t
  1244. rsock_recvmsg(int socket, struct msghdr *message, int flags)
  1245. {
  1246. ssize_t ret;
  1247. socklen_t len0;
  1248. #ifdef MSG_CMSG_CLOEXEC
  1249. /* MSG_CMSG_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
  1250. flags |= MSG_CMSG_CLOEXEC;
  1251. #endif
  1252. len0 = message->msg_namelen;
  1253. ret = recvmsg(socket, message, flags);
  1254. if (ret != -1 && len0 < message->msg_namelen)
  1255. message->msg_namelen = len0;
  1256. return ret;
  1257. }
  1258. static void *
  1259. nogvl_recvmsg_func(void *ptr)
  1260. {
  1261. struct recvmsg_args_struct *args = ptr;
  1262. int flags = args->flags;
  1263. return (void *)rsock_recvmsg(args->fd, args->msg, flags);
  1264. }
  1265. static ssize_t
  1266. rb_recvmsg(int fd, struct msghdr *msg, int flags)
  1267. {
  1268. struct recvmsg_args_struct args;
  1269. args.fd = fd;
  1270. args.msg = msg;
  1271. args.flags = flags;
  1272. return (ssize_t)rb_thread_call_without_gvl(nogvl_recvmsg_func, &args, RUBY_UBF_IO, 0);
  1273. }
  1274. #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
  1275. static void
  1276. discard_cmsg(struct cmsghdr *cmh, char *msg_end, int msg_peek_p)
  1277. {
  1278. # if !defined(FD_PASSING_WORK_WITH_RECVMSG_MSG_PEEK)
  1279. /*
  1280. * FreeBSD 8.2.0, NetBSD 5 and MacOS X Snow Leopard doesn't
  1281. * allocate fds by recvmsg with MSG_PEEK.
  1282. * [ruby-dev:44189]
  1283. * http://bugs.ruby-lang.org/issues/5075
  1284. *
  1285. * Linux 2.6.38 allocate fds by recvmsg with MSG_PEEK.
  1286. */
  1287. if (msg_peek_p)
  1288. return;
  1289. # endif
  1290. if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
  1291. int *fdp = (int *)CMSG_DATA(cmh);
  1292. int *end = (int *)((char *)cmh + cmh->cmsg_len);
  1293. while ((char *)fdp + sizeof(int) <= (char *)end &&
  1294. (char *)fdp + sizeof(int) <= msg_end) {
  1295. rb_update_max_fd(*fdp);
  1296. close(*fdp);
  1297. fdp++;
  1298. }
  1299. }
  1300. }
  1301. #endif
  1302. void
  1303. rsock_discard_cmsg_resource(struct msghdr *mh, int msg_peek_p)
  1304. {
  1305. #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
  1306. struct cmsghdr *cmh;
  1307. char *msg_end;
  1308. if (mh->msg_controllen == 0)
  1309. return;
  1310. msg_end = (char *)mh->msg_control + mh->msg_controllen;
  1311. for (cmh = CMSG_FIRSTHDR(mh); cmh != NULL; cmh = CMSG_NXTHDR(mh, cmh)) {
  1312. discard_cmsg(cmh, msg_end, msg_peek_p);
  1313. }
  1314. #endif
  1315. }
  1316. #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
  1317. static void
  1318. make_io_for_unix_rights(VALUE ctl, struct cmsghdr *cmh, char *msg_end)
  1319. {
  1320. if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
  1321. int *fdp, *end;
  1322. VALUE ary = rb_ary_new();
  1323. rb_ivar_set(ctl, rb_intern("unix_rights"), ary);
  1324. fdp = (int *)CMSG_DATA(cmh);
  1325. end = (int *)((char *)cmh + cmh->cmsg_len);
  1326. while ((char *)fdp + sizeof(int) <= (char *)end &&
  1327. (char *)fdp + sizeof(int) <= msg_end) {
  1328. int fd = *fdp;
  1329. struct stat stbuf;
  1330. VALUE io;
  1331. if (fstat(fd, &stbuf) == -1)
  1332. rb_raise(rb_eSocket, "invalid fd in SCM_RIGHTS");
  1333. rb_update_max_fd(fd);
  1334. if (rsock_cmsg_cloexec_state < 0)
  1335. rsock_cmsg_cloexec_state = rsock_detect_cloexec(fd);
  1336. if (rsock_cmsg_cloexec_state == 0 || fd <= 2)
  1337. rb_maygvl_fd_fix_cloexec(fd);
  1338. if (S_ISSOCK(stbuf.st_mode))
  1339. io = rsock_init_sock(rb_obj_alloc(rb_cSocket), fd);
  1340. else
  1341. io = rb_io_fdopen(fd, O_RDWR, NULL);
  1342. ary = rb_attr_get(ctl, rb_intern("unix_rights"));
  1343. rb_ary_push(ary, io);
  1344. fdp++;
  1345. }
  1346. OBJ_FREEZE(ary);
  1347. }
  1348. }
  1349. #endif
  1350. static VALUE
  1351. bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
  1352. {
  1353. rb_io_t *fptr;
  1354. VALUE vmaxdatlen, vmaxctllen, vflags;
  1355. VALUE vopts;
  1356. int grow_buffer;
  1357. size_t maxdatlen;
  1358. int flags, orig_flags;
  1359. struct msghdr mh;
  1360. struct iovec iov;
  1361. union_sockaddr namebuf;
  1362. char datbuf0[4096], *datbuf;
  1363. VALUE dat_str = Qnil;
  1364. VALUE ret;
  1365. ssize_t ss;
  1366. int request_scm_rights;
  1367. #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
  1368. struct cmsghdr *cmh;
  1369. size_t maxctllen;
  1370. union {
  1371. char bytes[4096];
  1372. struct cmsghdr align;
  1373. } ctlbuf0;
  1374. char *ctlbuf;
  1375. VALUE ctl_str = Qnil;
  1376. int family;
  1377. int gc_done = 0;
  1378. #endif
  1379. rb_scan_args(argc, argv, "03:", &vmaxdatlen, &vflags, &vmaxctllen, &vopts);
  1380. maxdatlen = NIL_P(vmaxdatlen) ? sizeof(datbuf0) : NUM2SIZET(vmaxdatlen);
  1381. #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
  1382. maxctllen = NIL_P(vmaxctllen) ? sizeof(ctlbuf0) : NUM2SIZET(vmaxctllen);
  1383. #else
  1384. if (!NIL_P(vmaxctllen))
  1385. rb_raise(rb_eArgError, "control message not supported");
  1386. #endif
  1387. flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
  1388. #ifdef MSG_DONTWAIT
  1389. if (nonblock)
  1390. flags |= MSG_DONTWAIT;
  1391. #endif
  1392. orig_flags = flags;
  1393. grow_buffer = NIL_P(vmaxdatlen) || NIL_P(vmaxctllen);
  1394. request_scm_rights = 0;
  1395. if (!NIL_P(vopts) && RTEST(rb_hash_aref(vopts, ID2SYM(rb_intern("scm_rights")))))
  1396. request_scm_rights = 1;
  1397. #if !defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
  1398. if (request_scm_rights)
  1399. rb_raise(rb_eNotImpError, "control message for recvmsg is unimplemented");
  1400. #endif
  1401. GetOpenFile(sock, fptr);
  1402. if (rb_io_read_pending(fptr)) {
  1403. rb_raise(rb_eIOError, "recvmsg for buffered IO");
  1404. }
  1405. #if !defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
  1406. if (grow_buffer) {
  1407. int socktype;
  1408. socklen_t optlen = (socklen_t)sizeof(socktype);
  1409. if (getsockopt(fptr->fd, SOL_SOCKET, SO_TYPE, (void*)&socktype, &optlen) == -1) {
  1410. rb_sys_fail("getsockopt(SO_TYPE)");
  1411. }
  1412. if (socktype == SOCK_STREAM)
  1413. grow_buffer = 0;
  1414. }
  1415. #endif
  1416. retry:
  1417. if (maxdatlen <= sizeof(datbuf0))
  1418. datbuf = datbuf0;
  1419. else {
  1420. if (NIL_P(dat_str))
  1421. dat_str = rb_str_tmp_new(maxdatlen);
  1422. else
  1423. rb_str_resize(dat_str, maxdatlen);
  1424. datbuf = RSTRING_PTR(dat_str);
  1425. }
  1426. #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
  1427. if (maxctllen <= sizeof(ctlbuf0))
  1428. ctlbuf = ctlbuf0.bytes;
  1429. else {
  1430. if (NIL_P(ctl_str))
  1431. ctl_str = rb_str_tmp_new(maxctllen);
  1432. else
  1433. rb_str_resize(ctl_str, maxctllen);
  1434. ctlbuf = RSTRING_PTR(ctl_str);
  1435. }
  1436. #endif
  1437. memset(&mh, 0, sizeof(mh));
  1438. memset(&namebuf, 0, sizeof(namebuf));
  1439. mh.msg_name = &namebuf.addr;
  1440. mh.msg_namelen = (socklen_t)sizeof(namebuf);
  1441. mh.msg_iov = &iov;
  1442. mh.msg_iovlen = 1;
  1443. iov.iov_base = datbuf;
  1444. iov.iov_len = maxdatlen;
  1445. #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
  1446. mh.msg_control = ctlbuf;
  1447. mh.msg_controllen = (socklen_t)maxctllen;
  1448. #endif
  1449. if (grow_buffer)
  1450. flags |= MSG_PEEK;
  1451. rb_io_check_closed(fptr);
  1452. if (nonblock)
  1453. rb_io_set_nonblock(fptr);
  1454. ss = rb_recvmsg(fptr->fd, &mh, flags);
  1455. if (ss == -1) {
  1456. if (!nonblock && rb_io_wait_readable(fptr->fd)) {
  1457. rb_io_check_closed(fptr);
  1458. goto retry;
  1459. }
  1460. if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
  1461. rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "recvmsg(2) would block");
  1462. #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
  1463. if (!gc_done && (errno == EMFILE || errno == EMSGSIZE)) {
  1464. /*
  1465. * When SCM_RIGHTS hit the file descriptors limit:
  1466. * - Linux 2.6.18 causes success with MSG_CTRUNC
  1467. * - MacOS X 10.4 causes EMSGSIZE (and lost file descriptors?)
  1468. * - Solaris 11 causes EMFILE
  1469. */
  1470. gc_and_retry:
  1471. rb_gc();
  1472. gc_done = 1;
  1473. goto retry;
  1474. }
  1475. #endif
  1476. rb_sys_fail("recvmsg(2)");
  1477. }
  1478. if (grow_buffer) {
  1479. int grown = 0;
  1480. #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
  1481. if (NIL_P(vmaxdatlen) && (mh.msg_flags & MSG_TRUNC)) {
  1482. if (SIZE_MAX/2 < maxdatlen)
  1483. rb_raise(rb_eArgError, "max data length too big");
  1484. maxdatlen *= 2;
  1485. grown = 1;
  1486. }
  1487. if (NIL_P(vmaxctllen) && (mh.msg_flags & MSG_CTRUNC)) {
  1488. #define BIG_ENOUGH_SPACE 65536
  1489. if (BIG_ENOUGH_SPACE < maxctllen &&
  1490. (socklen_t)mh.msg_controllen < (socklen_t)(maxctllen - BIG_ENOUGH_SPACE)) {
  1491. /* there are big space bug truncated.
  1492. * file descriptors limit? */
  1493. if (!gc_done) {
  1494. rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
  1495. goto gc_and_retry;
  1496. }
  1497. }
  1498. else {
  1499. if (SIZE_MAX/2 < maxctllen)
  1500. rb_raise(rb_eArgError, "max control message length too big");
  1501. maxctllen *= 2;
  1502. grown = 1;
  1503. }
  1504. #undef BIG_ENOUGH_SPACE
  1505. }
  1506. #else
  1507. if (NIL_P(vmaxdatlen) && ss != -1 && ss == (ssize_t)iov.iov_len) {
  1508. if (SIZE_MAX/2 < maxdatlen)
  1509. rb_raise(rb_eArgError, "max data length too big");
  1510. maxdatlen *= 2;
  1511. grown = 1;
  1512. }
  1513. #endif
  1514. if (grown) {
  1515. rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
  1516. goto retry;
  1517. }
  1518. else {
  1519. grow_buffer = 0;
  1520. if (flags != orig_flags) {
  1521. rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
  1522. flags = orig_flags;
  1523. goto retry;
  1524. }

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