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

/ext/socket/extconf.rb

http://github.com/ruby/ruby
Ruby | 681 lines | 617 code | 32 blank | 32 comment | 76 complexity | fa2a55e90b255ef5377b385ca1a40840 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, AGPL-3.0
  1. # frozen_string_literal: false
  2. require 'mkmf'
  3. AF_INET6_SOCKET_CREATION_TEST = <<EOF
  4. #include <sys/types.h>
  5. #ifndef _WIN32
  6. #include <sys/socket.h>
  7. #endif
  8. int
  9. main(void)
  10. {
  11. socket(AF_INET6, SOCK_STREAM, 0);
  12. return 0;
  13. }
  14. EOF
  15. GETADDRINFO_GETNAMEINFO_TEST = <<EOF
  16. #include <stdlib.h>
  17. #ifndef EXIT_SUCCESS
  18. #define EXIT_SUCCESS 0
  19. #endif
  20. #ifndef EXIT_FAILURE
  21. #define EXIT_FAILURE 1
  22. #endif
  23. #ifndef AF_LOCAL
  24. #define AF_LOCAL AF_UNIX
  25. #endif
  26. int
  27. main(void)
  28. {
  29. int passive, gaierr, inet4 = 0, inet6 = 0;
  30. struct addrinfo hints, *ai, *aitop;
  31. char straddr[INET6_ADDRSTRLEN], strport[16];
  32. #ifdef _WIN32
  33. WSADATA retdata;
  34. WSAStartup(MAKEWORD(2, 0), &retdata);
  35. #endif
  36. for (passive = 0; passive <= 1; passive++) {
  37. memset(&hints, 0, sizeof(hints));
  38. hints.ai_family = AF_UNSPEC;
  39. hints.ai_protocol = IPPROTO_TCP;
  40. hints.ai_flags = passive ? AI_PASSIVE : 0;
  41. hints.ai_socktype = SOCK_STREAM;
  42. if ((gaierr = getaddrinfo(NULL, "54321", &hints, &aitop)) != 0) {
  43. (void)gai_strerror(gaierr);
  44. goto bad;
  45. }
  46. for (ai = aitop; ai; ai = ai->ai_next) {
  47. if (ai->ai_family == AF_LOCAL) continue;
  48. if (ai->ai_addr == NULL)
  49. goto bad;
  50. #if defined(_AIX)
  51. if (ai->ai_family == AF_INET6 && passive) {
  52. inet6++;
  53. continue;
  54. }
  55. ai->ai_addr->sa_len = ai->ai_addrlen;
  56. ai->ai_addr->sa_family = ai->ai_family;
  57. #endif
  58. if (ai->ai_addrlen == 0 ||
  59. getnameinfo(ai->ai_addr, ai->ai_addrlen,
  60. straddr, sizeof(straddr), strport, sizeof(strport),
  61. NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
  62. goto bad;
  63. }
  64. if (strcmp(strport, "54321") != 0) {
  65. goto bad;
  66. }
  67. switch (ai->ai_family) {
  68. case AF_INET:
  69. if (passive) {
  70. if (strcmp(straddr, "0.0.0.0") != 0) {
  71. goto bad;
  72. }
  73. } else {
  74. if (strcmp(straddr, "127.0.0.1") != 0) {
  75. goto bad;
  76. }
  77. }
  78. inet4++;
  79. break;
  80. case AF_INET6:
  81. if (passive) {
  82. if (strcmp(straddr, "::") != 0) {
  83. goto bad;
  84. }
  85. } else {
  86. if (strcmp(straddr, "::1") != 0) {
  87. goto bad;
  88. }
  89. }
  90. inet6++;
  91. break;
  92. case AF_UNSPEC:
  93. goto bad;
  94. break;
  95. default:
  96. /* another family support? */
  97. break;
  98. }
  99. }
  100. }
  101. if (!(inet4 == 0 || inet4 == 2))
  102. goto bad;
  103. if (!(inet6 == 0 || inet6 == 2))
  104. goto bad;
  105. if (aitop)
  106. freeaddrinfo(aitop);
  107. return EXIT_SUCCESS;
  108. bad:
  109. if (aitop)
  110. freeaddrinfo(aitop);
  111. return EXIT_FAILURE;
  112. }
  113. EOF
  114. RECVMSG_WITH_MSG_PEEK_ALLOCATE_FD_TEST = <<'EOF'
  115. #include <stdlib.h>
  116. #include <stdio.h>
  117. #include <string.h>
  118. #include <sys/types.h>
  119. #include <sys/stat.h>
  120. #include <sys/socket.h>
  121. #include <sys/un.h>
  122. #include <unistd.h>
  123. int main(int argc, char *argv[])
  124. {
  125. int ps[2], sv[2];
  126. int ret;
  127. ssize_t ss;
  128. int s_fd, r_fd;
  129. struct msghdr s_msg, r_msg;
  130. union {
  131. struct cmsghdr hdr;
  132. char dummy[CMSG_SPACE(sizeof(int))];
  133. } s_cmsg, r_cmsg;
  134. struct iovec s_iov, r_iov;
  135. char s_buf[1], r_buf[1];
  136. struct stat s_statbuf, r_statbuf;
  137. ret = pipe(ps);
  138. if (ret == -1) { perror("pipe"); exit(EXIT_FAILURE); }
  139. s_fd = ps[0];
  140. ret = socketpair(AF_UNIX, SOCK_DGRAM, 0, sv);
  141. if (ret == -1) { perror("socketpair"); exit(EXIT_FAILURE); }
  142. s_msg.msg_name = NULL;
  143. s_msg.msg_namelen = 0;
  144. s_msg.msg_iov = &s_iov;
  145. s_msg.msg_iovlen = 1;
  146. s_msg.msg_control = &s_cmsg;
  147. s_msg.msg_controllen = CMSG_SPACE(sizeof(int));;
  148. s_msg.msg_flags = 0;
  149. s_iov.iov_base = &s_buf;
  150. s_iov.iov_len = sizeof(s_buf);
  151. s_buf[0] = 'a';
  152. s_cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(int));
  153. s_cmsg.hdr.cmsg_level = SOL_SOCKET;
  154. s_cmsg.hdr.cmsg_type = SCM_RIGHTS;
  155. memcpy(CMSG_DATA(&s_cmsg.hdr), (char *)&s_fd, sizeof(int));
  156. ss = sendmsg(sv[0], &s_msg, 0);
  157. if (ss == -1) { perror("sendmsg"); exit(EXIT_FAILURE); }
  158. r_msg.msg_name = NULL;
  159. r_msg.msg_namelen = 0;
  160. r_msg.msg_iov = &r_iov;
  161. r_msg.msg_iovlen = 1;
  162. r_msg.msg_control = &r_cmsg;
  163. r_msg.msg_controllen = CMSG_SPACE(sizeof(int));
  164. r_msg.msg_flags = 0;
  165. r_iov.iov_base = &r_buf;
  166. r_iov.iov_len = sizeof(r_buf);
  167. r_buf[0] = '0';
  168. memset(&r_cmsg, 0xff, CMSG_SPACE(sizeof(int)));
  169. ss = recvmsg(sv[1], &r_msg, MSG_PEEK);
  170. if (ss == -1) { perror("recvmsg"); exit(EXIT_FAILURE); }
  171. if (ss != 1) {
  172. fprintf(stderr, "unexpected return value from recvmsg: %ld\n", (long)ss);
  173. exit(EXIT_FAILURE);
  174. }
  175. if (r_buf[0] != 'a') {
  176. fprintf(stderr, "unexpected return data from recvmsg: 0x%02x\n", r_buf[0]);
  177. exit(EXIT_FAILURE);
  178. }
  179. if (r_msg.msg_controllen < CMSG_LEN(sizeof(int))) {
  180. fprintf(stderr, "unexpected: r_msg.msg_controllen < CMSG_LEN(sizeof(int)) not hold: %ld\n",
  181. (long)r_msg.msg_controllen);
  182. exit(EXIT_FAILURE);
  183. }
  184. if (r_cmsg.hdr.cmsg_len < CMSG_LEN(sizeof(int))) {
  185. fprintf(stderr, "unexpected: r_cmsg.hdr.cmsg_len < CMSG_LEN(sizeof(int)) not hold: %ld\n",
  186. (long)r_cmsg.hdr.cmsg_len);
  187. exit(EXIT_FAILURE);
  188. }
  189. memcpy((char *)&r_fd, CMSG_DATA(&r_cmsg.hdr), sizeof(int));
  190. if (r_fd < 0) {
  191. fprintf(stderr, "negative r_fd: %d\n", r_fd);
  192. exit(EXIT_FAILURE);
  193. }
  194. if (r_fd == s_fd) {
  195. fprintf(stderr, "r_fd and s_fd is same: %d\n", r_fd);
  196. exit(EXIT_FAILURE);
  197. }
  198. ret = fstat(s_fd, &s_statbuf);
  199. if (ret == -1) { perror("fstat(s_fd)"); exit(EXIT_FAILURE); }
  200. ret = fstat(r_fd, &r_statbuf);
  201. if (ret == -1) { perror("fstat(r_fd)"); exit(EXIT_FAILURE); }
  202. if (s_statbuf.st_dev != r_statbuf.st_dev ||
  203. s_statbuf.st_ino != r_statbuf.st_ino) {
  204. fprintf(stderr, "dev/ino doesn't match: s_fd:%ld/%ld r_fd:%ld/%ld\n",
  205. (long)s_statbuf.st_dev, (long)s_statbuf.st_ino,
  206. (long)r_statbuf.st_dev, (long)r_statbuf.st_ino);
  207. exit(EXIT_FAILURE);
  208. }
  209. return EXIT_SUCCESS;
  210. }
  211. EOF
  212. def test_recvmsg_with_msg_peek_creates_fds(headers)
  213. case RUBY_PLATFORM
  214. when /linux/
  215. # Linux 2.6.38 allocate fds by recvmsg with MSG_PEEK.
  216. close_fds = true
  217. when /bsd|darwin/
  218. # FreeBSD 8.2.0, NetBSD 5 and MacOS X Snow Leopard doesn't
  219. # allocate fds by recvmsg with MSG_PEEK.
  220. # [ruby-dev:44189]
  221. # http://bugs.ruby-lang.org/issues/5075
  222. close_fds = false
  223. when /cygwin/
  224. # Cygwin doesn't support fd passing.
  225. # http://cygwin.com/ml/cygwin/2003-09/msg01808.html
  226. close_fds = false
  227. else
  228. close_fds = nil
  229. end
  230. if !CROSS_COMPILING
  231. if checking_for("recvmsg() with MSG_PEEK allocate file descriptors") {
  232. try_run(cpp_include(headers) + RECVMSG_WITH_MSG_PEEK_ALLOCATE_FD_TEST)
  233. }
  234. if close_fds == false
  235. warn "unexpected fd-passing recvmsg() with MSG_PEEK behavor on #{RUBY_PLATFORM}: fd allocation unexpected."
  236. elsif close_fds == nil
  237. puts "info: #{RUBY_PLATFORM} recvmsg() with MSG_PEEK allocates fds on fd-passing."
  238. end
  239. close_fds = true
  240. else
  241. if close_fds == true
  242. warn "unexpected fd-passing recvmsg() with MSG_PEEK behavor on #{RUBY_PLATFORM}: fd allocation expected."
  243. elsif close_fds == nil
  244. puts "info: #{RUBY_PLATFORM}: recvmsg() with MSG_PEEK doesn't allocates fds on fd-passing."
  245. end
  246. close_fds = false
  247. end
  248. end
  249. if close_fds == nil
  250. abort <<EOS
  251. Fatal: cannot test fd-passing recvmsg() with MSG_PEEK behavor
  252. because cross-compilation for #{RUBY_PLATFORM}.
  253. If recvmsg() with MSG_PEEK allocates fds on fd passing:
  254. --enable-close-fds-by-recvmsg-with-peek
  255. If recvmsg() with MSG_PEEK doesn't allocate fds on fd passing:
  256. --disable-close-fds-by-recvmsg-with-peek
  257. EOS
  258. end
  259. close_fds
  260. end
  261. $INCFLAGS << " -I$(topdir) -I$(top_srcdir)"
  262. if /darwin/ =~ RUBY_PLATFORM
  263. # For IPv6 extension header access on OS X 10.7+ [Bug #8517]
  264. $CFLAGS << " -D__APPLE_USE_RFC_3542"
  265. end
  266. headers = []
  267. unless $mswin or $mingw
  268. headers = %w<sys/types.h netdb.h string.h sys/socket.h netinet/in.h>
  269. end
  270. %w[
  271. sys/uio.h
  272. xti.h
  273. netinet/in_systm.h
  274. netinet/tcp.h
  275. netinet/tcp_fsm.h
  276. netinet/udp.h
  277. arpa/inet.h
  278. netpacket/packet.h
  279. net/ethernet.h
  280. sys/un.h
  281. ifaddrs.h
  282. sys/ioctl.h
  283. sys/sockio.h
  284. net/if.h
  285. sys/param.h
  286. sys/ucred.h
  287. ucred.h
  288. net/if_dl.h
  289. arpa/nameser.h
  290. resolv.h
  291. ].each {|h|
  292. if have_header(h, headers)
  293. headers << h
  294. end
  295. }
  296. have_struct_member("struct sockaddr", "sa_len", headers) # 4.4BSD
  297. have_struct_member("struct sockaddr_in", "sin_len", headers) # 4.4BSD
  298. have_struct_member("struct sockaddr_in6", "sin6_len", headers) # 4.4BSD
  299. if have_type("struct sockaddr_un", headers) # POSIX
  300. have_struct_member("struct sockaddr_un", "sun_len", headers) # 4.4BSD
  301. end
  302. have_type("struct sockaddr_dl", headers) # AF_LINK address. 4.4BSD since Net2
  303. have_type("struct sockaddr_storage", headers)
  304. have_type("struct addrinfo", headers)
  305. if have_type("socklen_t", headers)
  306. if try_static_assert("sizeof(socklen_t) >= sizeof(long)", headers)
  307. $defs << "-DRSTRING_SOCKLEN=(socklen_t)RSTRING_LEN"
  308. end
  309. end
  310. have_type("struct in_pktinfo", headers) {|src|
  311. src.sub(%r'^/\*top\*/', '\&'"\n#if defined(IPPROTO_IP) && defined(IP_PKTINFO)") <<
  312. "#else\n" << "#error\n" << ">>>>>> no in_pktinfo <<<<<<\n" << "#endif\n"
  313. } and have_struct_member("struct in_pktinfo", "ipi_spec_dst", headers)
  314. have_type("struct in6_pktinfo", headers) {|src|
  315. src.sub(%r'^/\*top\*/', '\&'"\n#if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)") <<
  316. "#else\n" << "#error\n" << ">>>>>> no in6_pktinfo <<<<<<\n" << "#endif\n"
  317. }
  318. have_type("struct sockcred", headers)
  319. have_type("struct cmsgcred", headers)
  320. have_type("struct ip_mreq", headers) # 4.4BSD
  321. have_type("struct ip_mreqn", headers) # Linux 2.4
  322. have_type("struct ipv6_mreq", headers) # RFC 3493
  323. have_msg_control = nil
  324. have_msg_control = have_struct_member('struct msghdr', 'msg_control', headers) unless $mswin or $mingw
  325. have_struct_member('struct msghdr', 'msg_accrights', headers)
  326. if have_type("struct tcp_info", headers)
  327. have_const("TCP_ESTABLISHED", headers)
  328. have_const("TCP_SYN_SENT", headers)
  329. have_const("TCP_SYN_RECV", headers)
  330. have_const("TCP_FIN_WAIT1", headers)
  331. have_const("TCP_FIN_WAIT2", headers)
  332. have_const("TCP_TIME_WAIT", headers)
  333. have_const("TCP_CLOSE", headers)
  334. have_const("TCP_CLOSE_WAIT", headers)
  335. have_const("TCP_LAST_ACK", headers)
  336. have_const("TCP_LISTEN", headers)
  337. have_const("TCP_CLOSING", headers)
  338. have_struct_member('struct tcp_info', 'tcpi_state', headers)
  339. if /solaris/ !~ RUBY_PLATFORM
  340. have_struct_member('struct tcp_info', 'tcpi_ca_state', headers)
  341. end
  342. have_struct_member('struct tcp_info', 'tcpi_retransmits', headers)
  343. have_struct_member('struct tcp_info', 'tcpi_probes', headers)
  344. have_struct_member('struct tcp_info', 'tcpi_backoff', headers)
  345. have_struct_member('struct tcp_info', 'tcpi_options', headers)
  346. have_struct_member('struct tcp_info', 'tcpi_snd_wscale', headers)
  347. have_struct_member('struct tcp_info', 'tcpi_rcv_wscale', headers)
  348. have_struct_member('struct tcp_info', 'tcpi_rto', headers)
  349. have_struct_member('struct tcp_info', 'tcpi_ato', headers)
  350. have_struct_member('struct tcp_info', 'tcpi_snd_mss', headers)
  351. have_struct_member('struct tcp_info', 'tcpi_rcv_mss', headers)
  352. have_struct_member('struct tcp_info', 'tcpi_unacked', headers)
  353. have_struct_member('struct tcp_info', 'tcpi_sacked', headers)
  354. have_struct_member('struct tcp_info', 'tcpi_lost', headers)
  355. have_struct_member('struct tcp_info', 'tcpi_retrans', headers)
  356. have_struct_member('struct tcp_info', 'tcpi_fackets', headers)
  357. have_struct_member('struct tcp_info', 'tcpi_last_data_sent', headers)
  358. have_struct_member('struct tcp_info', 'tcpi_last_ack_sent', headers)
  359. have_struct_member('struct tcp_info', 'tcpi_last_data_recv', headers)
  360. have_struct_member('struct tcp_info', 'tcpi_last_ack_recv', headers)
  361. have_struct_member('struct tcp_info', 'tcpi_pmtu', headers)
  362. have_struct_member('struct tcp_info', 'tcpi_rcv_ssthresh', headers)
  363. have_struct_member('struct tcp_info', 'tcpi_rtt', headers)
  364. have_struct_member('struct tcp_info', 'tcpi_rttvar', headers)
  365. have_struct_member('struct tcp_info', 'tcpi_snd_ssthresh', headers)
  366. have_struct_member('struct tcp_info', 'tcpi_snd_cwnd', headers)
  367. have_struct_member('struct tcp_info', 'tcpi_advmss', headers)
  368. have_struct_member('struct tcp_info', 'tcpi_reordering', headers)
  369. have_struct_member('struct tcp_info', 'tcpi_rcv_rtt', headers)
  370. have_struct_member('struct tcp_info', 'tcpi_rcv_space', headers)
  371. have_struct_member('struct tcp_info', 'tcpi_total_retrans', headers)
  372. # FreeBSD extension
  373. have_struct_member('struct tcp_info', 'tcpi_snd_wnd', headers)
  374. have_struct_member('struct tcp_info', 'tcpi_snd_bwnd', headers)
  375. have_struct_member('struct tcp_info', 'tcpi_snd_nxt', headers)
  376. have_struct_member('struct tcp_info', 'tcpi_rcv_nxt', headers)
  377. have_struct_member('struct tcp_info', 'tcpi_toe_tid', headers)
  378. have_struct_member('struct tcp_info', 'tcpi_snd_rexmitpack', headers)
  379. have_struct_member('struct tcp_info', 'tcpi_rcv_ooopack', headers)
  380. have_struct_member('struct tcp_info', 'tcpi_snd_zerowin', headers)
  381. end
  382. case RUBY_PLATFORM
  383. when /mswin(32|64)|mingw/
  384. test_func = "WSACleanup"
  385. have_library("iphlpapi")
  386. have_library("ws2_32", "WSACleanup", headers)
  387. when /cygwin/
  388. test_func = "socket(0,0,0)"
  389. when /haiku/
  390. test_func = "socket(0,0,0)"
  391. have_library("network", "socket(0,0,0)", headers)
  392. else
  393. test_func = "socket(0,0,0)"
  394. have_library("nsl", 't_open("", 0, (struct t_info *)NULL)', headers) # SunOS
  395. have_library("socket", "socket(0,0,0)", headers) # SunOS
  396. have_library("anl", 'getaddrinfo_a', headers)
  397. end
  398. if have_func(test_func, headers)
  399. have_func("sendmsg(0, (struct msghdr *)NULL, 0)", headers) # POSIX
  400. have_recvmsg = have_func("recvmsg(0, (struct msghdr *)NULL, 0)", headers) # POSIX
  401. have_func("freehostent((struct hostent *)NULL)", headers) # RFC 2553
  402. have_func("freeaddrinfo((struct addrinfo *)NULL)", headers) # RFC 2553
  403. if /haiku/ !~ RUBY_PLATFORM and
  404. have_func("gai_strerror(0)", headers) # POSIX
  405. if checking_for("gai_strerror() returns const pointer") {!try_compile(<<EOF)}
  406. #{cpp_include(headers)}
  407. #include <stdlib.h>
  408. void
  409. conftest_gai_strerror_is_const()
  410. {
  411. *gai_strerror(0) = 0;
  412. }
  413. EOF
  414. $defs << "-DGAI_STRERROR_CONST"
  415. end
  416. end
  417. have_func("accept4", headers)
  418. have_func('inet_ntop(0, (const void *)0, (char *)0, 0)', headers) or
  419. have_func("inet_ntoa(*(struct in_addr *)NULL)", headers)
  420. have_func('inet_pton(0, "", (void *)0)', headers) or
  421. have_func('inet_aton("", (struct in_addr *)0)', headers)
  422. have_func('getservbyport(0, "")', headers)
  423. have_func("getifaddrs((struct ifaddrs **)NULL)", headers)
  424. have_struct_member("struct if_data", "ifi_vhid", headers) # FreeBSD
  425. have_func("getpeereid", headers)
  426. have_func("getpeerucred(0, (ucred_t **)NULL)", headers) # SunOS
  427. have_func_decl = proc do |name, headers|
  428. if !checking_for("declaration of #{name}()") {!%w[int void].all? {|ret| try_compile(<<EOF)}}
  429. #{cpp_include(headers)}
  430. #{ret} #{name}(void);
  431. EOF
  432. $defs << "-DNEED_#{name.tr_cpp}_DECL"
  433. end
  434. end
  435. if have_func('if_indextoname(0, "")', headers)
  436. have_func_decl["if_indextoname"]
  437. end
  438. if have_func('if_nametoindex("")', headers)
  439. have_func_decl["if_nametoindex"]
  440. end
  441. have_func("hsterror", headers)
  442. have_func('getipnodebyname("", 0, 0, (int *)0)', headers) # RFC 2553
  443. have_func('gethostbyname2("", 0)', headers) # RFC 2133
  444. have_func("socketpair(0, 0, 0, 0)", headers)
  445. unless have_func("gethostname((char *)0, 0)", headers)
  446. have_func("uname((struct utsname *)NULL)", headers)
  447. end
  448. have_func("getaddrinfo_a", headers)
  449. ipv6 = false
  450. default_ipv6 = /haiku/ !~ RUBY_PLATFORM
  451. if enable_config("ipv6", default_ipv6)
  452. if checking_for("ipv6") {try_link(AF_INET6_SOCKET_CREATION_TEST)}
  453. $defs << "-DENABLE_IPV6" << "-DINET6"
  454. ipv6 = true
  455. end
  456. end
  457. if ipv6
  458. if $mingw
  459. $CPPFLAGS << " -D_WIN32_WINNT=0x501" unless $CPPFLAGS.include?("_WIN32_WINNT")
  460. end
  461. ipv6lib = nil
  462. class << (fmt = "unknown")
  463. def %(s) s || self end
  464. end
  465. idirs, ldirs = dir_config("inet6", %w[/usr/inet6 /usr/local/v6].find {|d| File.directory?(d)})
  466. checking_for("ipv6 type", fmt) do
  467. if have_macro("IPV6_INRIA_VERSION", "netinet/in.h")
  468. "inria"
  469. elsif have_macro("__KAME__", "netinet/in.h")
  470. have_library(ipv6lib = "inet6")
  471. "kame"
  472. elsif have_macro("_TOSHIBA_INET6", "sys/param.h")
  473. have_library(ipv6lib = "inet6") and "toshiba"
  474. elsif have_macro("__V6D__", "sys/v6config.h")
  475. have_library(ipv6lib = "v6") and "v6d"
  476. elsif have_macro("_ZETA_MINAMI_INET6", "sys/param.h")
  477. have_library(ipv6lib = "inet6") and "zeta"
  478. elsif have_library("inet6")
  479. "inet6"
  480. end
  481. end or not ipv6lib or abort <<EOS
  482. Fatal: no #{ipv6lib} library found. cannot continue.
  483. You need to fetch lib#{ipv6lib}.a from appropriate
  484. ipv6 kit and compile beforehand.
  485. EOS
  486. end
  487. if !have_macro("IPPROTO_IPV6", headers) && have_const("IPPROTO_IPV6", headers)
  488. IO.read(File.join(File.dirname(__FILE__), "mkconstants.rb")).sub(/\A.*^__END__$/m, '').split(/\r?\n/).grep(/\AIPPROTO_\w*/){$&}.each {|name|
  489. have_const(name, headers) unless $defs.include?("-DHAVE_CONST_#{name.upcase}")
  490. }
  491. end
  492. if enable_config("close-fds-by-recvmsg-with-peek") {
  493. have_msg_control && have_recvmsg &&
  494. have_const('AF_UNIX', headers) && have_const('SCM_RIGHTS', headers) &&
  495. test_recvmsg_with_msg_peek_creates_fds(headers)
  496. }
  497. $defs << "-DFD_PASSING_WORK_WITH_RECVMSG_MSG_PEEK"
  498. end
  499. case enable_config("wide-getaddrinfo")
  500. when true
  501. getaddr_info_ok = :wide
  502. when nil, false
  503. getaddr_info_ok = (:wide if getaddr_info_ok.nil?)
  504. if have_func("getnameinfo", headers) and have_func("getaddrinfo", headers)
  505. if CROSS_COMPILING ||
  506. $mingw || $mswin ||
  507. checking_for("system getaddrinfo working") {
  508. try_run(cpp_include(headers) + GETADDRINFO_GETNAMEINFO_TEST)
  509. }
  510. getaddr_info_ok = :os
  511. end
  512. end
  513. else
  514. raise "unexpected enable_config() value"
  515. end
  516. if ipv6 and not getaddr_info_ok
  517. abort <<EOS
  518. Fatal: --enable-ipv6 is specified, and your OS seems to support IPv6 feature.
  519. But your getaddrinfo() and getnameinfo() are appeared to be broken. Sorry,
  520. you cannot compile IPv6 socket classes with broken these functions.
  521. You can try --enable-wide-getaddrinfo.
  522. EOS
  523. end
  524. case with_config("lookup-order-hack", "UNSPEC")
  525. when "INET"
  526. $defs << "-DLOOKUP_ORDER_HACK_INET"
  527. when "INET6"
  528. $defs << "-DLOOKUP_ORDER_HACK_INET6"
  529. when "UNSPEC"
  530. # nothing special
  531. else
  532. abort <<EOS
  533. Fatal: invalid value for --with-lookup-order-hack (expected INET, INET6 or UNSPEC)
  534. EOS
  535. end
  536. $objs = [
  537. "init.#{$OBJEXT}",
  538. "constants.#{$OBJEXT}",
  539. "basicsocket.#{$OBJEXT}",
  540. "socket.#{$OBJEXT}",
  541. "ipsocket.#{$OBJEXT}",
  542. "tcpsocket.#{$OBJEXT}",
  543. "tcpserver.#{$OBJEXT}",
  544. "sockssocket.#{$OBJEXT}",
  545. "udpsocket.#{$OBJEXT}",
  546. "unixsocket.#{$OBJEXT}",
  547. "unixserver.#{$OBJEXT}",
  548. "option.#{$OBJEXT}",
  549. "ancdata.#{$OBJEXT}",
  550. "raddrinfo.#{$OBJEXT}",
  551. "ifaddr.#{$OBJEXT}"
  552. ]
  553. if getaddr_info_ok == :wide
  554. if !have_type("struct in6_addr", headers) and have_type("struct in_addr6", headers)
  555. $defs.pop(2)
  556. $defs << "-Din_addr6=in6_addr"
  557. end
  558. if have_struct_member("struct in6_addr", "s6_addr8", headers)
  559. $defs[-1] = "-Ds6_addr=s6_addr8"
  560. end
  561. if ipv6 == "kame" && have_struct_member("struct in6_addr", "s6_addr32", headers)
  562. $defs[-1] = "-DFAITH"
  563. end
  564. $CPPFLAGS="-I. "+$CPPFLAGS
  565. $objs += ["getaddrinfo.#{$OBJEXT}"]
  566. $objs += ["getnameinfo.#{$OBJEXT}"]
  567. $defs << "-DGETADDRINFO_EMU"
  568. end
  569. # workaround for recent Windows SDK
  570. $defs << "-DIPPROTO_IPV6=IPPROTO_IPV6" if $defs.include?("-DHAVE_CONST_IPPROTO_IPV6") && !have_macro("IPPROTO_IPV6")
  571. $distcleanfiles << "constants.h" << "constdefs.*"
  572. if enable_config("socks", ENV["SOCKS_SERVER"])
  573. if have_library("socks5", "SOCKSinit")
  574. $defs << "-DSOCKS5" << "-DSOCKS"
  575. elsif have_library("socksd", "Rconnect") || have_library("socks", "Rconnect")
  576. $defs << "-DSOCKS"
  577. end
  578. end
  579. hdr = "netinet6/in6.h"
  580. if /darwin/ =~ RUBY_PLATFORM and !try_compile(<<"SRC", nil, :werror=>true)
  581. #include <netinet/in.h>
  582. int t(struct in6_addr *addr) {return IN6_IS_ADDR_UNSPECIFIED(addr);}
  583. SRC
  584. print "fixing apple's netinet6/in6.h ..."; $stdout.flush
  585. in6 = File.read("/usr/include/#{hdr}")
  586. if in6.gsub!(/\*\(const\s+__uint32_t\s+\*\)\(const\s+void\s+\*\)\(&(\(\w+\))->s6_addr\[(\d+)\]\)/) do
  587. i, r = $2.to_i.divmod(4)
  588. if r.zero?
  589. "#$1->__u6_addr.__u6_addr32[#{i}]"
  590. else
  591. $&
  592. end
  593. end
  594. FileUtils.mkdir_p(File.dirname(hdr))
  595. open(hdr, "w") {|f| f.write(in6)}
  596. $distcleanfiles << hdr
  597. $distcleandirs << File.dirname(hdr)
  598. puts "done"
  599. else
  600. puts "not needed"
  601. end
  602. end
  603. create_makefile("socket")
  604. end