PageRenderTime 234ms CodeModel.GetById 79ms app.highlight 83ms RepoModel.GetById 66ms app.codeStats 0ms

/components/ruby-2.1.0/ext/socket/extconf.rb

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