summaryrefslogtreecommitdiff
path: root/ext/socket/extconf.rb
diff options
context:
space:
mode:
Diffstat (limited to 'ext/socket/extconf.rb')
-rw-r--r--ext/socket/extconf.rb881
1 files changed, 596 insertions, 285 deletions
diff --git a/ext/socket/extconf.rb b/ext/socket/extconf.rb
index 4f7b49407f..a814e21c3a 100644
--- a/ext/socket/extconf.rb
+++ b/ext/socket/extconf.rb
@@ -1,221 +1,44 @@
+# frozen_string_literal: false
require 'mkmf'
-case RUBY_PLATFORM
-when /bccwin32/
- test_func = "WSACleanup"
- have_library("ws2_32", "WSACleanup")
- have_func("closesocket")
-when /mswin32|mingw/
- test_func = "WSACleanup"
- have_library("wsock32", "WSACleanup")
- have_func("closesocket")
-when /cygwin/
- test_func = "socket"
-when /beos/
- test_func = "socket"
- have_library("net", "socket")
- have_func("closesocket")
-when /i386-os2_emx/
- test_func = "socket"
- have_library("socket", "socket")
-else
- test_func = "socket"
- have_library("nsl", "t_open")
- have_library("socket", "socket")
-end
-
-$ipv6 = false
-default_ipv6 = /cygwin/ !~ RUBY_PLATFORM
-if enable_config("ipv6", default_ipv6)
- if try_link(<<EOF)
+AF_INET6_SOCKET_CREATION_TEST = <<EOF
#include <sys/types.h>
+#ifndef _WIN32
#include <sys/socket.h>
-main()
-{
- socket(AF_INET6, SOCK_STREAM, 0);
-}
-EOF
- $CFLAGS+=" -DENABLE_IPV6"
- $ipv6 = true
- end
-end
-
-$ipv6type = nil
-$ipv6lib = nil
-$ipv6libdir = nil
-$ipv6trylibc = nil
-if $ipv6
- if macro_defined?("IPV6_INRIA_VERSION", <<EOF)
-#include <netinet/in.h>
-EOF
- $ipv6type = "inria"
- $CFLAGS="-DINET6 "+$CFLAGS
- elsif macro_defined?("__KAME__", <<EOF)
-#include <netinet/in.h>
-EOF
- $ipv6type = "kame"
- $ipv6lib="inet6"
- $ipv6libdir="/usr/local/v6/lib"
- $ipv6trylibc=true
- $CFLAGS="-DINET6 "+$CFLAGS
- elsif File.directory? "/usr/inet6"
- $ipv6type = "linux"
- $ipv6lib="inet6"
- $ipv6libdir="/usr/inet6/lib"
- $CFLAGS="-DINET6 -I/usr/inet6/include "+$CFLAGS
- elsif macro_defined?("_TOSHIBA_INET6", <<EOF)
-#include <sys/param.h>
-EOF
- $ipv6type = "toshiba"
- $ipv6lib="inet6"
- $ipv6libdir="/usr/local/v6/lib"
- $CFLAGS="-DINET6 "+$CFLAGS
- elsif macro_defined?("__V6D__", <<EOF)
-#include </usr/local/v6/include/sys/v6config.h>
-EOF
- $ipv6type = "v6d"
- $ipv6lib="v6"
- $ipv6libdir="/usr/local/v6/lib"
- $CFLAGS="-DINET6 -I/usr/local/v6/include "+$CFLAGS
- elsif macro_defined?("_ZETA_MINAMI_INET6", <<EOF)
-#include <sys/param.h>
-EOF
- $ipv6type = "zeta"
- $ipv6lib="inet6"
- $ipv6libdir="/usr/local/v6/lib"
- $CFLAGS="-DINET6 "+$CFLAGS
- else
- $ipv6lib=with_config("ipv6-lib", nil)
- $ipv6libdir=with_config("ipv6-libdir", nil)
- $CFLAGS="-DINET6 "+$CFLAGS
- end
-
- if $ipv6lib
- if File.directory? $ipv6libdir and File.exist? "#{$ipv6libdir}/lib#{$ipv6lib}.a"
- $LOCAL_LIBS = " -L#$ipv6libdir -l#$ipv6lib"
- elsif !$ipv6trylibc
- print <<EOS
-
-Fatal: no #$ipv6lib library found. cannot continue.
-You need to fetch lib#{$ipv6lib}.a from appropriate
-ipv6 kit and compile beforehand.
-EOS
- exit
- end
- end
-end
-
- if try_link(<<EOF)
-#ifdef _WIN32
-# include <windows.h>
-# include <winsock.h>
-#else
-# include <sys/types.h>
-# include <netdb.h>
-# include <string.h>
-# include <sys/socket.h>
-# include <netinet/in.h>
#endif
int
-main()
+main(void)
{
- struct sockaddr_in sin;
-
- sin.sin_len;
- return 0;
+ socket(AF_INET6, SOCK_STREAM, 0);
+ return 0;
}
EOF
- $CFLAGS="-DHAVE_SIN_LEN "+$CFLAGS
-end
- if try_link(<<EOF)
-#ifdef _WIN32
-# include <windows.h>
-# include <winsock.h>
-#else
-# include <sys/types.h>
-# include <netdb.h>
-# include <string.h>
-# include <sys/socket.h>
-#endif
-int
-main()
-{
- struct sockaddr_storage ss;
+GETADDRINFO_GETNAMEINFO_TEST = <<EOF
+#include <stdlib.h>
- ss.ss_family;
- return 0;
-}
-EOF
- $CFLAGS="-DHAVE_SOCKADDR_STORAGE "+$CFLAGS
-else # doug's fix, NOW add -Dss_family... only if required!
-$CPPFLAGS += " -Dss_family=__ss_family -Dss_len=__ss_len"
- if try_link(<<EOF)
-#ifdef _WIN32
-# include <windows.h>
-# include <winsock.h>
-#else
-# include <sys/types.h>
-# include <netdb.h>
-# include <string.h>
-# include <sys/socket.h>
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS 0
+#endif
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
#endif
-int
-main()
-{
- struct sockaddr_storage ss;
-
- ss.ss_family;
- return 0;
-}
-EOF
- $CFLAGS="-DHAVE_SOCKADDR_STORAGE "+$CFLAGS
-end
-end
-
- if try_link(<<EOF)
-#include <sys/types.h>
-#include <netdb.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-int
-main()
-{
- struct sockaddr sa;
-
- sa.sa_len;
- return 0;
-}
-EOF
- $CFLAGS="-DHAVE_SA_LEN "+$CFLAGS
-end
-
-have_header("netinet/tcp.h") if not /cygwin/ =~ RUBY_PLATFORM # for cygwin 1.1.5
-have_header("netinet/udp.h")
-
-if have_func("sendmsg") | have_func("recvmsg")
- have_struct_member('struct msghdr', 'msg_control', ['sys/types.h', 'sys/socket.h'])
- have_struct_member('struct msghdr', 'msg_accrights', ['sys/types.h', 'sys/socket.h'])
-end
-
-$getaddr_info_ok = false
-if !enable_config("wide-getaddrinfo", false) and try_run(<<EOF)
-#include <sys/types.h>
-#include <netdb.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
#ifndef AF_LOCAL
#define AF_LOCAL AF_UNIX
#endif
-main()
+int
+main(void)
{
int passive, gaierr, inet4 = 0, inet6 = 0;
struct addrinfo hints, *ai, *aitop;
char straddr[INET6_ADDRSTRLEN], strport[16];
+#ifdef _WIN32
+ WSADATA retdata;
+
+ WSAStartup(MAKEWORD(2, 0), &retdata);
+#endif
for (passive = 0; passive <= 1; passive++) {
memset(&hints, 0, sizeof(hints));
@@ -229,8 +52,17 @@ main()
}
for (ai = aitop; ai; ai = ai->ai_next) {
if (ai->ai_family == AF_LOCAL) continue;
- if (ai->ai_addr == NULL ||
- ai->ai_addrlen == 0 ||
+ if (ai->ai_addr == NULL)
+ goto bad;
+#if defined(_AIX)
+ if (ai->ai_family == AF_INET6 && passive) {
+ inet6++;
+ continue;
+ }
+ ai->ai_addr->sa_len = ai->ai_addrlen;
+ ai->ai_addr->sa_family = ai->ai_family;
+#endif
+ if (ai->ai_addrlen == 0 ||
getnameinfo(ai->ai_addr, ai->ai_addrlen,
straddr, sizeof(straddr), strport, sizeof(strport),
NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
@@ -281,120 +113,599 @@ main()
if (aitop)
freeaddrinfo(aitop);
- exit(0);
+ return EXIT_SUCCESS;
bad:
if (aitop)
freeaddrinfo(aitop);
- exit(1);
+ return EXIT_FAILURE;
}
EOF
- $getaddr_info_ok = true
-end
-if $ipv6 and not $getaddr_info_ok
- print <<EOS
-Fatal: --enable-ipv6 is specified, and your OS seems to support IPv6 feature.
-But your getaddrinfo() and getnameinfo() are appeared to be broken. Sorry,
-you cannot compile IPv6 socket classes with broken these functions.
-You can try --enable-wide-getaddrinfo.
+RECVMSG_WITH_MSG_PEEK_ALLOCATE_FD_TEST = <<'EOF'
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+ int ps[2], sv[2];
+ int ret;
+ ssize_t ss;
+ int s_fd, r_fd;
+ struct msghdr s_msg, r_msg;
+ union {
+ struct cmsghdr hdr;
+ char dummy[CMSG_SPACE(sizeof(int))];
+ } s_cmsg, r_cmsg;
+ struct iovec s_iov, r_iov;
+ char s_buf[1], r_buf[1];
+ struct stat s_statbuf, r_statbuf;
+
+ ret = pipe(ps);
+ if (ret == -1) { perror("pipe"); exit(EXIT_FAILURE); }
+
+ s_fd = ps[0];
+
+ ret = socketpair(AF_UNIX, SOCK_DGRAM, 0, sv);
+ if (ret == -1) { perror("socketpair"); exit(EXIT_FAILURE); }
+
+ s_msg.msg_name = NULL;
+ s_msg.msg_namelen = 0;
+ s_msg.msg_iov = &s_iov;
+ s_msg.msg_iovlen = 1;
+ s_msg.msg_control = &s_cmsg;
+ s_msg.msg_controllen = CMSG_SPACE(sizeof(int));;
+ s_msg.msg_flags = 0;
+
+ s_iov.iov_base = &s_buf;
+ s_iov.iov_len = sizeof(s_buf);
+
+ s_buf[0] = 'a';
+
+ s_cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(int));
+ s_cmsg.hdr.cmsg_level = SOL_SOCKET;
+ s_cmsg.hdr.cmsg_type = SCM_RIGHTS;
+ memcpy(CMSG_DATA(&s_cmsg.hdr), (char *)&s_fd, sizeof(int));
+
+ ss = sendmsg(sv[0], &s_msg, 0);
+ if (ss == -1) { perror("sendmsg"); exit(EXIT_FAILURE); }
+
+ r_msg.msg_name = NULL;
+ r_msg.msg_namelen = 0;
+ r_msg.msg_iov = &r_iov;
+ r_msg.msg_iovlen = 1;
+ r_msg.msg_control = &r_cmsg;
+ r_msg.msg_controllen = CMSG_SPACE(sizeof(int));
+ r_msg.msg_flags = 0;
+
+ r_iov.iov_base = &r_buf;
+ r_iov.iov_len = sizeof(r_buf);
+
+ r_buf[0] = '0';
+
+ memset(&r_cmsg, 0xff, CMSG_SPACE(sizeof(int)));
+
+ ss = recvmsg(sv[1], &r_msg, MSG_PEEK);
+ if (ss == -1) { perror("recvmsg"); exit(EXIT_FAILURE); }
+
+ if (ss != 1) {
+ fprintf(stderr, "unexpected return value from recvmsg: %ld\n", (long)ss);
+ exit(EXIT_FAILURE);
+ }
+ if (r_buf[0] != 'a') {
+ fprintf(stderr, "unexpected return data from recvmsg: 0x%02x\n", r_buf[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (r_msg.msg_controllen < CMSG_LEN(sizeof(int))) {
+ fprintf(stderr, "unexpected: r_msg.msg_controllen < CMSG_LEN(sizeof(int)) not hold: %ld\n",
+ (long)r_msg.msg_controllen);
+ exit(EXIT_FAILURE);
+ }
+ if (r_cmsg.hdr.cmsg_len < CMSG_LEN(sizeof(int))) {
+ fprintf(stderr, "unexpected: r_cmsg.hdr.cmsg_len < CMSG_LEN(sizeof(int)) not hold: %ld\n",
+ (long)r_cmsg.hdr.cmsg_len);
+ exit(EXIT_FAILURE);
+ }
+ memcpy((char *)&r_fd, CMSG_DATA(&r_cmsg.hdr), sizeof(int));
+
+ if (r_fd < 0) {
+ fprintf(stderr, "negative r_fd: %d\n", r_fd);
+ exit(EXIT_FAILURE);
+ }
+
+ if (r_fd == s_fd) {
+ fprintf(stderr, "r_fd and s_fd is same: %d\n", r_fd);
+ exit(EXIT_FAILURE);
+ }
+
+ ret = fstat(s_fd, &s_statbuf);
+ if (ret == -1) { perror("fstat(s_fd)"); exit(EXIT_FAILURE); }
+
+ ret = fstat(r_fd, &r_statbuf);
+ if (ret == -1) { perror("fstat(r_fd)"); exit(EXIT_FAILURE); }
+
+ if (s_statbuf.st_dev != r_statbuf.st_dev ||
+ s_statbuf.st_ino != r_statbuf.st_ino) {
+ fprintf(stderr, "dev/ino doesn't match: s_fd:%ld/%ld r_fd:%ld/%ld\n",
+ (long)s_statbuf.st_dev, (long)s_statbuf.st_ino,
+ (long)r_statbuf.st_dev, (long)r_statbuf.st_ino);
+ exit(EXIT_FAILURE);
+ }
+
+ return EXIT_SUCCESS;
+}
+EOF
+
+def test_recvmsg_with_msg_peek_creates_fds(headers)
+ case RUBY_PLATFORM
+ when /linux/
+ # Linux 2.6.38 allocate fds by recvmsg with MSG_PEEK.
+ close_fds = true
+ when /bsd|darwin/
+ # FreeBSD 8.2.0, NetBSD 5 and MacOS X Snow Leopard doesn't
+ # allocate fds by recvmsg with MSG_PEEK.
+ # [ruby-dev:44189]
+ # http://bugs.ruby-lang.org/issues/5075
+ close_fds = false
+ when /cygwin/
+ # Cygwin doesn't support fd passing.
+ # http://cygwin.com/ml/cygwin/2003-09/msg01808.html
+ close_fds = false
+ else
+ close_fds = nil
+ end
+ if !CROSS_COMPILING
+ if checking_for("recvmsg() with MSG_PEEK allocate file descriptors") {
+ try_run(cpp_include(headers) + RECVMSG_WITH_MSG_PEEK_ALLOCATE_FD_TEST)
+ }
+ if close_fds == false
+ warn "unexpected fd-passing recvmsg() with MSG_PEEK behavor on #{RUBY_PLATFORM}: fd allocation unexpected."
+ elsif close_fds == nil
+ puts "info: #{RUBY_PLATFORM} recvmsg() with MSG_PEEK allocates fds on fd-passing."
+ end
+ close_fds = true
+ else
+ if close_fds == true
+ warn "unexpected fd-passing recvmsg() with MSG_PEEK behavor on #{RUBY_PLATFORM}: fd allocation expected."
+ elsif close_fds == nil
+ puts "info: #{RUBY_PLATFORM}: recvmsg() with MSG_PEEK doesn't allocates fds on fd-passing."
+ end
+ close_fds = false
+ end
+ end
+ if close_fds == nil
+ abort <<EOS
+Fatal: cannot test fd-passing recvmsg() with MSG_PEEK behavor
+because cross-compilation for #{RUBY_PLATFORM}.
+If recvmsg() with MSG_PEEK allocates fds on fd passing:
+--enable-close-fds-by-recvmsg-with-peek
+If recvmsg() with MSG_PEEK doesn't allocate fds on fd passing:
+--disable-close-fds-by-recvmsg-with-peek
EOS
- exit
+ end
+ close_fds
end
-
-case with_config("lookup-order-hack", "UNSPEC")
-when "INET"
- $CFLAGS="-DLOOKUP_ORDER_HACK_INET "+$CFLAGS
-when "INET6"
- $CFLAGS="-DLOOKUP_ORDER_HACK_INET6 "+$CFLAGS
-when "UNSPEC"
- # nothing special
-else
- print <<EOS
-Fatal: invalid value for --with-lookup-order-hack (expected INET, INET6 or UNSPEC)
-EOS
- exit
+$INCFLAGS << " -I$(topdir) -I$(top_srcdir)"
+
+if /darwin/ =~ RUBY_PLATFORM
+ # For IPv6 extension header access on OS X 10.7+ [Bug #8517]
+ $CFLAGS << " -D__APPLE_USE_RFC_3542"
end
-$objs = ["socket.#{$OBJEXT}"]
-
-if $getaddr_info_ok and have_func("getaddrinfo", "netdb.h") and have_func("getnameinfo", "netdb.h")
- have_getaddrinfo = true
-else
- if try_link(<<EOF)
-#ifndef _WIN32
-# include <sys/types.h>
-# include <netdb.h>
-# include <string.h>
-# include <sys/socket.h>
-# include <netinet/in.h>
-#else
-# include <windows.h>
-# ifdef _WIN32_WCE
-# include <winsock.h>
-# else
-# include <winsock.h>
-# endif
-#endif
-int
-main()
-{
- struct in6_addr addr;
- unsigned char c;
- c = addr.s6_addr8;
- return 0;
+headers = []
+unless $mswin or $mingw
+ headers = %w<sys/types.h netdb.h string.h sys/socket.h netinet/in.h>
+end
+
+%w[
+ sys/uio.h
+ xti.h
+ netinet/in_systm.h
+ netinet/tcp.h
+ netinet/tcp_fsm.h
+ netinet/udp.h
+ arpa/inet.h
+ netpacket/packet.h
+ net/ethernet.h
+ sys/un.h
+ afunix.h
+ ifaddrs.h
+ sys/ioctl.h
+ sys/sockio.h
+ net/if.h
+ sys/param.h
+ sys/ucred.h
+ ucred.h
+ net/if_dl.h
+ arpa/nameser.h
+ resolv.h
+ pthread.h
+ sched.h
+].each {|h|
+ if have_header(h, headers)
+ headers << h
+ end
}
-EOF
- $CFLAGS="-DHAVE_ADDR8 "+$CFLAGS
+
+have_struct_member("struct sockaddr", "sa_len", headers) # 4.4BSD
+have_struct_member("struct sockaddr_in", "sin_len", headers) # 4.4BSD
+have_struct_member("struct sockaddr_in6", "sin6_len", headers) # 4.4BSD
+
+if have_type("struct sockaddr_un", headers) # POSIX
+ have_struct_member("struct sockaddr_un", "sun_len", headers) # 4.4BSD
+end
+
+have_type("struct sockaddr_dl", headers) # AF_LINK address. 4.4BSD since Net2
+
+have_type("struct sockaddr_storage", headers)
+
+have_type("struct addrinfo", headers)
+
+def check_socklen(headers)
+ def (fmt = "none").%(x)
+ x || self
end
+ s = checking_for("RSTRING_SOCKLEN", fmt) do
+ if try_static_assert("sizeof(socklen_t) >= sizeof(long)", headers)
+ "RSTRING_LEN"
+ else
+ "RSTRING_LENINT"
+ end
+ end
+ $defs << "-DRSTRING_SOCKLEN=(socklen_t)"+s
+end
+
+if have_type("socklen_t", headers)
+ check_socklen(headers)
+end
+
+have_type("struct in_pktinfo", headers) {|src|
+ src.sub(%r'^/\*top\*/', '\&'"\n#if defined(IPPROTO_IP) && defined(IP_PKTINFO)") <<
+ "#else\n" << "#error\n" << ">>>>>> no in_pktinfo <<<<<<\n" << "#endif\n"
+} and have_struct_member("struct in_pktinfo", "ipi_spec_dst", headers)
+have_type("struct in6_pktinfo", headers) {|src|
+ src.sub(%r'^/\*top\*/', '\&'"\n#if defined(IPPROTO_IPV6) && defined(IPV6_PKTINFO)") <<
+ "#else\n" << "#error\n" << ">>>>>> no in6_pktinfo <<<<<<\n" << "#endif\n"
+}
+
+have_type("struct sockcred", headers)
+have_type("struct cmsgcred", headers)
+
+have_type("struct ip_mreq", headers) # 4.4BSD
+have_type("struct ip_mreqn", headers) # Linux 2.4
+have_type("struct ipv6_mreq", headers) # RFC 3493
+
+have_msg_control = nil
+have_msg_control = have_struct_member('struct msghdr', 'msg_control', headers) unless $mswin or $mingw
+have_struct_member('struct msghdr', 'msg_accrights', headers)
+
+if have_type("struct tcp_info", headers)
+ have_const("TCP_ESTABLISHED", headers)
+ have_const("TCP_SYN_SENT", headers)
+ have_const("TCP_SYN_RECV", headers)
+ have_const("TCP_FIN_WAIT1", headers)
+ have_const("TCP_FIN_WAIT2", headers)
+ have_const("TCP_TIME_WAIT", headers)
+ have_const("TCP_CLOSE", headers)
+ have_const("TCP_CLOSE_WAIT", headers)
+ have_const("TCP_LAST_ACK", headers)
+ have_const("TCP_LISTEN", headers)
+ have_const("TCP_CLOSING", headers)
+ have_struct_member('struct tcp_info', 'tcpi_state', headers)
+ if /solaris/ !~ RUBY_PLATFORM
+ have_struct_member('struct tcp_info', 'tcpi_ca_state', headers)
+ end
+ have_struct_member('struct tcp_info', 'tcpi_retransmits', headers)
+ have_struct_member('struct tcp_info', 'tcpi_probes', headers)
+ have_struct_member('struct tcp_info', 'tcpi_backoff', headers)
+ have_struct_member('struct tcp_info', 'tcpi_options', headers)
+ have_struct_member('struct tcp_info', 'tcpi_snd_wscale', headers)
+ have_struct_member('struct tcp_info', 'tcpi_rcv_wscale', headers)
+ have_struct_member('struct tcp_info', 'tcpi_rto', headers)
+ have_struct_member('struct tcp_info', 'tcpi_ato', headers)
+ have_struct_member('struct tcp_info', 'tcpi_snd_mss', headers)
+ have_struct_member('struct tcp_info', 'tcpi_rcv_mss', headers)
+ have_struct_member('struct tcp_info', 'tcpi_unacked', headers)
+ have_struct_member('struct tcp_info', 'tcpi_sacked', headers)
+ have_struct_member('struct tcp_info', 'tcpi_lost', headers)
+ have_struct_member('struct tcp_info', 'tcpi_retrans', headers)
+ have_struct_member('struct tcp_info', 'tcpi_fackets', headers)
+ have_struct_member('struct tcp_info', 'tcpi_last_data_sent', headers)
+ have_struct_member('struct tcp_info', 'tcpi_last_ack_sent', headers)
+ have_struct_member('struct tcp_info', 'tcpi_last_data_recv', headers)
+ have_struct_member('struct tcp_info', 'tcpi_last_ack_recv', headers)
+ have_struct_member('struct tcp_info', 'tcpi_pmtu', headers)
+ have_struct_member('struct tcp_info', 'tcpi_rcv_ssthresh', headers)
+ have_struct_member('struct tcp_info', 'tcpi_rtt', headers)
+ have_struct_member('struct tcp_info', 'tcpi_rttvar', headers)
+ have_struct_member('struct tcp_info', 'tcpi_snd_ssthresh', headers)
+ have_struct_member('struct tcp_info', 'tcpi_snd_cwnd', headers)
+ have_struct_member('struct tcp_info', 'tcpi_advmss', headers)
+ have_struct_member('struct tcp_info', 'tcpi_reordering', headers)
+ have_struct_member('struct tcp_info', 'tcpi_rcv_rtt', headers)
+ have_struct_member('struct tcp_info', 'tcpi_rcv_space', headers)
+ have_struct_member('struct tcp_info', 'tcpi_total_retrans', headers)
+
+ # FreeBSD extension
+ have_struct_member('struct tcp_info', 'tcpi_snd_wnd', headers)
+ have_struct_member('struct tcp_info', 'tcpi_snd_bwnd', headers)
+ have_struct_member('struct tcp_info', 'tcpi_snd_nxt', headers)
+ have_struct_member('struct tcp_info', 'tcpi_rcv_nxt', headers)
+ have_struct_member('struct tcp_info', 'tcpi_toe_tid', headers)
+ have_struct_member('struct tcp_info', 'tcpi_snd_rexmitpack', headers)
+ have_struct_member('struct tcp_info', 'tcpi_rcv_ooopack', headers)
+ have_struct_member('struct tcp_info', 'tcpi_snd_zerowin', headers)
end
-if have_getaddrinfo
- $CFLAGS="-DHAVE_GETADDRINFO "+$CFLAGS
+case RUBY_PLATFORM
+when /mswin(32|64)|mingw/
+ test_func = "WSACleanup"
+ have_library("iphlpapi")
+ have_library("ws2_32", "WSACleanup", headers)
+when /cygwin/
+ test_func = "socket(0,0,0)"
+when /haiku/
+ test_func = "socket(0,0,0)"
+ have_library("network", "socket(0,0,0)", headers)
else
- $CFLAGS="-I. "+$CFLAGS
- $objs += ["getaddrinfo.#{$OBJEXT}"]
- $objs += ["getnameinfo.#{$OBJEXT}"]
- have_func("inet_ntop") or have_func("inet_ntoa")
- have_func("inet_pton") or have_func("inet_aton")
- have_func("getservbyport")
- have_header("arpa/inet.h")
- have_header("arpa/nameser.h")
- have_header("resolv.h")
+ test_func = "socket(0,0,0)"
+ have_library("nsl", 't_open("", 0, (struct t_info *)NULL)', headers) # SunOS
+ have_library("socket", "socket(0,0,0)", headers) # SunOS
end
-if !try_link(<<EOF)
-#include <sys/types.h>
-#include <netdb.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-int
-main()
+if have_func(test_func, headers)
+
+ have_func("sendmsg(0, (struct msghdr *)NULL, 0)", headers) # POSIX
+ have_recvmsg = have_func("recvmsg(0, (struct msghdr *)NULL, 0)", headers) # POSIX
+
+ have_func("freehostent((struct hostent *)NULL)", headers) # RFC 2553
+ have_func("freeaddrinfo((struct addrinfo *)NULL)", headers) # RFC 2553
+
+ if /haiku/ !~ RUBY_PLATFORM and
+ have_func("gai_strerror(0)", headers) # POSIX
+ if checking_for("gai_strerror() returns const pointer") {!try_compile(<<EOF)}
+#{cpp_include(headers)}
+#include <stdlib.h>
+void
+conftest_gai_strerror_is_const()
{
- socklen_t len;
- return 0;
+ *gai_strerror(0) = 0;
}
EOF
- $CFLAGS="-Dsocklen_t=int "+$CFLAGS
-end
+ $defs << "-DGAI_STRERROR_CONST"
+ end
+ end
+
+ have_func("accept4", headers)
+
+ have_func('inet_ntop(0, (const void *)0, (char *)0, 0)', headers) or
+ have_func("inet_ntoa(*(struct in_addr *)NULL)", headers)
+ have_func('inet_pton(0, "", (void *)0)', headers) or
+ have_func('inet_aton("", (struct in_addr *)0)', headers)
+ have_func('getservbyport(0, "")', headers)
+ have_func("getifaddrs((struct ifaddrs **)NULL)", headers)
+ have_struct_member("struct if_data", "ifi_vhid", headers) # FreeBSD
-have_header("sys/un.h")
-have_header("sys/uio.h")
+ have_func("getpeereid", headers)
-if have_func(test_func)
- have_func("hsterror")
- have_func("getipnodebyname") or have_func("gethostbyname2")
- unless have_func("gethostname")
- have_func("uname")
+ have_func("getpeerucred(0, (ucred_t **)NULL)", headers) # SunOS
+
+ have_func_decl = proc do |name, headers|
+ # check if there is a declaration of <name> by trying to declare
+ # both "int <name>(void)" and "void <name>(void)"
+ # (at least one attempt should fail if there is a declaration)
+ if !checking_for("declaration of #{name}()") {!%w[int void].all? {|ret| try_compile(<<EOF)}}
+#{cpp_include(headers)}
+#{ret} #{name}(void);
+EOF
+ $defs << "-DNEED_#{name.tr_cpp}_DECL"
+ end
+ end
+ if have_func('if_indextoname(0, "")', headers)
+ have_func_decl["if_indextoname", headers]
end
+ if have_func('if_nametoindex("")', headers)
+ have_func_decl["if_nametoindex", headers]
+ end
+
+ have_func("hsterror", headers)
+ have_func('getipnodebyname("", 0, 0, (int *)0)', headers) # RFC 2553
+ have_func('gethostbyname2("", 0)', headers) # RFC 2133
+ have_func("socketpair(0, 0, 0, 0)", headers)
+ unless have_func("gethostname((char *)0, 0)", headers)
+ have_func("uname((struct utsname *)NULL)", headers)
+ end
+
+ ipv6 = false
+ default_ipv6 = /haiku/ !~ RUBY_PLATFORM
+ if enable_config("ipv6", default_ipv6)
+ if checking_for("ipv6") {try_link(AF_INET6_SOCKET_CREATION_TEST)}
+ $defs << "-DENABLE_IPV6" << "-DINET6"
+ ipv6 = true
+ end
+ end
+
+ if ipv6
+ if $mingw
+ $CPPFLAGS << " -D_WIN32_WINNT=0x501" unless $CPPFLAGS.include?("_WIN32_WINNT")
+ end
+ ipv6lib = nil
+ class << (fmt = "unknown")
+ def %(s) s || self end
+ end
+ idirs, ldirs = dir_config("inet6", %w[/usr/inet6 /usr/local/v6].find {|d| File.directory?(d)})
+ checking_for("ipv6 type", fmt) do
+ if have_macro("IPV6_INRIA_VERSION", "netinet/in.h")
+ "inria"
+ elsif have_macro("__KAME__", "netinet/in.h")
+ have_library(ipv6lib = "inet6")
+ "kame"
+ elsif have_macro("_TOSHIBA_INET6", "sys/param.h")
+ have_library(ipv6lib = "inet6") and "toshiba"
+ elsif have_macro("__V6D__", "sys/v6config.h")
+ have_library(ipv6lib = "v6") and "v6d"
+ elsif have_macro("_ZETA_MINAMI_INET6", "sys/param.h")
+ have_library(ipv6lib = "inet6") and "zeta"
+ elsif have_library("inet6")
+ "inet6"
+ end
+ end or not ipv6lib or abort <<EOS
+
+Fatal: no #{ipv6lib} library found. cannot continue.
+You need to fetch lib#{ipv6lib}.a from appropriate
+ipv6 kit and compile beforehand.
+EOS
+ end
+
+ if !have_macro("IPPROTO_IPV6", headers) && have_const("IPPROTO_IPV6", headers)
+ File.read(File.join(File.dirname(__FILE__), "mkconstants.rb")).sub(/\A.*^__END__$/m, '').split(/\r?\n/).grep(/\AIPPROTO_\w*/){$&}.each {|name|
+ have_const(name, headers) unless $defs.include?("-DHAVE_CONST_#{name.upcase}")
+ }
+ end
+
+ if enable_config("close-fds-by-recvmsg-with-peek") {
+ have_msg_control && have_recvmsg &&
+ have_const('AF_UNIX', headers) && have_const('SCM_RIGHTS', headers) &&
+ test_recvmsg_with_msg_peek_creates_fds(headers)
+ }
+ $defs << "-DFD_PASSING_WORK_WITH_RECVMSG_MSG_PEEK"
+ end
+
+ case enable_config("wide-getaddrinfo")
+ when true
+ getaddr_info_ok = :wide
+ when nil, false
+ getaddr_info_ok = (:wide if getaddr_info_ok.nil?)
+ if have_func("getnameinfo", headers) and have_func("getaddrinfo", headers)
+ if CROSS_COMPILING ||
+ $mingw || $mswin ||
+ checking_for("system getaddrinfo working") {
+ try_run(cpp_include(headers) + GETADDRINFO_GETNAMEINFO_TEST)
+ }
+ getaddr_info_ok = :os
+ end
+ end
+ else
+ raise "unexpected enable_config() value"
+ end
+
+ if ipv6 and not getaddr_info_ok
+ abort <<EOS
+
+Fatal: --enable-ipv6 is specified, and your OS seems to support IPv6 feature.
+But your getaddrinfo() and getnameinfo() are appeared to be broken. Sorry,
+you cannot compile IPv6 socket classes with broken these functions.
+You can try --enable-wide-getaddrinfo.
+EOS
+ end
+
+ case with_config("lookup-order-hack", "UNSPEC")
+ when "INET"
+ $defs << "-DLOOKUP_ORDER_HACK_INET"
+ when "INET6"
+ $defs << "-DLOOKUP_ORDER_HACK_INET6"
+ when "UNSPEC"
+ # nothing special
+ else
+ abort <<EOS
+
+Fatal: invalid value for --with-lookup-order-hack (expected INET, INET6 or UNSPEC)
+EOS
+ end
+
+ $objs = [
+ "init.#{$OBJEXT}",
+ "constants.#{$OBJEXT}",
+ "basicsocket.#{$OBJEXT}",
+ "socket.#{$OBJEXT}",
+ "ipsocket.#{$OBJEXT}",
+ "tcpsocket.#{$OBJEXT}",
+ "tcpserver.#{$OBJEXT}",
+ "sockssocket.#{$OBJEXT}",
+ "udpsocket.#{$OBJEXT}",
+ "unixsocket.#{$OBJEXT}",
+ "unixserver.#{$OBJEXT}",
+ "option.#{$OBJEXT}",
+ "ancdata.#{$OBJEXT}",
+ "raddrinfo.#{$OBJEXT}",
+ "ifaddr.#{$OBJEXT}"
+ ]
+
+ if getaddr_info_ok == :wide
+ if !have_type("struct in6_addr", headers) and have_type("struct in_addr6", headers)
+ $defs.pop(2)
+ $defs << "-Din_addr6=in6_addr"
+ end
+ if have_struct_member("struct in6_addr", "s6_addr8", headers)
+ $defs[-1] = "-Ds6_addr=s6_addr8"
+ end
+ if ipv6 == "kame" && have_struct_member("struct in6_addr", "s6_addr32", headers)
+ $defs[-1] = "-DFAITH"
+ end
+ $CPPFLAGS="-I. "+$CPPFLAGS
+ $objs += ["getaddrinfo.#{$OBJEXT}"]
+ $objs += ["getnameinfo.#{$OBJEXT}"]
+ $defs << "-DGETADDRINFO_EMU"
+ end
+
+ # workaround for recent Windows SDK
+ $defs << "-DIPPROTO_IPV6=IPPROTO_IPV6" if $defs.include?("-DHAVE_CONST_IPPROTO_IPV6") && !have_macro("IPPROTO_IPV6")
+
+ $distcleanfiles << "constants.h" << "constdefs.*"
+
if enable_config("socks", ENV["SOCKS_SERVER"])
if have_library("socks5", "SOCKSinit")
- $CFLAGS+=" -DSOCKS5 -DSOCKS"
- elsif have_library("socks", "Rconnect")
- $CFLAGS+=" -DSOCKS"
+ $defs << "-DSOCKS5" << "-DSOCKS"
+ elsif have_library("socksd", "Rconnect") || have_library("socks", "Rconnect")
+ $defs << "-DSOCKS"
+ end
+ end
+
+ hdr = "netinet6/in6.h"
+ /darwin/ =~ RUBY_PLATFORM and
+ checking_for("if apple's #{hdr} needs s6_addr patch") {!try_compile(<<"SRC", nil, :werror=>true)} and
+#include <netinet/in.h>
+int t(struct in6_addr *addr) {return IN6_IS_ADDR_UNSPECIFIED(addr);}
+SRC
+ checking_for("fixing apple's #{hdr}", "%s") do
+ file = xpopen(%w"clang -include netinet/in.h -E -xc -", in: IO::NULL) do |f|
+ re = %r[^# *\d+ *"(.*/netinet/in\.h)"]
+ Logging.message " grep(#{re})\n"
+ f.read[re, 1]
+ end
+ Logging.message "Substitute from #{file}\n"
+
+ in6 = File.read(file)
+ if in6.gsub!(/\*\(const\s+__uint32_t\s+\*\)\(const\s+void\s+\*\)\(&(\(\w+\))->s6_addr\[(\d+)\]\)/) do
+ i, r = $2.to_i.divmod(4)
+ if r.zero?
+ "#$1->__u6_addr.__u6_addr32[#{i}]"
+ else
+ $&
+ end
+ end
+ FileUtils.mkdir_p(File.dirname(hdr))
+ File.write(hdr, in6)
+ $distcleanfiles << hdr
+ $distcleandirs << File.dirname(hdr)
+ "done"
+ else
+ "not needed"
end
end
+
+ have_func("pthread_create")
+ have_func("pthread_detach")
+ have_func("pthread_attr_setdetachstate")
+
+ $VPATH << '$(topdir)' << '$(top_srcdir)'
create_makefile("socket")
end