PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/ext/socket/extconf.rb

https://github.com/nazy/ruby
Ruby | 363 lines | 302 code | 36 blank | 25 comment | 71 complexity | a1ddb836149c5f947598937c4ca6c8f6 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, AGPL-3.0, 0BSD, Unlicense
  1. require 'mkmf'
  2. case RUBY_PLATFORM
  3. when /(ms|bcc)win32|mingw/
  4. test_func = "WSACleanup"
  5. have_library("ws2_32", "WSACleanup")
  6. $defs << "-DHAVE_SOCKETPAIR"
  7. when /cygwin/
  8. test_func = "socket"
  9. when /beos/
  10. test_func = "socket"
  11. have_library("net", "socket")
  12. when /haiku/
  13. test_func = "socket"
  14. have_library("network", "socket")
  15. when /i386-os2_emx/
  16. test_func = "socket"
  17. have_library("socket", "socket")
  18. else
  19. test_func = "socket"
  20. have_library("nsl", "t_open")
  21. have_library("socket", "socket")
  22. end
  23. unless $mswin or $bccwin or $mingw
  24. headers = %w<sys/types.h netdb.h string.h sys/socket.h netinet/in.h>
  25. end
  26. if /solaris/ =~ RUBY_PLATFORM and !try_compile("")
  27. # bug of gcc 3.0 on Solaris 8 ?
  28. headers << "sys/feature_tests.h"
  29. end
  30. if have_header("arpa/inet.h")
  31. headers << "arpa/inet.h"
  32. end
  33. ipv6 = false
  34. default_ipv6 = /mswin|cygwin|beos|haiku/ !~ RUBY_PLATFORM
  35. if enable_config("ipv6", default_ipv6)
  36. if checking_for("ipv6") {try_link(<<EOF)}
  37. #include <sys/types.h>
  38. #ifndef _WIN32
  39. #include <sys/socket.h>
  40. #endif
  41. int
  42. main()
  43. {
  44. socket(AF_INET6, SOCK_STREAM, 0);
  45. }
  46. EOF
  47. $defs << "-DENABLE_IPV6" << "-DINET6"
  48. ipv6 = true
  49. end
  50. end
  51. if ipv6
  52. if $mingw
  53. $CPPFLAGS << " -D_WIN32_WINNT=0x501"
  54. end
  55. ipv6lib = nil
  56. class << (fmt = "unknown")
  57. def %(s) s || self end
  58. end
  59. idirs, ldirs = dir_config("inet6", %w[/usr/inet6 /usr/local/v6].find {|d| File.directory?(d)})
  60. checking_for("ipv6 type", fmt) do
  61. if have_macro("IPV6_INRIA_VERSION", "netinet/in.h")
  62. "inria"
  63. elsif have_macro("__KAME__", "netinet/in.h")
  64. have_library(ipv6lib = "inet6")
  65. "kame"
  66. elsif have_macro("_TOSHIBA_INET6", "sys/param.h")
  67. have_library(ipv6lib = "inet6") and "toshiba"
  68. elsif have_macro("__V6D__", "sys/v6config.h")
  69. have_library(ipv6lib = "v6") and "v6d"
  70. elsif have_macro("_ZETA_MINAMI_INET6", "sys/param.h")
  71. have_library(ipv6lib = "inet6") and "zeta"
  72. elsif ipv6lib = with_config("ipv6-lib")
  73. warn <<EOS
  74. --with-ipv6-lib and --with-ipv6-libdir option will be obsolete, use
  75. --with-inet6lib and --with-inet6-{include,lib} options instead.
  76. EOS
  77. find_library(ipv6lib, nil, with_config("ipv6-libdir", ldirs)) and
  78. ipv6lib
  79. elsif have_library("inet6")
  80. "inet6"
  81. end
  82. end or not ipv6lib or abort <<EOS
  83. Fatal: no #{ipv6lib} library found. cannot continue.
  84. You need to fetch lib#{ipv6lib}.a from appropriate
  85. ipv6 kit and compile beforehand.
  86. EOS
  87. end
  88. if have_struct_member("struct sockaddr_in", "sin_len", headers)
  89. $defs[-1] = "-DHAVE_SIN_LEN"
  90. end
  91. # doug's fix, NOW add -Dss_family... only if required!
  92. doug = proc {have_struct_member("struct sockaddr_storage", "ss_family", headers)}
  93. if (doug[] or
  94. with_cppflags($CPPFLAGS + " -Dss_family=__ss_family", &doug))
  95. $defs[-1] = "-DHAVE_SOCKADDR_STORAGE"
  96. doug = proc {have_struct_member("struct sockaddr_storage", "ss_len", headers)}
  97. doug[] or with_cppflags($CPPFLAGS + " -Dss_len=__ss_len", &doug)
  98. end
  99. if have_struct_member("struct sockaddr", "sa_len", headers)
  100. $defs[-1] = "-DHAVE_SA_LEN "
  101. end
  102. have_header("netinet/tcp.h") if /cygwin/ !~ RUBY_PLATFORM # for cygwin 1.1.5
  103. have_header("netinet/udp.h")
  104. if !have_macro("IPPROTO_IPV6", headers) && have_const("IPPROTO_IPV6", headers)
  105. IO.read(File.join(File.dirname(__FILE__), "mkconstants.rb")).sub(/\A.*^__END__$/m, '').split(/\r?\n/).grep(/\AIPPROTO_\w*/){$&}.each {|name|
  106. have_const(name, headers) unless $defs.include?("-DHAVE_CONST_#{name.upcase}")
  107. }
  108. end
  109. if have_func("sendmsg") | have_func("recvmsg")
  110. have_struct_member('struct msghdr', 'msg_control', ['sys/types.h', 'sys/socket.h'])
  111. have_struct_member('struct msghdr', 'msg_accrights', ['sys/types.h', 'sys/socket.h'])
  112. end
  113. getaddr_info_ok = (enable_config("wide-getaddrinfo") && :wide) ||
  114. (checking_for("wide getaddrinfo") {try_run(<<EOF)} && :os)
  115. #{cpp_include(headers)}
  116. #include <stdlib.h>
  117. #ifndef EXIT_SUCCESS
  118. #define EXIT_SUCCESS 0
  119. #endif
  120. #ifndef EXIT_FAILURE
  121. #define EXIT_FAILURE 1
  122. #endif
  123. #ifndef AF_LOCAL
  124. #define AF_LOCAL AF_UNIX
  125. #endif
  126. int
  127. main()
  128. {
  129. int passive, gaierr, inet4 = 0, inet6 = 0;
  130. struct addrinfo hints, *ai, *aitop;
  131. char straddr[INET6_ADDRSTRLEN], strport[16];
  132. #ifdef _WIN32
  133. WSADATA retdata;
  134. WSAStartup(MAKEWORD(2, 0), &retdata);
  135. #endif
  136. for (passive = 0; passive <= 1; passive++) {
  137. memset(&hints, 0, sizeof(hints));
  138. hints.ai_family = AF_UNSPEC;
  139. hints.ai_protocol = IPPROTO_TCP;
  140. hints.ai_flags = passive ? AI_PASSIVE : 0;
  141. hints.ai_socktype = SOCK_STREAM;
  142. if ((gaierr = getaddrinfo(NULL, "54321", &hints, &aitop)) != 0) {
  143. (void)gai_strerror(gaierr);
  144. goto bad;
  145. }
  146. for (ai = aitop; ai; ai = ai->ai_next) {
  147. if (ai->ai_family == AF_LOCAL) continue;
  148. if (ai->ai_addr == NULL)
  149. goto bad;
  150. #if defined(_AIX)
  151. if (ai->ai_family == AF_INET6 && passive) {
  152. inet6++;
  153. continue;
  154. }
  155. ai->ai_addr->sa_len = ai->ai_addrlen;
  156. ai->ai_addr->sa_family = ai->ai_family;
  157. #endif
  158. if (ai->ai_addrlen == 0 ||
  159. getnameinfo(ai->ai_addr, ai->ai_addrlen,
  160. straddr, sizeof(straddr), strport, sizeof(strport),
  161. NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
  162. goto bad;
  163. }
  164. if (strcmp(strport, "54321") != 0) {
  165. goto bad;
  166. }
  167. switch (ai->ai_family) {
  168. case AF_INET:
  169. if (passive) {
  170. if (strcmp(straddr, "0.0.0.0") != 0) {
  171. goto bad;
  172. }
  173. } else {
  174. if (strcmp(straddr, "127.0.0.1") != 0) {
  175. goto bad;
  176. }
  177. }
  178. inet4++;
  179. break;
  180. case AF_INET6:
  181. if (passive) {
  182. if (strcmp(straddr, "::") != 0) {
  183. goto bad;
  184. }
  185. } else {
  186. if (strcmp(straddr, "::1") != 0) {
  187. goto bad;
  188. }
  189. }
  190. inet6++;
  191. break;
  192. case AF_UNSPEC:
  193. goto bad;
  194. break;
  195. default:
  196. /* another family support? */
  197. break;
  198. }
  199. }
  200. }
  201. if (!(inet4 == 0 || inet4 == 2))
  202. goto bad;
  203. if (!(inet6 == 0 || inet6 == 2))
  204. goto bad;
  205. if (aitop)
  206. freeaddrinfo(aitop);
  207. exit(EXIT_SUCCESS);
  208. bad:
  209. if (aitop)
  210. freeaddrinfo(aitop);
  211. exit(EXIT_FAILURE);
  212. }
  213. EOF
  214. if ipv6 and not getaddr_info_ok
  215. abort <<EOS
  216. Fatal: --enable-ipv6 is specified, and your OS seems to support IPv6 feature.
  217. But your getaddrinfo() and getnameinfo() are appeared to be broken. Sorry,
  218. you cannot compile IPv6 socket classes with broken these functions.
  219. You can try --enable-wide-getaddrinfo.
  220. EOS
  221. end
  222. case with_config("lookup-order-hack", "UNSPEC")
  223. when "INET"
  224. $defs << "-DLOOKUP_ORDER_HACK_INET"
  225. when "INET6"
  226. $defs << "-DLOOKUP_ORDER_HACK_INET6"
  227. when "UNSPEC"
  228. # nothing special
  229. else
  230. abort <<EOS
  231. Fatal: invalid value for --with-lookup-order-hack (expected INET, INET6 or UNSPEC)
  232. EOS
  233. end
  234. have_type("struct addrinfo", headers)
  235. have_func("freehostent")
  236. have_func("freeaddrinfo")
  237. if /haiku/ !~ RUBY_PLATFORM and have_func("gai_strerror")
  238. if checking_for("gai_strerror() returns const pointer") {!try_compile(<<EOF)}
  239. #{cpp_include(headers)}
  240. #include <stdlib.h>
  241. void
  242. conftest_gai_strerror_is_const()
  243. {
  244. *gai_strerror(0) = 0;
  245. }
  246. EOF
  247. $defs << "-DGAI_STRERROR_CONST"
  248. end
  249. end
  250. $objs = [
  251. "init.#{$OBJEXT}",
  252. "constants.#{$OBJEXT}",
  253. "basicsocket.#{$OBJEXT}",
  254. "socket.#{$OBJEXT}",
  255. "ipsocket.#{$OBJEXT}",
  256. "tcpsocket.#{$OBJEXT}",
  257. "tcpserver.#{$OBJEXT}",
  258. "sockssocket.#{$OBJEXT}",
  259. "udpsocket.#{$OBJEXT}",
  260. "unixsocket.#{$OBJEXT}",
  261. "unixserver.#{$OBJEXT}",
  262. "option.#{$OBJEXT}",
  263. "ancdata.#{$OBJEXT}",
  264. "raddrinfo.#{$OBJEXT}"
  265. ]
  266. if getaddr_info_ok == :wide or
  267. !have_func("getnameinfo", headers) or !have_func("getaddrinfo", headers)
  268. if have_struct_member("struct in6_addr", "s6_addr8", headers)
  269. $defs[-1] = "s6_addr=s6_addr8"
  270. end
  271. if ipv6 == "kame" && have_struct_member("struct in6_addr", "s6_addr32", headers)
  272. $defs[-1] = "-DFAITH"
  273. end
  274. $CPPFLAGS="-I. "+$CPPFLAGS
  275. $objs += ["getaddrinfo.#{$OBJEXT}"]
  276. $objs += ["getnameinfo.#{$OBJEXT}"]
  277. $defs << "-DGETADDRINFO_EMU"
  278. have_func("inet_ntop") or have_func("inet_ntoa")
  279. have_func("inet_pton") or have_func("inet_aton")
  280. have_func("getservbyport")
  281. have_header("arpa/nameser.h")
  282. have_header("resolv.h")
  283. end
  284. have_header("ifaddrs.h")
  285. have_func("getifaddrs")
  286. have_header("sys/ioctl.h")
  287. have_header("sys/sockio.h")
  288. have_header("net/if.h", headers)
  289. have_header("sys/param.h", headers)
  290. have_header("sys/ucred.h", headers)
  291. unless have_type("socklen_t", headers)
  292. $defs << "-Dsocklen_t=int"
  293. end
  294. have_header("sys/un.h")
  295. have_header("sys/uio.h")
  296. have_type("struct in_pktinfo", headers) {|src|
  297. src.sub(%r'^/\*top\*/', '\1'"\n#if defined(IPPROTO_IP) && defined(IP_PKTINFO)") <<
  298. "#else\n" << "#error\n" << ">>>>>> no in_pktinfo <<<<<<\n" << "#endif\n"
  299. } and have_struct_member("struct in_pktinfo", "ipi_spec_dst", headers)
  300. have_type("struct in6_pktinfo", headers) {|src|
  301. src.sub(%r'^/\*top\*/', '\1'"\n#if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)") <<
  302. "#else\n" << "#error\n" << ">>>>>> no in6_pktinfo <<<<<<\n" << "#endif\n"
  303. }
  304. have_type("struct sockcred", headers)
  305. have_type("struct cmsgcred", headers)
  306. have_func("getpeereid")
  307. have_header("ucred.h", headers)
  308. have_func("getpeerucred")
  309. # workaround for recent Windows SDK
  310. $defs << "-DIPPROTO_IPV6=IPPROTO_IPV6" if $defs.include?("-DHAVE_CONST_IPPROTO_IPV6") && !have_macro("IPPROTO_IPV6")
  311. $distcleanfiles << "constants.h" << "constdefs.*"
  312. if have_func(test_func)
  313. have_func("hsterror")
  314. have_func("getipnodebyname") or have_func("gethostbyname2")
  315. have_func("socketpair") unless $defs.include?("-DHAVE_SOCKETPAIR")
  316. unless have_func("gethostname")
  317. have_func("uname")
  318. end
  319. if enable_config("socks", ENV["SOCKS_SERVER"])
  320. if have_library("socks5", "SOCKSinit")
  321. $defs << "-DSOCKS5" << "-DSOCKS"
  322. elsif have_library("socks", "Rconnect")
  323. $defs << "-DSOCKS"
  324. end
  325. end
  326. create_makefile("socket")
  327. end