summaryrefslogtreecommitdiff
path: root/ext/socket
diff options
context:
space:
mode:
Diffstat (limited to 'ext/socket')
-rw-r--r--ext/socket/depend75
-rw-r--r--ext/socket/extconf.rb1
-rw-r--r--ext/socket/getaddrinfo.c7
-rw-r--r--ext/socket/getnameinfo.c18
-rw-r--r--ext/socket/ifaddr.c2
-rw-r--r--ext/socket/init.c9
-rw-r--r--ext/socket/ipsocket.c268
-rw-r--r--ext/socket/lib/socket.rb120
-rw-r--r--ext/socket/raddrinfo.c187
-rw-r--r--ext/socket/rubysocket.h18
-rw-r--r--ext/socket/socket.c8
-rw-r--r--ext/socket/sockssocket.c5
-rw-r--r--ext/socket/tcpserver.c2
-rw-r--r--ext/socket/tcpsocket.c26
-rw-r--r--ext/socket/udpsocket.c6
-rw-r--r--ext/socket/unixsocket.c3
16 files changed, 542 insertions, 213 deletions
diff --git a/ext/socket/depend b/ext/socket/depend
index 750bb0734f..77f6239a3d 100644
--- a/ext/socket/depend
+++ b/ext/socket/depend
@@ -151,6 +151,7 @@ ancdata.o: $(hdrdir)/ruby/internal/intern/re.h
ancdata.o: $(hdrdir)/ruby/internal/intern/ruby.h
ancdata.o: $(hdrdir)/ruby/internal/intern/select.h
ancdata.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ancdata.o: $(hdrdir)/ruby/internal/intern/set.h
ancdata.o: $(hdrdir)/ruby/internal/intern/signal.h
ancdata.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ancdata.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -192,9 +193,12 @@ ancdata.o: $(top_srcdir)/ccan/check_type/check_type.h
ancdata.o: $(top_srcdir)/ccan/container_of/container_of.h
ancdata.o: $(top_srcdir)/ccan/list/list.h
ancdata.o: $(top_srcdir)/ccan/str/str.h
+ancdata.o: $(top_srcdir)/encindex.h
+ancdata.o: $(top_srcdir)/id_table.h
ancdata.o: $(top_srcdir)/internal.h
ancdata.o: $(top_srcdir)/internal/array.h
ancdata.o: $(top_srcdir)/internal/basic_operators.h
+ancdata.o: $(top_srcdir)/internal/box.h
ancdata.o: $(top_srcdir)/internal/compilers.h
ancdata.o: $(top_srcdir)/internal/error.h
ancdata.o: $(top_srcdir)/internal/gc.h
@@ -202,6 +206,7 @@ ancdata.o: $(top_srcdir)/internal/imemo.h
ancdata.o: $(top_srcdir)/internal/io.h
ancdata.o: $(top_srcdir)/internal/sanitizers.h
ancdata.o: $(top_srcdir)/internal/serial.h
+ancdata.o: $(top_srcdir)/internal/set_table.h
ancdata.o: $(top_srcdir)/internal/static_assert.h
ancdata.o: $(top_srcdir)/internal/string.h
ancdata.o: $(top_srcdir)/internal/thread.h
@@ -362,6 +367,7 @@ basicsocket.o: $(hdrdir)/ruby/internal/intern/re.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/select.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+basicsocket.o: $(hdrdir)/ruby/internal/intern/set.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/signal.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
basicsocket.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -403,9 +409,12 @@ basicsocket.o: $(top_srcdir)/ccan/check_type/check_type.h
basicsocket.o: $(top_srcdir)/ccan/container_of/container_of.h
basicsocket.o: $(top_srcdir)/ccan/list/list.h
basicsocket.o: $(top_srcdir)/ccan/str/str.h
+basicsocket.o: $(top_srcdir)/encindex.h
+basicsocket.o: $(top_srcdir)/id_table.h
basicsocket.o: $(top_srcdir)/internal.h
basicsocket.o: $(top_srcdir)/internal/array.h
basicsocket.o: $(top_srcdir)/internal/basic_operators.h
+basicsocket.o: $(top_srcdir)/internal/box.h
basicsocket.o: $(top_srcdir)/internal/compilers.h
basicsocket.o: $(top_srcdir)/internal/error.h
basicsocket.o: $(top_srcdir)/internal/gc.h
@@ -413,6 +422,7 @@ basicsocket.o: $(top_srcdir)/internal/imemo.h
basicsocket.o: $(top_srcdir)/internal/io.h
basicsocket.o: $(top_srcdir)/internal/sanitizers.h
basicsocket.o: $(top_srcdir)/internal/serial.h
+basicsocket.o: $(top_srcdir)/internal/set_table.h
basicsocket.o: $(top_srcdir)/internal/static_assert.h
basicsocket.o: $(top_srcdir)/internal/string.h
basicsocket.o: $(top_srcdir)/internal/thread.h
@@ -573,6 +583,7 @@ constants.o: $(hdrdir)/ruby/internal/intern/re.h
constants.o: $(hdrdir)/ruby/internal/intern/ruby.h
constants.o: $(hdrdir)/ruby/internal/intern/select.h
constants.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+constants.o: $(hdrdir)/ruby/internal/intern/set.h
constants.o: $(hdrdir)/ruby/internal/intern/signal.h
constants.o: $(hdrdir)/ruby/internal/intern/sprintf.h
constants.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -614,9 +625,12 @@ constants.o: $(top_srcdir)/ccan/check_type/check_type.h
constants.o: $(top_srcdir)/ccan/container_of/container_of.h
constants.o: $(top_srcdir)/ccan/list/list.h
constants.o: $(top_srcdir)/ccan/str/str.h
+constants.o: $(top_srcdir)/encindex.h
+constants.o: $(top_srcdir)/id_table.h
constants.o: $(top_srcdir)/internal.h
constants.o: $(top_srcdir)/internal/array.h
constants.o: $(top_srcdir)/internal/basic_operators.h
+constants.o: $(top_srcdir)/internal/box.h
constants.o: $(top_srcdir)/internal/compilers.h
constants.o: $(top_srcdir)/internal/error.h
constants.o: $(top_srcdir)/internal/gc.h
@@ -624,6 +638,7 @@ constants.o: $(top_srcdir)/internal/imemo.h
constants.o: $(top_srcdir)/internal/io.h
constants.o: $(top_srcdir)/internal/sanitizers.h
constants.o: $(top_srcdir)/internal/serial.h
+constants.o: $(top_srcdir)/internal/set_table.h
constants.o: $(top_srcdir)/internal/static_assert.h
constants.o: $(top_srcdir)/internal/string.h
constants.o: $(top_srcdir)/internal/thread.h
@@ -785,6 +800,7 @@ ifaddr.o: $(hdrdir)/ruby/internal/intern/re.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/ruby.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/select.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ifaddr.o: $(hdrdir)/ruby/internal/intern/set.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/signal.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ifaddr.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -826,9 +842,12 @@ ifaddr.o: $(top_srcdir)/ccan/check_type/check_type.h
ifaddr.o: $(top_srcdir)/ccan/container_of/container_of.h
ifaddr.o: $(top_srcdir)/ccan/list/list.h
ifaddr.o: $(top_srcdir)/ccan/str/str.h
+ifaddr.o: $(top_srcdir)/encindex.h
+ifaddr.o: $(top_srcdir)/id_table.h
ifaddr.o: $(top_srcdir)/internal.h
ifaddr.o: $(top_srcdir)/internal/array.h
ifaddr.o: $(top_srcdir)/internal/basic_operators.h
+ifaddr.o: $(top_srcdir)/internal/box.h
ifaddr.o: $(top_srcdir)/internal/compilers.h
ifaddr.o: $(top_srcdir)/internal/error.h
ifaddr.o: $(top_srcdir)/internal/gc.h
@@ -836,6 +855,7 @@ ifaddr.o: $(top_srcdir)/internal/imemo.h
ifaddr.o: $(top_srcdir)/internal/io.h
ifaddr.o: $(top_srcdir)/internal/sanitizers.h
ifaddr.o: $(top_srcdir)/internal/serial.h
+ifaddr.o: $(top_srcdir)/internal/set_table.h
ifaddr.o: $(top_srcdir)/internal/static_assert.h
ifaddr.o: $(top_srcdir)/internal/string.h
ifaddr.o: $(top_srcdir)/internal/thread.h
@@ -996,6 +1016,7 @@ init.o: $(hdrdir)/ruby/internal/intern/re.h
init.o: $(hdrdir)/ruby/internal/intern/ruby.h
init.o: $(hdrdir)/ruby/internal/intern/select.h
init.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+init.o: $(hdrdir)/ruby/internal/intern/set.h
init.o: $(hdrdir)/ruby/internal/intern/signal.h
init.o: $(hdrdir)/ruby/internal/intern/sprintf.h
init.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1037,9 +1058,12 @@ init.o: $(top_srcdir)/ccan/check_type/check_type.h
init.o: $(top_srcdir)/ccan/container_of/container_of.h
init.o: $(top_srcdir)/ccan/list/list.h
init.o: $(top_srcdir)/ccan/str/str.h
+init.o: $(top_srcdir)/encindex.h
+init.o: $(top_srcdir)/id_table.h
init.o: $(top_srcdir)/internal.h
init.o: $(top_srcdir)/internal/array.h
init.o: $(top_srcdir)/internal/basic_operators.h
+init.o: $(top_srcdir)/internal/box.h
init.o: $(top_srcdir)/internal/compilers.h
init.o: $(top_srcdir)/internal/error.h
init.o: $(top_srcdir)/internal/gc.h
@@ -1047,6 +1071,7 @@ init.o: $(top_srcdir)/internal/imemo.h
init.o: $(top_srcdir)/internal/io.h
init.o: $(top_srcdir)/internal/sanitizers.h
init.o: $(top_srcdir)/internal/serial.h
+init.o: $(top_srcdir)/internal/set_table.h
init.o: $(top_srcdir)/internal/static_assert.h
init.o: $(top_srcdir)/internal/string.h
init.o: $(top_srcdir)/internal/thread.h
@@ -1207,6 +1232,7 @@ ipsocket.o: $(hdrdir)/ruby/internal/intern/re.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/select.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+ipsocket.o: $(hdrdir)/ruby/internal/intern/set.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/signal.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
ipsocket.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1248,9 +1274,12 @@ ipsocket.o: $(top_srcdir)/ccan/check_type/check_type.h
ipsocket.o: $(top_srcdir)/ccan/container_of/container_of.h
ipsocket.o: $(top_srcdir)/ccan/list/list.h
ipsocket.o: $(top_srcdir)/ccan/str/str.h
+ipsocket.o: $(top_srcdir)/encindex.h
+ipsocket.o: $(top_srcdir)/id_table.h
ipsocket.o: $(top_srcdir)/internal.h
ipsocket.o: $(top_srcdir)/internal/array.h
ipsocket.o: $(top_srcdir)/internal/basic_operators.h
+ipsocket.o: $(top_srcdir)/internal/box.h
ipsocket.o: $(top_srcdir)/internal/compilers.h
ipsocket.o: $(top_srcdir)/internal/error.h
ipsocket.o: $(top_srcdir)/internal/gc.h
@@ -1258,6 +1287,7 @@ ipsocket.o: $(top_srcdir)/internal/imemo.h
ipsocket.o: $(top_srcdir)/internal/io.h
ipsocket.o: $(top_srcdir)/internal/sanitizers.h
ipsocket.o: $(top_srcdir)/internal/serial.h
+ipsocket.o: $(top_srcdir)/internal/set_table.h
ipsocket.o: $(top_srcdir)/internal/static_assert.h
ipsocket.o: $(top_srcdir)/internal/string.h
ipsocket.o: $(top_srcdir)/internal/thread.h
@@ -1418,6 +1448,7 @@ option.o: $(hdrdir)/ruby/internal/intern/re.h
option.o: $(hdrdir)/ruby/internal/intern/ruby.h
option.o: $(hdrdir)/ruby/internal/intern/select.h
option.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+option.o: $(hdrdir)/ruby/internal/intern/set.h
option.o: $(hdrdir)/ruby/internal/intern/signal.h
option.o: $(hdrdir)/ruby/internal/intern/sprintf.h
option.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1459,9 +1490,12 @@ option.o: $(top_srcdir)/ccan/check_type/check_type.h
option.o: $(top_srcdir)/ccan/container_of/container_of.h
option.o: $(top_srcdir)/ccan/list/list.h
option.o: $(top_srcdir)/ccan/str/str.h
+option.o: $(top_srcdir)/encindex.h
+option.o: $(top_srcdir)/id_table.h
option.o: $(top_srcdir)/internal.h
option.o: $(top_srcdir)/internal/array.h
option.o: $(top_srcdir)/internal/basic_operators.h
+option.o: $(top_srcdir)/internal/box.h
option.o: $(top_srcdir)/internal/compilers.h
option.o: $(top_srcdir)/internal/error.h
option.o: $(top_srcdir)/internal/gc.h
@@ -1469,6 +1503,7 @@ option.o: $(top_srcdir)/internal/imemo.h
option.o: $(top_srcdir)/internal/io.h
option.o: $(top_srcdir)/internal/sanitizers.h
option.o: $(top_srcdir)/internal/serial.h
+option.o: $(top_srcdir)/internal/set_table.h
option.o: $(top_srcdir)/internal/static_assert.h
option.o: $(top_srcdir)/internal/string.h
option.o: $(top_srcdir)/internal/thread.h
@@ -1629,6 +1664,7 @@ raddrinfo.o: $(hdrdir)/ruby/internal/intern/re.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/ruby.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/select.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+raddrinfo.o: $(hdrdir)/ruby/internal/intern/set.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/signal.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/sprintf.h
raddrinfo.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1670,9 +1706,12 @@ raddrinfo.o: $(top_srcdir)/ccan/check_type/check_type.h
raddrinfo.o: $(top_srcdir)/ccan/container_of/container_of.h
raddrinfo.o: $(top_srcdir)/ccan/list/list.h
raddrinfo.o: $(top_srcdir)/ccan/str/str.h
+raddrinfo.o: $(top_srcdir)/encindex.h
+raddrinfo.o: $(top_srcdir)/id_table.h
raddrinfo.o: $(top_srcdir)/internal.h
raddrinfo.o: $(top_srcdir)/internal/array.h
raddrinfo.o: $(top_srcdir)/internal/basic_operators.h
+raddrinfo.o: $(top_srcdir)/internal/box.h
raddrinfo.o: $(top_srcdir)/internal/compilers.h
raddrinfo.o: $(top_srcdir)/internal/error.h
raddrinfo.o: $(top_srcdir)/internal/gc.h
@@ -1680,6 +1719,7 @@ raddrinfo.o: $(top_srcdir)/internal/imemo.h
raddrinfo.o: $(top_srcdir)/internal/io.h
raddrinfo.o: $(top_srcdir)/internal/sanitizers.h
raddrinfo.o: $(top_srcdir)/internal/serial.h
+raddrinfo.o: $(top_srcdir)/internal/set_table.h
raddrinfo.o: $(top_srcdir)/internal/static_assert.h
raddrinfo.o: $(top_srcdir)/internal/string.h
raddrinfo.o: $(top_srcdir)/internal/thread.h
@@ -1840,6 +1880,7 @@ socket.o: $(hdrdir)/ruby/internal/intern/re.h
socket.o: $(hdrdir)/ruby/internal/intern/ruby.h
socket.o: $(hdrdir)/ruby/internal/intern/select.h
socket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+socket.o: $(hdrdir)/ruby/internal/intern/set.h
socket.o: $(hdrdir)/ruby/internal/intern/signal.h
socket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
socket.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -1881,9 +1922,12 @@ socket.o: $(top_srcdir)/ccan/check_type/check_type.h
socket.o: $(top_srcdir)/ccan/container_of/container_of.h
socket.o: $(top_srcdir)/ccan/list/list.h
socket.o: $(top_srcdir)/ccan/str/str.h
+socket.o: $(top_srcdir)/encindex.h
+socket.o: $(top_srcdir)/id_table.h
socket.o: $(top_srcdir)/internal.h
socket.o: $(top_srcdir)/internal/array.h
socket.o: $(top_srcdir)/internal/basic_operators.h
+socket.o: $(top_srcdir)/internal/box.h
socket.o: $(top_srcdir)/internal/compilers.h
socket.o: $(top_srcdir)/internal/error.h
socket.o: $(top_srcdir)/internal/gc.h
@@ -1891,6 +1935,7 @@ socket.o: $(top_srcdir)/internal/imemo.h
socket.o: $(top_srcdir)/internal/io.h
socket.o: $(top_srcdir)/internal/sanitizers.h
socket.o: $(top_srcdir)/internal/serial.h
+socket.o: $(top_srcdir)/internal/set_table.h
socket.o: $(top_srcdir)/internal/static_assert.h
socket.o: $(top_srcdir)/internal/string.h
socket.o: $(top_srcdir)/internal/thread.h
@@ -2051,6 +2096,7 @@ sockssocket.o: $(hdrdir)/ruby/internal/intern/re.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/select.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+sockssocket.o: $(hdrdir)/ruby/internal/intern/set.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/signal.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
sockssocket.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2092,9 +2138,12 @@ sockssocket.o: $(top_srcdir)/ccan/check_type/check_type.h
sockssocket.o: $(top_srcdir)/ccan/container_of/container_of.h
sockssocket.o: $(top_srcdir)/ccan/list/list.h
sockssocket.o: $(top_srcdir)/ccan/str/str.h
+sockssocket.o: $(top_srcdir)/encindex.h
+sockssocket.o: $(top_srcdir)/id_table.h
sockssocket.o: $(top_srcdir)/internal.h
sockssocket.o: $(top_srcdir)/internal/array.h
sockssocket.o: $(top_srcdir)/internal/basic_operators.h
+sockssocket.o: $(top_srcdir)/internal/box.h
sockssocket.o: $(top_srcdir)/internal/compilers.h
sockssocket.o: $(top_srcdir)/internal/error.h
sockssocket.o: $(top_srcdir)/internal/gc.h
@@ -2102,6 +2151,7 @@ sockssocket.o: $(top_srcdir)/internal/imemo.h
sockssocket.o: $(top_srcdir)/internal/io.h
sockssocket.o: $(top_srcdir)/internal/sanitizers.h
sockssocket.o: $(top_srcdir)/internal/serial.h
+sockssocket.o: $(top_srcdir)/internal/set_table.h
sockssocket.o: $(top_srcdir)/internal/static_assert.h
sockssocket.o: $(top_srcdir)/internal/string.h
sockssocket.o: $(top_srcdir)/internal/thread.h
@@ -2262,6 +2312,7 @@ tcpserver.o: $(hdrdir)/ruby/internal/intern/re.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/ruby.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/select.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+tcpserver.o: $(hdrdir)/ruby/internal/intern/set.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/signal.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/sprintf.h
tcpserver.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2303,9 +2354,12 @@ tcpserver.o: $(top_srcdir)/ccan/check_type/check_type.h
tcpserver.o: $(top_srcdir)/ccan/container_of/container_of.h
tcpserver.o: $(top_srcdir)/ccan/list/list.h
tcpserver.o: $(top_srcdir)/ccan/str/str.h
+tcpserver.o: $(top_srcdir)/encindex.h
+tcpserver.o: $(top_srcdir)/id_table.h
tcpserver.o: $(top_srcdir)/internal.h
tcpserver.o: $(top_srcdir)/internal/array.h
tcpserver.o: $(top_srcdir)/internal/basic_operators.h
+tcpserver.o: $(top_srcdir)/internal/box.h
tcpserver.o: $(top_srcdir)/internal/compilers.h
tcpserver.o: $(top_srcdir)/internal/error.h
tcpserver.o: $(top_srcdir)/internal/gc.h
@@ -2313,6 +2367,7 @@ tcpserver.o: $(top_srcdir)/internal/imemo.h
tcpserver.o: $(top_srcdir)/internal/io.h
tcpserver.o: $(top_srcdir)/internal/sanitizers.h
tcpserver.o: $(top_srcdir)/internal/serial.h
+tcpserver.o: $(top_srcdir)/internal/set_table.h
tcpserver.o: $(top_srcdir)/internal/static_assert.h
tcpserver.o: $(top_srcdir)/internal/string.h
tcpserver.o: $(top_srcdir)/internal/thread.h
@@ -2473,6 +2528,7 @@ tcpsocket.o: $(hdrdir)/ruby/internal/intern/re.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/select.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+tcpsocket.o: $(hdrdir)/ruby/internal/intern/set.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/signal.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
tcpsocket.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2514,9 +2570,12 @@ tcpsocket.o: $(top_srcdir)/ccan/check_type/check_type.h
tcpsocket.o: $(top_srcdir)/ccan/container_of/container_of.h
tcpsocket.o: $(top_srcdir)/ccan/list/list.h
tcpsocket.o: $(top_srcdir)/ccan/str/str.h
+tcpsocket.o: $(top_srcdir)/encindex.h
+tcpsocket.o: $(top_srcdir)/id_table.h
tcpsocket.o: $(top_srcdir)/internal.h
tcpsocket.o: $(top_srcdir)/internal/array.h
tcpsocket.o: $(top_srcdir)/internal/basic_operators.h
+tcpsocket.o: $(top_srcdir)/internal/box.h
tcpsocket.o: $(top_srcdir)/internal/compilers.h
tcpsocket.o: $(top_srcdir)/internal/error.h
tcpsocket.o: $(top_srcdir)/internal/gc.h
@@ -2524,6 +2583,7 @@ tcpsocket.o: $(top_srcdir)/internal/imemo.h
tcpsocket.o: $(top_srcdir)/internal/io.h
tcpsocket.o: $(top_srcdir)/internal/sanitizers.h
tcpsocket.o: $(top_srcdir)/internal/serial.h
+tcpsocket.o: $(top_srcdir)/internal/set_table.h
tcpsocket.o: $(top_srcdir)/internal/static_assert.h
tcpsocket.o: $(top_srcdir)/internal/string.h
tcpsocket.o: $(top_srcdir)/internal/thread.h
@@ -2684,6 +2744,7 @@ udpsocket.o: $(hdrdir)/ruby/internal/intern/re.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/select.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+udpsocket.o: $(hdrdir)/ruby/internal/intern/set.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/signal.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
udpsocket.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2725,9 +2786,12 @@ udpsocket.o: $(top_srcdir)/ccan/check_type/check_type.h
udpsocket.o: $(top_srcdir)/ccan/container_of/container_of.h
udpsocket.o: $(top_srcdir)/ccan/list/list.h
udpsocket.o: $(top_srcdir)/ccan/str/str.h
+udpsocket.o: $(top_srcdir)/encindex.h
+udpsocket.o: $(top_srcdir)/id_table.h
udpsocket.o: $(top_srcdir)/internal.h
udpsocket.o: $(top_srcdir)/internal/array.h
udpsocket.o: $(top_srcdir)/internal/basic_operators.h
+udpsocket.o: $(top_srcdir)/internal/box.h
udpsocket.o: $(top_srcdir)/internal/compilers.h
udpsocket.o: $(top_srcdir)/internal/error.h
udpsocket.o: $(top_srcdir)/internal/gc.h
@@ -2735,6 +2799,7 @@ udpsocket.o: $(top_srcdir)/internal/imemo.h
udpsocket.o: $(top_srcdir)/internal/io.h
udpsocket.o: $(top_srcdir)/internal/sanitizers.h
udpsocket.o: $(top_srcdir)/internal/serial.h
+udpsocket.o: $(top_srcdir)/internal/set_table.h
udpsocket.o: $(top_srcdir)/internal/static_assert.h
udpsocket.o: $(top_srcdir)/internal/string.h
udpsocket.o: $(top_srcdir)/internal/thread.h
@@ -2895,6 +2960,7 @@ unixserver.o: $(hdrdir)/ruby/internal/intern/re.h
unixserver.o: $(hdrdir)/ruby/internal/intern/ruby.h
unixserver.o: $(hdrdir)/ruby/internal/intern/select.h
unixserver.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+unixserver.o: $(hdrdir)/ruby/internal/intern/set.h
unixserver.o: $(hdrdir)/ruby/internal/intern/signal.h
unixserver.o: $(hdrdir)/ruby/internal/intern/sprintf.h
unixserver.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -2936,9 +3002,12 @@ unixserver.o: $(top_srcdir)/ccan/check_type/check_type.h
unixserver.o: $(top_srcdir)/ccan/container_of/container_of.h
unixserver.o: $(top_srcdir)/ccan/list/list.h
unixserver.o: $(top_srcdir)/ccan/str/str.h
+unixserver.o: $(top_srcdir)/encindex.h
+unixserver.o: $(top_srcdir)/id_table.h
unixserver.o: $(top_srcdir)/internal.h
unixserver.o: $(top_srcdir)/internal/array.h
unixserver.o: $(top_srcdir)/internal/basic_operators.h
+unixserver.o: $(top_srcdir)/internal/box.h
unixserver.o: $(top_srcdir)/internal/compilers.h
unixserver.o: $(top_srcdir)/internal/error.h
unixserver.o: $(top_srcdir)/internal/gc.h
@@ -2946,6 +3015,7 @@ unixserver.o: $(top_srcdir)/internal/imemo.h
unixserver.o: $(top_srcdir)/internal/io.h
unixserver.o: $(top_srcdir)/internal/sanitizers.h
unixserver.o: $(top_srcdir)/internal/serial.h
+unixserver.o: $(top_srcdir)/internal/set_table.h
unixserver.o: $(top_srcdir)/internal/static_assert.h
unixserver.o: $(top_srcdir)/internal/string.h
unixserver.o: $(top_srcdir)/internal/thread.h
@@ -3106,6 +3176,7 @@ unixsocket.o: $(hdrdir)/ruby/internal/intern/re.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/ruby.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/select.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/select/largesize.h
+unixsocket.o: $(hdrdir)/ruby/internal/intern/set.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/signal.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/sprintf.h
unixsocket.o: $(hdrdir)/ruby/internal/intern/string.h
@@ -3147,9 +3218,12 @@ unixsocket.o: $(top_srcdir)/ccan/check_type/check_type.h
unixsocket.o: $(top_srcdir)/ccan/container_of/container_of.h
unixsocket.o: $(top_srcdir)/ccan/list/list.h
unixsocket.o: $(top_srcdir)/ccan/str/str.h
+unixsocket.o: $(top_srcdir)/encindex.h
+unixsocket.o: $(top_srcdir)/id_table.h
unixsocket.o: $(top_srcdir)/internal.h
unixsocket.o: $(top_srcdir)/internal/array.h
unixsocket.o: $(top_srcdir)/internal/basic_operators.h
+unixsocket.o: $(top_srcdir)/internal/box.h
unixsocket.o: $(top_srcdir)/internal/compilers.h
unixsocket.o: $(top_srcdir)/internal/error.h
unixsocket.o: $(top_srcdir)/internal/gc.h
@@ -3157,6 +3231,7 @@ unixsocket.o: $(top_srcdir)/internal/imemo.h
unixsocket.o: $(top_srcdir)/internal/io.h
unixsocket.o: $(top_srcdir)/internal/sanitizers.h
unixsocket.o: $(top_srcdir)/internal/serial.h
+unixsocket.o: $(top_srcdir)/internal/set_table.h
unixsocket.o: $(top_srcdir)/internal/static_assert.h
unixsocket.o: $(top_srcdir)/internal/string.h
unixsocket.o: $(top_srcdir)/internal/thread.h
diff --git a/ext/socket/extconf.rb b/ext/socket/extconf.rb
index d44ce31b0a..a814e21c3a 100644
--- a/ext/socket/extconf.rb
+++ b/ext/socket/extconf.rb
@@ -704,6 +704,7 @@ SRC
have_func("pthread_create")
have_func("pthread_detach")
+ have_func("pthread_attr_setdetachstate")
$VPATH << '$(topdir)' << '$(top_srcdir)'
create_makefile("socket")
diff --git a/ext/socket/getaddrinfo.c b/ext/socket/getaddrinfo.c
index bf0d90129f..9a65490b1d 100644
--- a/ext/socket/getaddrinfo.c
+++ b/ext/socket/getaddrinfo.c
@@ -62,9 +62,6 @@
#endif
#include <unistd.h>
#else
-#if defined(_MSC_VER) && _MSC_VER <= 1200
-#include <windows.h>
-#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#include <io.h>
@@ -171,9 +168,7 @@ static const char *const ai_errlist[] = {
#define GET_CANONNAME(ai, str) \
if (pai->ai_flags & AI_CANONNAME) {\
- if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
- strcpy((ai)->ai_canonname, (str));\
- } else {\
+ if (((ai)->ai_canonname = strdup(str)) == NULL) {\
error = EAI_MEMORY;\
goto free;\
}\
diff --git a/ext/socket/getnameinfo.c b/ext/socket/getnameinfo.c
index ae5284fab6..98da8c1647 100644
--- a/ext/socket/getnameinfo.c
+++ b/ext/socket/getnameinfo.c
@@ -55,9 +55,6 @@
#endif
#endif
#ifdef _WIN32
-#if defined(_MSC_VER) && _MSC_VER <= 1200
-#include <windows.h>
-#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#define snprintf _snprintf
@@ -158,16 +155,14 @@ getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t ho
/* what we should do? */
} else if (flags & NI_NUMERICSERV) {
snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
- if (strlen(numserv) + 1 > servlen)
+ if (strlcpy(serv, numserv, servlen) >= servlen)
return ENI_MEMORY;
- strcpy(serv, numserv);
} else {
#if defined(HAVE_GETSERVBYPORT)
struct servent *sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp");
if (sp) {
- if (strlen(sp->s_name) + 1 > servlen)
+ if (strlcpy(serv, sp->s_name, servlen) >= servlen)
return ENI_MEMORY;
- strcpy(serv, sp->s_name);
} else
return ENI_NOSERVNAME;
#else
@@ -202,9 +197,8 @@ getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t ho
if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
== NULL)
return ENI_SYSTEM;
- if (strlen(numaddr) > hostlen)
+ if (strlcpy(host, numaddr, hostlen) >= hostlen)
return ENI_MEMORY;
- strcpy(host, numaddr);
} else {
#ifdef INET6
hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
@@ -218,13 +212,12 @@ getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t ho
p = strchr(hp->h_name, '.');
if (p) *p = '\0';
}
- if (strlen(hp->h_name) + 1 > hostlen) {
+ if (strlcpy(host, hp->h_name, hostlen) >= hostlen) {
#ifdef INET6
freehostent(hp);
#endif
return ENI_MEMORY;
}
- strcpy(host, hp->h_name);
#ifdef INET6
freehostent(hp);
#endif
@@ -234,9 +227,8 @@ getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t ho
if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
== NULL)
return ENI_NOHOSTNAME;
- if (strlen(numaddr) > hostlen)
+ if (strlcpy(host, numaddr, hostlen) >= hostlen)
return ENI_MEMORY;
- strcpy(host, numaddr);
}
}
return SUCCESS;
diff --git a/ext/socket/ifaddr.c b/ext/socket/ifaddr.c
index ab163dcc8f..3596c40a11 100644
--- a/ext/socket/ifaddr.c
+++ b/ext/socket/ifaddr.c
@@ -177,6 +177,8 @@ ifaddr_ifindex(VALUE self)
* ifaddr.flags => integer
*
* Returns the flags of _ifaddr_.
+ *
+ * The value is bitwise-or of Socket::IFF_* constants such as Socket::IFF_LOOPBACK.
*/
static VALUE
diff --git a/ext/socket/init.c b/ext/socket/init.c
index 8e405609ba..b761d601c3 100644
--- a/ext/socket/init.c
+++ b/ext/socket/init.c
@@ -473,7 +473,7 @@ rsock_socket(int domain, int type, int proto)
/* emulate blocking connect behavior on EINTR or non-blocking socket */
static int
-wait_connectable(VALUE self, VALUE timeout)
+wait_connectable(VALUE self, VALUE timeout, const struct sockaddr *sockaddr, int len)
{
int sockerr;
socklen_t sockerrlen;
@@ -514,7 +514,10 @@ wait_connectable(VALUE self, VALUE timeout)
VALUE result = rb_io_wait(self, RB_INT2NUM(RUBY_IO_READABLE|RUBY_IO_WRITABLE), timeout);
if (result == Qfalse) {
- rb_raise(rb_eIOTimeoutError, "Connect timed out!");
+ VALUE rai = rsock_addrinfo_new((struct sockaddr *)sockaddr, len, PF_UNSPEC, 0, 0, Qnil, Qnil);
+ VALUE addr_str = rsock_addrinfo_inspect_sockaddr(rai);
+ VALUE message = rb_sprintf("user specified timeout for %" PRIsVALUE, addr_str);
+ rb_raise(rb_eIOTimeoutError, "%" PRIsVALUE, message);
}
int revents = RB_NUM2INT(result);
@@ -603,7 +606,7 @@ rsock_connect(VALUE self, const struct sockaddr *sockaddr, int len, int socks, V
#ifdef EINPROGRESS
case EINPROGRESS:
#endif
- return wait_connectable(self, timeout);
+ return wait_connectable(self, timeout, sockaddr, len);
}
}
return status;
diff --git a/ext/socket/ipsocket.c b/ext/socket/ipsocket.c
index 3e497a43be..931a1a629c 100644
--- a/ext/socket/ipsocket.c
+++ b/ext/socket/ipsocket.c
@@ -23,8 +23,25 @@ struct inetsock_arg
int type;
VALUE resolv_timeout;
VALUE connect_timeout;
+ VALUE open_timeout;
};
+void
+rsock_raise_user_specified_timeout(struct addrinfo *ai, VALUE host, VALUE port)
+{
+ VALUE message;
+
+ if (ai && ai->ai_addr) {
+ VALUE rai = rsock_addrinfo_new((struct sockaddr *)ai->ai_addr, (socklen_t)ai->ai_addrlen, PF_UNSPEC, 0, 0, Qnil, Qnil);
+ VALUE addr_str = rsock_addrinfo_inspect_sockaddr(rai);
+ message = rb_sprintf("user specified timeout for %" PRIsVALUE, addr_str);
+ } else {
+ message = rb_sprintf("user specified timeout for %" PRIsVALUE " port %" PRIsVALUE, host, port);
+ }
+
+ rb_raise(rb_eIOTimeoutError, "%" PRIsVALUE, message);
+}
+
static VALUE
inetsock_cleanup(VALUE v)
{
@@ -45,6 +62,13 @@ inetsock_cleanup(VALUE v)
}
static VALUE
+current_clocktime(void)
+{
+ VALUE clock_monotnic_const = rb_const_get(rb_mProcess, rb_intern("CLOCK_MONOTONIC"));
+ return rb_funcall(rb_mProcess, rb_intern("clock_gettime"), 1, clock_monotnic_const);
+}
+
+static VALUE
init_inetsock_internal(VALUE v)
{
struct inetsock_arg *arg = (void *)v;
@@ -54,12 +78,18 @@ init_inetsock_internal(VALUE v)
int status = 0, local = 0;
int family = AF_UNSPEC;
const char *syscall = 0;
+ VALUE resolv_timeout = arg->resolv_timeout;
VALUE connect_timeout = arg->connect_timeout;
+ VALUE open_timeout = arg->open_timeout;
+ VALUE timeout;
+ VALUE starts_at;
+
+ timeout = NIL_P(open_timeout) ? resolv_timeout : open_timeout;
+ starts_at = current_clocktime();
arg->remote.res = rsock_addrinfo(arg->remote.host, arg->remote.serv,
family, SOCK_STREAM,
- (type == INET_SERVER) ? AI_PASSIVE : 0);
-
+ (type == INET_SERVER) ? AI_PASSIVE : 0, timeout);
/*
* Maybe also accept a local address
@@ -67,7 +97,7 @@ init_inetsock_internal(VALUE v)
if (type != INET_SERVER && (!NIL_P(arg->local.host) || !NIL_P(arg->local.serv))) {
arg->local.res = rsock_addrinfo(arg->local.host, arg->local.serv,
- family, SOCK_STREAM, 0);
+ family, SOCK_STREAM, 0, timeout);
}
VALUE io = Qnil;
@@ -122,8 +152,18 @@ init_inetsock_internal(VALUE v)
syscall = "bind(2)";
}
+ if (NIL_P(open_timeout)) {
+ timeout = connect_timeout;
+ } else {
+ VALUE elapsed = rb_funcall(current_clocktime(), '-', 1, starts_at);
+ timeout = rb_funcall(open_timeout, '-', 1, elapsed);
+ if (rb_funcall(timeout, '<', 1, INT2FIX(0)) == Qtrue) {
+ rsock_raise_user_specified_timeout(res, arg->remote.host, arg->remote.serv);
+ }
+ }
+
if (status >= 0) {
- status = rsock_connect(io, res->ai_addr, res->ai_addrlen, (type == INET_SOCKS), connect_timeout);
+ status = rsock_connect(io, res->ai_addr, res->ai_addrlen, (type == INET_SOCKS), timeout);
syscall = "connect(2)";
}
}
@@ -172,8 +212,16 @@ init_inetsock_internal(VALUE v)
#if FAST_FALLBACK_INIT_INETSOCK_IMPL == 0
VALUE
-rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type, VALUE resolv_timeout, VALUE connect_timeout, VALUE _fast_fallback, VALUE _test_mode_settings)
+rsock_init_inetsock(
+ VALUE self, VALUE remote_host, VALUE remote_serv,
+ VALUE local_host, VALUE local_serv, int type,
+ VALUE resolv_timeout, VALUE connect_timeout, VALUE open_timeout,
+ VALUE _fast_fallback, VALUE _test_mode_settings)
{
+ if (!NIL_P(open_timeout) && (!NIL_P(resolv_timeout) || !NIL_P(connect_timeout))) {
+ rb_raise(rb_eArgError, "Cannot specify open_timeout along with connect_timeout or resolv_timeout");
+ }
+
struct inetsock_arg arg;
arg.self = self;
arg.io = Qnil;
@@ -186,6 +234,7 @@ rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE loca
arg.type = type;
arg.resolv_timeout = resolv_timeout;
arg.connect_timeout = connect_timeout;
+ arg.open_timeout = open_timeout;
return rb_ensure(init_inetsock_internal, (VALUE)&arg,
inetsock_cleanup, (VALUE)&arg);
}
@@ -209,6 +258,21 @@ is_specified_ip_address(const char *hostname)
inet_pton(AF_INET, hostname, &ipv4addr) == 1);
}
+static int
+is_local_port_fixed(const char *portp)
+{
+ if (!portp) return 0;
+
+ char *endp;
+ errno = 0;
+ long port = strtol(portp, &endp, 10);
+
+ if (endp == portp) return 0;
+ if (errno == ERANGE) return 0;
+
+ return port > 0;
+}
+
struct fast_fallback_inetsock_arg
{
VALUE self;
@@ -221,6 +285,7 @@ struct fast_fallback_inetsock_arg
int type;
VALUE resolv_timeout;
VALUE connect_timeout;
+ VALUE open_timeout;
const char *hostp, *portp;
int *families;
@@ -295,7 +360,7 @@ struct hostname_resolution_store
{
struct hostname_resolution_result v6;
struct hostname_resolution_result v4;
- int is_all_finised;
+ int is_all_finished;
};
static int
@@ -380,12 +445,22 @@ select_expires_at(
struct timeval *resolution_delay,
struct timeval *connection_attempt_delay,
struct timeval *user_specified_resolv_timeout_at,
- struct timeval *user_specified_connect_timeout_at
-) {
+ struct timeval *user_specified_connect_timeout_at,
+ struct timeval *user_specified_open_timeout_at)
+{
if (any_addrinfos(resolution_store)) {
- return resolution_delay ? resolution_delay : connection_attempt_delay;
+ struct timeval *delay;
+ delay = resolution_delay ? resolution_delay : connection_attempt_delay;
+
+ if (user_specified_open_timeout_at &&
+ timercmp(user_specified_open_timeout_at, delay, <)) {
+ return user_specified_open_timeout_at;
+ }
+ return delay;
}
+ if (user_specified_open_timeout_at) return user_specified_open_timeout_at;
+
struct timeval *timeout = NULL;
if (user_specified_resolv_timeout_at) {
@@ -474,7 +549,8 @@ in_progress_fds(int fds_size)
}
static void
-remove_connection_attempt_fd(int *fds, int *fds_size, int removing_fd) {
+remove_connection_attempt_fd(int *fds, int *fds_size, int removing_fd)
+{
int i, j;
for (i = 0; i < *fds_size; i++) {
@@ -503,6 +579,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
VALUE io = arg->io;
VALUE resolv_timeout = arg->resolv_timeout;
VALUE connect_timeout = arg->connect_timeout;
+ VALUE open_timeout = arg->open_timeout;
VALUE test_mode_settings = arg->test_mode_settings;
struct addrinfo *remote_ai = NULL, *local_ai = NULL;
int connected_fd = -1, status = 0, local_status = 0;
@@ -527,7 +604,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
struct timeval *delay_p = NULL;
struct hostname_resolution_store resolution_store;
- resolution_store.is_all_finised = false;
+ resolution_store.is_all_finished = false;
resolution_store.v6.ai = NULL;
resolution_store.v6.finished = false;
resolution_store.v6.has_error = false;
@@ -549,7 +626,16 @@ init_fast_fallback_inetsock_internal(VALUE v)
struct timeval *user_specified_resolv_timeout_at = NULL;
struct timeval user_specified_connect_timeout_storage;
struct timeval *user_specified_connect_timeout_at = NULL;
+ struct timeval user_specified_open_timeout_storage;
+ struct timeval *user_specified_open_timeout_at = NULL;
struct timespec now = current_clocktime_ts();
+ VALUE starts_at = current_clocktime();
+
+ if (!NIL_P(open_timeout)) {
+ struct timeval open_timeout_tv = rb_time_interval(open_timeout);
+ user_specified_open_timeout_storage = add_ts_to_tv(open_timeout_tv, now);
+ user_specified_open_timeout_at = &user_specified_open_timeout_storage;
+ }
/* start of hostname resolution */
if (arg->family_size == 1) {
@@ -557,12 +643,15 @@ init_fast_fallback_inetsock_internal(VALUE v)
arg->getaddrinfo_shared = NULL;
int family = arg->families[0];
+ VALUE t = NIL_P(open_timeout) ? resolv_timeout : open_timeout;
+
arg->remote.res = rsock_addrinfo(
arg->remote.host,
arg->remote.serv,
family,
SOCK_STREAM,
- 0
+ 0,
+ t
);
if (family == AF_INET6) {
@@ -574,7 +663,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
resolution_store.v4.finished = true;
resolution_store.v6.finished = true;
}
- resolution_store.is_all_finised = true;
+ resolution_store.is_all_finished = true;
} else {
if (pipe(pipefd) != 0) rb_syserr_fail(errno, "pipe(2)");
hostname_resolution_waiter = pipefd[0];
@@ -593,7 +682,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
arg->getaddrinfo_shared->notify = hostname_resolution_notifier;
arg->getaddrinfo_shared->node = arg->hostp ? ruby_strdup(arg->hostp) : NULL;
- arg->getaddrinfo_shared->service = ruby_strdup(arg->portp);
+ arg->getaddrinfo_shared->service = arg->portp ? ruby_strdup(arg->portp) : NULL;
arg->getaddrinfo_shared->refcount = arg->family_size + 1;
for (int i = 0; i < arg->family_size; i++) {
@@ -640,7 +729,6 @@ init_fast_fallback_inetsock_internal(VALUE v)
if (raddrinfo_pthread_create(&threads[i], fork_safe_do_fast_fallback_getaddrinfo, arg->getaddrinfo_entries[i]) != 0) {
rsock_raise_resolution_error("getaddrinfo(3)", EAI_AGAIN);
}
- pthread_detach(threads[i]);
}
if (NIL_P(resolv_timeout)) {
@@ -664,7 +752,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
if (remote_ai->ai_family == AF_INET6) {
if (any_addrinfos(&resolution_store)) continue;
if (!in_progress_fds(arg->connection_attempt_fds_size)) break;
- if (resolution_store.is_all_finised) break;
+ if (resolution_store.is_all_finished) break;
if (local_status < 0) {
host = arg->local.host;
@@ -690,7 +778,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
if (!local_ai) {
if (any_addrinfos(&resolution_store)) continue;
if (in_progress_fds(arg->connection_attempt_fds_size)) break;
- if (!resolution_store.is_all_finised) break;
+ if (!resolution_store.is_all_finished) break;
/* Use a different family local address if no choice, this
* will cause EAFNOSUPPORT. */
@@ -707,7 +795,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
if (any_addrinfos(&resolution_store)) continue;
if (in_progress_fds(arg->connection_attempt_fds_size)) break;
- if (!resolution_store.is_all_finised) break;
+ if (!resolution_store.is_all_finished) break;
if (local_status < 0) {
host = arg->local.host;
@@ -743,7 +831,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
if (any_addrinfos(&resolution_store)) continue;
if (in_progress_fds(arg->connection_attempt_fds_size)) break;
- if (!resolution_store.is_all_finised) break;
+ if (!resolution_store.is_all_finished) break;
if (local_status < 0) {
host = arg->local.host;
@@ -764,19 +852,31 @@ init_fast_fallback_inetsock_internal(VALUE v)
if (any_addrinfos(&resolution_store) ||
in_progress_fds(arg->connection_attempt_fds_size) ||
- !resolution_store.is_all_finised) {
+ !resolution_store.is_all_finished) {
socket_nonblock_set(fd);
status = connect(fd, remote_ai->ai_addr, remote_ai->ai_addrlen);
last_family = remote_ai->ai_family;
} else {
- if (!NIL_P(connect_timeout)) {
- user_specified_connect_timeout_storage = rb_time_interval(connect_timeout);
- user_specified_connect_timeout_at = &user_specified_connect_timeout_storage;
+ VALUE timeout = Qnil;
+
+ if (!NIL_P(open_timeout)) {
+ VALUE elapsed = rb_funcall(current_clocktime(), '-', 1, starts_at);
+ timeout = rb_funcall(open_timeout, '-', 1, elapsed);
+
+ if (rb_funcall(timeout, '<', 1, INT2FIX(0)) == Qtrue) {
+ rsock_raise_user_specified_timeout(NULL, arg->remote.host, arg->remote.serv);
+ }
+ }
+ if (NIL_P(timeout)) {
+ if (!NIL_P(connect_timeout)) {
+ user_specified_connect_timeout_storage = rb_time_interval(connect_timeout);
+ user_specified_connect_timeout_at = &user_specified_connect_timeout_storage;
+ }
+ timeout =
+ (user_specified_connect_timeout_at && is_infinity(*user_specified_connect_timeout_at)) ?
+ Qnil : tv_to_seconds(user_specified_connect_timeout_at);
}
- VALUE timeout =
- (user_specified_connect_timeout_at && is_infinity(*user_specified_connect_timeout_at)) ?
- Qnil : tv_to_seconds(user_specified_connect_timeout_at);
io = arg->io = rsock_init_sock(arg->self, fd);
status = rsock_connect(io, remote_ai->ai_addr, remote_ai->ai_addrlen, 0, timeout);
}
@@ -824,7 +924,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
if (any_addrinfos(&resolution_store)) continue;
if (in_progress_fds(arg->connection_attempt_fds_size)) break;
- if (!resolution_store.is_all_finised) break;
+ if (!resolution_store.is_all_finished) break;
if (local_status < 0) {
host = arg->local.host;
@@ -848,7 +948,8 @@ init_fast_fallback_inetsock_internal(VALUE v)
resolution_delay_expires_at,
connection_attempt_delay_expires_at,
user_specified_resolv_timeout_at,
- user_specified_connect_timeout_at
+ user_specified_connect_timeout_at,
+ user_specified_open_timeout_at
);
if (ends_at) {
delay = tv_to_timeout(ends_at, now);
@@ -892,7 +993,6 @@ init_fast_fallback_inetsock_internal(VALUE v)
}
status = rb_thread_fd_select(nfds, &arg->readfds, &arg->writefds, NULL, delay_p);
- syscall = "select(2)";
now = current_clocktime_ts();
if (is_timeout_tv(resolution_delay_expires_at, now)) {
@@ -923,7 +1023,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
if (any_addrinfos(&resolution_store)) continue;
if (in_progress_fds(arg->connection_attempt_fds_size)) break;
- if (!resolution_store.is_all_finised) break;
+ if (!resolution_store.is_all_finished) break;
if (local_status < 0) {
host = arg->local.host;
@@ -962,7 +1062,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
if (connected_fd >= 0) break;
if (!in_progress_fds(arg->connection_attempt_fds_size)) {
- if (!any_addrinfos(&resolution_store) && resolution_store.is_all_finised) {
+ if (!any_addrinfos(&resolution_store) && resolution_store.is_all_finished) {
if (local_status < 0) {
host = arg->local.host;
serv = arg->local.serv;
@@ -982,7 +1082,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
}
/* check for hostname resolution */
- if (!resolution_store.is_all_finised && rb_fd_isset(hostname_resolution_waiter, &arg->readfds)) {
+ if (!resolution_store.is_all_finished && rb_fd_isset(hostname_resolution_waiter, &arg->readfds)) {
while (true) {
resolved_type_size = read(
hostname_resolution_waiter,
@@ -998,15 +1098,17 @@ init_fast_fallback_inetsock_internal(VALUE v)
if (arg->getaddrinfo_entries[IPV6_ENTRY_POS]->err &&
arg->getaddrinfo_entries[IPV6_ENTRY_POS]->err != EAI_ADDRFAMILY) {
- last_error.type = RESOLUTION_ERROR;
- last_error.ecode = arg->getaddrinfo_entries[IPV6_ENTRY_POS]->err;
- syscall = "getaddrinfo(3)";
+ if (!resolution_store.v4.finished || resolution_store.v4.has_error) {
+ last_error.type = RESOLUTION_ERROR;
+ last_error.ecode = arg->getaddrinfo_entries[IPV6_ENTRY_POS]->err;
+ syscall = "getaddrinfo(3)";
+ }
resolution_store.v6.has_error = true;
} else {
resolution_store.v6.ai = arg->getaddrinfo_entries[IPV6_ENTRY_POS]->ai;
}
if (resolution_store.v4.finished) {
- resolution_store.is_all_finised = true;
+ resolution_store.is_all_finished = true;
resolution_delay_expires_at = NULL;
user_specified_resolv_timeout_at = NULL;
break;
@@ -1015,16 +1117,18 @@ init_fast_fallback_inetsock_internal(VALUE v)
resolution_store.v4.finished = true;
if (arg->getaddrinfo_entries[IPV4_ENTRY_POS]->err) {
- last_error.type = RESOLUTION_ERROR;
- last_error.ecode = arg->getaddrinfo_entries[IPV4_ENTRY_POS]->err;
- syscall = "getaddrinfo(3)";
+ if (!resolution_store.v6.finished || resolution_store.v6.has_error) {
+ last_error.type = RESOLUTION_ERROR;
+ last_error.ecode = arg->getaddrinfo_entries[IPV4_ENTRY_POS]->err;
+ syscall = "getaddrinfo(3)";
+ }
resolution_store.v4.has_error = true;
} else {
resolution_store.v4.ai = arg->getaddrinfo_entries[IPV4_ENTRY_POS]->ai;
}
if (resolution_store.v6.finished) {
- resolution_store.is_all_finised = true;
+ resolution_store.is_all_finished = true;
resolution_delay_expires_at = NULL;
user_specified_resolv_timeout_at = NULL;
break;
@@ -1052,21 +1156,23 @@ init_fast_fallback_inetsock_internal(VALUE v)
}
/* For cases where write(2) fails in child threads */
- if (!resolution_store.is_all_finised) {
+ if (!resolution_store.is_all_finished) {
if (!resolution_store.v6.finished && arg->getaddrinfo_entries[IPV6_ENTRY_POS]->has_syserr) {
resolution_store.v6.finished = true;
if (arg->getaddrinfo_entries[IPV6_ENTRY_POS]->err) {
- last_error.type = RESOLUTION_ERROR;
- last_error.ecode = arg->getaddrinfo_entries[IPV6_ENTRY_POS]->err;
- syscall = "getaddrinfo(3)";
+ if (!resolution_store.v4.finished || resolution_store.v4.has_error) {
+ last_error.type = RESOLUTION_ERROR;
+ last_error.ecode = arg->getaddrinfo_entries[IPV6_ENTRY_POS]->err;
+ syscall = "getaddrinfo(3)";
+ }
resolution_store.v6.has_error = true;
} else {
resolution_store.v6.ai = arg->getaddrinfo_entries[IPV6_ENTRY_POS]->ai;
}
if (resolution_store.v4.finished) {
- resolution_store.is_all_finised = true;
+ resolution_store.is_all_finished = true;
resolution_delay_expires_at = NULL;
user_specified_resolv_timeout_at = NULL;
}
@@ -1075,16 +1181,18 @@ init_fast_fallback_inetsock_internal(VALUE v)
resolution_store.v4.finished = true;
if (arg->getaddrinfo_entries[IPV4_ENTRY_POS]->err) {
- last_error.type = RESOLUTION_ERROR;
- last_error.ecode = arg->getaddrinfo_entries[IPV4_ENTRY_POS]->err;
- syscall = "getaddrinfo(3)";
+ if (!resolution_store.v6.finished || resolution_store.v6.has_error) {
+ last_error.type = RESOLUTION_ERROR;
+ last_error.ecode = arg->getaddrinfo_entries[IPV4_ENTRY_POS]->err;
+ syscall = "getaddrinfo(3)";
+ }
resolution_store.v4.has_error = true;
} else {
resolution_store.v4.ai = arg->getaddrinfo_entries[IPV4_ENTRY_POS]->ai;
}
if (resolution_store.v6.finished) {
- resolution_store.is_all_finised = true;
+ resolution_store.is_all_finished = true;
resolution_delay_expires_at = NULL;
user_specified_resolv_timeout_at = NULL;
} else {
@@ -1094,9 +1202,13 @@ init_fast_fallback_inetsock_internal(VALUE v)
}
}
+ if (is_timeout_tv(user_specified_open_timeout_at, now)) {
+ rsock_raise_user_specified_timeout(NULL, arg->remote.host, arg->remote.serv);
+ }
+
if (!any_addrinfos(&resolution_store)) {
if (!in_progress_fds(arg->connection_attempt_fds_size) &&
- resolution_store.is_all_finised) {
+ resolution_store.is_all_finished) {
if (local_status < 0) {
host = arg->local.host;
serv = arg->local.serv;
@@ -1112,12 +1224,10 @@ init_fast_fallback_inetsock_internal(VALUE v)
}
if ((is_timeout_tv(user_specified_resolv_timeout_at, now) ||
- resolution_store.is_all_finised) &&
+ resolution_store.is_all_finished) &&
(is_timeout_tv(user_specified_connect_timeout_at, now) ||
!in_progress_fds(arg->connection_attempt_fds_size))) {
- VALUE errno_module = rb_const_get(rb_cObject, rb_intern("Errno"));
- VALUE etimedout_error = rb_const_get(errno_module, rb_intern("ETIMEDOUT"));
- rb_raise(etimedout_error, "user specified timeout");
+ rsock_raise_user_specified_timeout(NULL, arg->remote.host, arg->remote.serv);
}
}
}
@@ -1152,13 +1262,19 @@ fast_fallback_inetsock_cleanup(VALUE v)
getaddrinfo_shared->notify = -1;
int shared_need_free = 0;
- int need_free[2] = { 0, 0 };
+ struct addrinfo *ais[arg->family_size];
+ for (int i = 0; i < arg->family_size; i++) ais[i] = NULL;
rb_nativethread_lock_lock(&getaddrinfo_shared->lock);
{
for (int i = 0; i < arg->family_size; i++) {
- if (arg->getaddrinfo_entries[i] && --(arg->getaddrinfo_entries[i]->refcount) == 0) {
- need_free[i] = 1;
+ struct fast_fallback_getaddrinfo_entry *getaddrinfo_entry = arg->getaddrinfo_entries[i];
+
+ if (!getaddrinfo_entry) continue;
+
+ if (--(getaddrinfo_entry->refcount) == 0) {
+ ais[i] = getaddrinfo_entry->ai;
+ getaddrinfo_entry->ai = NULL;
}
}
if (--(getaddrinfo_shared->refcount) == 0) {
@@ -1168,9 +1284,11 @@ fast_fallback_inetsock_cleanup(VALUE v)
rb_nativethread_lock_unlock(&getaddrinfo_shared->lock);
for (int i = 0; i < arg->family_size; i++) {
- if (need_free[i]) free_fast_fallback_getaddrinfo_entry(&arg->getaddrinfo_entries[i]);
+ if (ais[i]) freeaddrinfo(ais[i]);
+ }
+ if (getaddrinfo_shared && shared_need_free) {
+ free_fast_fallback_getaddrinfo_shared(&getaddrinfo_shared);
}
- if (shared_need_free) free_fast_fallback_getaddrinfo_shared(&getaddrinfo_shared);
}
int connection_attempt_fd;
@@ -1199,17 +1317,27 @@ fast_fallback_inetsock_cleanup(VALUE v)
}
VALUE
-rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type, VALUE resolv_timeout, VALUE connect_timeout, VALUE fast_fallback, VALUE test_mode_settings)
+rsock_init_inetsock(
+ VALUE self, VALUE remote_host, VALUE remote_serv,
+ VALUE local_host, VALUE local_serv, int type,
+ VALUE resolv_timeout, VALUE connect_timeout, VALUE open_timeout,
+ VALUE fast_fallback, VALUE test_mode_settings)
{
+ if (!NIL_P(open_timeout) && (!NIL_P(resolv_timeout) || !NIL_P(connect_timeout))) {
+ rb_raise(rb_eArgError, "Cannot specify open_timeout along with connect_timeout or resolv_timeout");
+ }
+
if (type == INET_CLIENT && FAST_FALLBACK_INIT_INETSOCK_IMPL == 1 && RTEST(fast_fallback)) {
struct rb_addrinfo *local_res = NULL;
- char *hostp, *portp;
- char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
+ char *hostp, *portp, *local_portp;
+ char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV], local_pbuf[NI_MAXSERV];
int additional_flags = 0;
- hostp = host_str(remote_host, hbuf, sizeof(hbuf), &additional_flags);
- portp = port_str(remote_serv, pbuf, sizeof(pbuf), &additional_flags);
+ int local_flags = 0;
+ hostp = raddrinfo_host_str(remote_host, hbuf, sizeof(hbuf), &additional_flags);
+ portp = raddrinfo_port_str(remote_serv, pbuf, sizeof(pbuf), &additional_flags);
+ local_portp = raddrinfo_port_str(local_serv, local_pbuf, sizeof(local_pbuf), &local_flags);
- if (!is_specified_ip_address(hostp)) {
+ if (!is_specified_ip_address(hostp) && !is_local_port_fixed(local_portp)) {
int target_families[2] = { 0, 0 };
int resolving_family_size = 0;
@@ -1217,16 +1345,18 @@ rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE loca
* Maybe also accept a local address
*/
if (!NIL_P(local_host) || !NIL_P(local_serv)) {
+ VALUE t = NIL_P(open_timeout) ? resolv_timeout : open_timeout;
local_res = rsock_addrinfo(
local_host,
local_serv,
AF_UNSPEC,
SOCK_STREAM,
- 0
+ 0,
+ t
);
struct addrinfo *tmp_p = local_res->ai;
- for (tmp_p; tmp_p != NULL; tmp_p = tmp_p->ai_next) {
+ for (; tmp_p != NULL; tmp_p = tmp_p->ai_next) {
if (target_families[0] == 0 && tmp_p->ai_family == AF_INET6) {
target_families[0] = AF_INET6;
resolving_family_size++;
@@ -1256,6 +1386,7 @@ rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE loca
fast_fallback_arg.type = type;
fast_fallback_arg.resolv_timeout = resolv_timeout;
fast_fallback_arg.connect_timeout = connect_timeout;
+ fast_fallback_arg.open_timeout = open_timeout;
fast_fallback_arg.hostp = hostp;
fast_fallback_arg.portp = portp;
fast_fallback_arg.additional_flags = additional_flags;
@@ -1292,6 +1423,7 @@ rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE loca
arg.type = type;
arg.resolv_timeout = resolv_timeout;
arg.connect_timeout = connect_timeout;
+ arg.open_timeout = open_timeout;
return rb_ensure(init_inetsock_internal, (VALUE)&arg,
inetsock_cleanup, (VALUE)&arg);
@@ -1477,7 +1609,7 @@ static VALUE
ip_s_getaddress(VALUE obj, VALUE host)
{
union_sockaddr addr;
- struct rb_addrinfo *res = rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, 0);
+ struct rb_addrinfo *res = rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, 0, Qnil);
socklen_t len = res->ai->ai_addrlen;
/* just take the first one */
diff --git a/ext/socket/lib/socket.rb b/ext/socket/lib/socket.rb
index 6a1ddf9eda..36fcceaee9 100644
--- a/ext/socket/lib/socket.rb
+++ b/ext/socket/lib/socket.rb
@@ -62,7 +62,7 @@ class Addrinfo
break
when :wait_writable
sock.wait_writable(timeout) or
- raise Errno::ETIMEDOUT, 'user specified timeout'
+ raise Errno::ETIMEDOUT, "user specified timeout for #{self.ip_address}:#{self.ip_port}"
end while true
else
sock.connect(self)
@@ -599,6 +599,7 @@ class Socket < BasicSocket
__accept_nonblock(exception)
end
+ # :stopdoc:
RESOLUTION_DELAY = 0.05
private_constant :RESOLUTION_DELAY
@@ -614,8 +615,9 @@ class Socket < BasicSocket
HOSTNAME_RESOLUTION_QUEUE_UPDATED = 0
private_constant :HOSTNAME_RESOLUTION_QUEUE_UPDATED
- IPV6_ADRESS_FORMAT = /\A(?i:(?:(?:[0-9A-F]{1,4}:){7}(?:[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){6}(?:[0-9A-F]{1,4}|:(?:[0-9A-F]{1,4}:){1,5}[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){5}(?:(?::[0-9A-F]{1,4}){1,2}|:(?:[0-9A-F]{1,4}:){1,4}[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){4}(?:(?::[0-9A-F]{1,4}){1,3}|:(?:[0-9A-F]{1,4}:){1,3}[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){3}(?:(?::[0-9A-F]{1,4}){1,4}|:(?:[0-9A-F]{1,4}:){1,2}[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){2}(?:(?::[0-9A-F]{1,4}){1,5}|:(?:[0-9A-F]{1,4}:)[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){1}(?:(?::[0-9A-F]{1,4}){1,6}|:(?:[0-9A-F]{1,4}:){0,5}[0-9A-F]{1,4}|:)|(?:::(?:[0-9A-F]{1,4}:){0,7}[0-9A-F]{1,4}|::)))(?:%.+)?\z/
- private_constant :IPV6_ADRESS_FORMAT
+ IPV6_ADDRESS_FORMAT = /\A(?i:(?:(?:[0-9A-F]{1,4}:){7}(?:[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){6}(?:[0-9A-F]{1,4}|:(?:[0-9A-F]{1,4}:){1,5}[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){5}(?:(?::[0-9A-F]{1,4}){1,2}|:(?:[0-9A-F]{1,4}:){1,4}[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){4}(?:(?::[0-9A-F]{1,4}){1,3}|:(?:[0-9A-F]{1,4}:){1,3}[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){3}(?:(?::[0-9A-F]{1,4}){1,4}|:(?:[0-9A-F]{1,4}:){1,2}[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){2}(?:(?::[0-9A-F]{1,4}){1,5}|:(?:[0-9A-F]{1,4}:)[0-9A-F]{1,4}|:)|(?:[0-9A-F]{1,4}:){1}(?:(?::[0-9A-F]{1,4}){1,6}|:(?:[0-9A-F]{1,4}:){0,5}[0-9A-F]{1,4}|:)|(?:::(?:[0-9A-F]{1,4}:){0,7}[0-9A-F]{1,4}|::)))(?:%.+)?\z/
+ private_constant :IPV6_ADDRESS_FORMAT
+ # :startdoc:
# :call-seq:
# Socket.tcp(host, port, local_host=nil, local_port=nil, [opts]) {|socket| ... }
@@ -643,6 +645,7 @@ class Socket < BasicSocket
#
# [:resolv_timeout] Specifies the timeout in seconds from when the hostname resolution starts.
# [:connect_timeout] This method sequentially attempts connecting to all candidate destination addresses.<br>The +connect_timeout+ specifies the timeout in seconds from the start of the connection attempt to the last candidate.<br>By default, all connection attempts continue until the timeout occurs.<br>When +fast_fallback:false+ is explicitly specified,<br>a timeout is set for each connection attempt and any connection attempt that exceeds its timeout will be canceled.
+ # [:open_timeout] Specifies the timeout in seconds from the start of the method execution.<br>If this timeout is reached while there are still addresses that have not yet been attempted for connection, no further attempts will be made.<br>If this option is specified together with other timeout options, an +ArgumentError+ will be raised.
# [:fast_fallback] Enables the Happy Eyeballs Version 2 algorithm (enabled by default).
#
# If a block is given, the block is called with the socket.
@@ -656,11 +659,15 @@ class Socket < BasicSocket
# sock.close_write
# puts sock.read
# }
- def self.tcp(host, port, local_host = nil, local_port = nil, connect_timeout: nil, resolv_timeout: nil, fast_fallback: tcp_fast_fallback, &) # :yield: socket
- sock = if fast_fallback && !(host && ip_address?(host))
- tcp_with_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:)
+ def self.tcp(host, port, local_host = nil, local_port = nil, connect_timeout: nil, resolv_timeout: nil, open_timeout: nil, fast_fallback: tcp_fast_fallback, &) # :yield: socket
+ if open_timeout && (connect_timeout || resolv_timeout)
+ raise ArgumentError, "Cannot specify open_timeout along with connect_timeout or resolv_timeout"
+ end
+
+ sock = if fast_fallback && !(host && ip_address?(host)) && !(local_port && local_port.to_i != 0)
+ tcp_with_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:, open_timeout:)
else
- tcp_without_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:)
+ tcp_without_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:, open_timeout:)
end
if block_given?
@@ -674,9 +681,10 @@ class Socket < BasicSocket
end
end
- def self.tcp_with_fast_fallback(host, port, local_host = nil, local_port = nil, connect_timeout: nil, resolv_timeout: nil)
+ # :stopdoc:
+ def self.tcp_with_fast_fallback(host, port, local_host = nil, local_port = nil, connect_timeout: nil, resolv_timeout: nil, open_timeout: nil)
if local_host || local_port
- local_addrinfos = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, timeout: resolv_timeout)
+ local_addrinfos = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, timeout: open_timeout || resolv_timeout)
resolving_family_names = local_addrinfos.map { |lai| ADDRESS_FAMILIES.key(lai.afamily) }.uniq
else
local_addrinfos = []
@@ -689,14 +697,17 @@ class Socket < BasicSocket
is_windows_environment ||= (RUBY_PLATFORM =~ /mswin|mingw|cygwin/)
now = current_clock_time
+ starts_at = now
resolution_delay_expires_at = nil
connection_attempt_delay_expires_at = nil
user_specified_connect_timeout_at = nil
+ user_specified_open_timeout_at = open_timeout ? now + open_timeout : nil
last_error = nil
+ last_error_from_thread = false
if resolving_family_names.size == 1
family_name = resolving_family_names.first
- addrinfos = Addrinfo.getaddrinfo(host, port, family_name, :STREAM, timeout: resolv_timeout)
+ addrinfos = Addrinfo.getaddrinfo(host, port, ADDRESS_FAMILIES[:family_name], :STREAM, timeout: open_timeout || resolv_timeout)
resolution_store.add_resolved(family_name, addrinfos)
hostname_resolution_result = nil
hostname_resolution_notifier = nil
@@ -713,7 +724,6 @@ class Socket < BasicSocket
thread
}
)
-
user_specified_resolv_timeout_at = resolv_timeout ? now + resolv_timeout : Float::INFINITY
end
@@ -725,7 +735,7 @@ class Socket < BasicSocket
if local_addrinfos.any?
local_addrinfo = local_addrinfos.find { |lai| lai.afamily == addrinfo.afamily }
- if local_addrinfo.nil? # Connecting addrinfoと同じアドレスファミリのLocal addrinfoがない
+ if local_addrinfo.nil?
if resolution_store.any_addrinfos?
# Try other Addrinfo in next "while"
next
@@ -747,9 +757,16 @@ class Socket < BasicSocket
socket.bind(local_addrinfo) if local_addrinfo
result = socket.connect_nonblock(addrinfo, exception: false)
else
+ timeout =
+ if open_timeout
+ t = open_timeout - (current_clock_time - starts_at)
+ t.negative? ? 0 : t
+ else
+ connect_timeout
+ end
result = socket = local_addrinfo ?
- addrinfo.connect_from(local_addrinfo, timeout: connect_timeout) :
- addrinfo.connect(timeout: connect_timeout)
+ addrinfo.connect_from(local_addrinfo, timeout:) :
+ addrinfo.connect(timeout:)
end
if result == :wait_writable
@@ -783,7 +800,10 @@ class Socket < BasicSocket
ends_at =
if resolution_store.any_addrinfos?
- resolution_delay_expires_at || connection_attempt_delay_expires_at
+ [(resolution_delay_expires_at || connection_attempt_delay_expires_at),
+ user_specified_open_timeout_at].compact.min
+ elsif user_specified_open_timeout_at
+ user_specified_open_timeout_at
else
[user_specified_resolv_timeout_at, user_specified_connect_timeout_at].compact.max
end
@@ -833,7 +853,7 @@ class Socket < BasicSocket
if except_sockets&.any?
except_sockets.each do |except_socket|
failed_ai = connecting_sockets.delete except_socket
- sockopt = except_socket.getsockopt(Socket::SOL_SOCKET, Socket::SO_CONNECT_TIME)
+ sockopt = except_socket.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR)
except_socket.close
ip_address = failed_ai.ipv6? ? "[#{failed_ai.ip_address}]" : failed_ai.ip_address
last_error = SystemCallError.new("connect(2) for #{ip_address}:#{failed_ai.ip_port}", sockopt.int)
@@ -862,7 +882,11 @@ class Socket < BasicSocket
unless (Socket.const_defined?(:EAI_ADDRFAMILY)) &&
(result.is_a?(Socket::ResolutionError)) &&
(result.error_code == Socket::EAI_ADDRFAMILY)
- last_error = result
+ other = family_name == :ipv6 ? :ipv4 : :ipv6
+ if !resolution_store.resolved?(other) || !resolution_store.resolved_successfully?(other)
+ last_error = result
+ last_error_from_thread = true
+ end
end
else
resolution_store.add_resolved(family_name, result)
@@ -880,14 +904,22 @@ class Socket < BasicSocket
end
end
+ if expired?(now, user_specified_open_timeout_at)
+ raise(IO::TimeoutError, "user specified timeout for #{host}:#{port}")
+ end
+
if resolution_store.empty_addrinfos?
if connecting_sockets.empty? && resolution_store.resolved_all_families?
- raise last_error
+ if last_error_from_thread
+ raise last_error.class, last_error.message, cause: last_error
+ else
+ raise last_error
+ end
end
if (expired?(now, user_specified_resolv_timeout_at) || resolution_store.resolved_all_families?) &&
(expired?(now, user_specified_connect_timeout_at) || connecting_sockets.empty?)
- raise Errno::ETIMEDOUT, 'user specified timeout'
+ raise(IO::TimeoutError, "user specified timeout for #{host}:#{port}")
end
end
end
@@ -902,17 +934,21 @@ class Socket < BasicSocket
connecting_socket.close
end
end
+ private_class_method :tcp_with_fast_fallback
- def self.tcp_without_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:)
+ def self.tcp_without_fast_fallback(host, port, local_host, local_port, connect_timeout:, resolv_timeout:, open_timeout:)
last_error = nil
ret = nil
local_addr_list = nil
if local_host != nil || local_port != nil
- local_addr_list = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, nil)
+ local_addr_list = Addrinfo.getaddrinfo(local_host, local_port, nil, :STREAM, nil, timeout: open_timeout || resolv_timeout)
end
- Addrinfo.foreach(host, port, nil, :STREAM, timeout: resolv_timeout) {|ai|
+ timeout = open_timeout ? open_timeout : resolv_timeout
+ starts_at = current_clock_time
+
+ Addrinfo.foreach(host, port, nil, :STREAM, timeout:) {|ai|
if local_addr_list
local_addr = local_addr_list.find {|local_ai| local_ai.afamily == ai.afamily }
next unless local_addr
@@ -920,9 +956,17 @@ class Socket < BasicSocket
local_addr = nil
end
begin
+ timeout =
+ if open_timeout
+ t = open_timeout - (current_clock_time - starts_at)
+ t.negative? ? 0 : t
+ else
+ connect_timeout
+ end
+
sock = local_addr ?
- ai.connect_from(local_addr, timeout: connect_timeout) :
- ai.connect(timeout: connect_timeout)
+ ai.connect_from(local_addr, timeout:) :
+ ai.connect(timeout:)
rescue SystemCallError
last_error = $!
next
@@ -943,7 +987,7 @@ class Socket < BasicSocket
private_class_method :tcp_without_fast_fallback
def self.ip_address?(hostname)
- hostname.match?(IPV6_ADRESS_FORMAT) || hostname.match?(/\A([0-9]{1,3}\.){3}[0-9]{1,3}\z/)
+ hostname.match?(IPV6_ADDRESS_FORMAT) || hostname.match?(/\A([0-9]{1,3}\.){3}[0-9]{1,3}\z/)
end
private_class_method :ip_address?
@@ -1018,8 +1062,8 @@ class Socket < BasicSocket
private_constant :HostnameResolutionResult
class HostnameResolutionStore
- PRIORITY_ON_V6 = [:ipv6, :ipv4]
- PRIORITY_ON_V4 = [:ipv4, :ipv6]
+ PRIORITY_ON_V6 = [:ipv6, :ipv4].freeze
+ PRIORITY_ON_V4 = [:ipv4, :ipv6].freeze
def initialize(family_names)
@family_names = family_names
@@ -1068,7 +1112,7 @@ class Socket < BasicSocket
end
def resolved_successfully?(family)
- resolved?(family) && !!@error_dict[family]
+ resolved?(family) && !@error_dict[family]
end
def resolved_all_families?
@@ -1081,7 +1125,6 @@ class Socket < BasicSocket
end
private_constant :HostnameResolutionStore
- # :stopdoc:
def self.ip_sockets_port0(ai_list, reuseaddr)
sockets = []
begin
@@ -1114,9 +1157,7 @@ class Socket < BasicSocket
end
sockets
end
- class << self
- private :ip_sockets_port0
- end
+ private_class_method :ip_sockets_port0
def self.tcp_server_sockets_port0(host)
ai_list = Addrinfo.getaddrinfo(host, 0, nil, :STREAM, nil, Socket::AI_PASSIVE)
@@ -1544,13 +1585,18 @@ class Socket < BasicSocket
end
end
- class << self
- private
-
- def unix_socket_abstract_name?(path)
- /linux/ =~ RUBY_PLATFORM && /\A(\0|\z)/ =~ path
+ # :stopdoc:
+ if RUBY_PLATFORM.include?("linux")
+ def self.unix_socket_abstract_name?(path)
+ path.empty? or path.start_with?("\0")
+ end
+ else
+ def self.unix_socket_abstract_name?(path)
+ false
end
end
+ private_class_method :unix_socket_abstract_name?
+ # :startdoc:
# creates a UNIX socket server on _path_.
# It calls the block for each socket accepted.
diff --git a/ext/socket/raddrinfo.c b/ext/socket/raddrinfo.c
index bd39b35390..6cdf5c6abc 100644
--- a/ext/socket/raddrinfo.c
+++ b/ext/socket/raddrinfo.c
@@ -293,10 +293,22 @@ rb_freeaddrinfo(struct rb_addrinfo *ai)
xfree(ai);
}
+static int
+rsock_value_timeout_to_msec(VALUE timeout)
+{
+ double seconds = NUM2DBL(timeout);
+ if (seconds < 0) rb_raise(rb_eArgError, "timeout must not be negative");
+
+ double msec = seconds * 1000.0;
+ if (msec > UINT_MAX) rb_raise(rb_eArgError, "timeout too large");
+
+ return (unsigned int)(msec + 0.5);
+}
+
#if GETADDRINFO_IMPL == 0
static int
-rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai)
+rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, int _timeout)
{
return getaddrinfo(hostp, portp, hints, ai);
}
@@ -334,7 +346,7 @@ fork_safe_getaddrinfo(void *arg)
}
static int
-rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai)
+rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, int _timeout)
{
struct getaddrinfo_arg arg;
MEMZERO(&arg, struct getaddrinfo_arg, 1);
@@ -352,13 +364,14 @@ struct getaddrinfo_arg
char *node, *service;
struct addrinfo hints;
struct addrinfo *ai;
- int err, gai_errno, refcount, done, cancelled;
+ int err, gai_errno, refcount, done, cancelled, timedout;
rb_nativethread_lock_t lock;
rb_nativethread_cond_t cond;
+ int timeout;
};
static struct getaddrinfo_arg *
-allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addrinfo *hints)
+allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addrinfo *hints, int timeout)
{
size_t hostp_offset = sizeof(struct getaddrinfo_arg);
size_t portp_offset = hostp_offset + (hostp ? strlen(hostp) + 1 : 0);
@@ -374,7 +387,7 @@ allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addr
if (hostp) {
arg->node = buf + hostp_offset;
- strcpy(arg->node, hostp);
+ memcpy(arg->node, hostp, portp_offset - hostp_offset);
}
else {
arg->node = NULL;
@@ -382,7 +395,7 @@ allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addr
if (portp) {
arg->service = buf + portp_offset;
- strcpy(arg->service, portp);
+ memcpy(arg->service, portp, bufsize - portp_offset);
}
else {
arg->service = NULL;
@@ -392,7 +405,8 @@ allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addr
arg->ai = NULL;
arg->refcount = 2;
- arg->done = arg->cancelled = 0;
+ arg->done = arg->cancelled = arg->timedout = 0;
+ arg->timeout = timeout;
rb_nativethread_lock_initialize(&arg->lock);
rb_native_cond_initialize(&arg->cond);
@@ -451,7 +465,19 @@ wait_getaddrinfo(void *ptr)
struct getaddrinfo_arg *arg = (struct getaddrinfo_arg *)ptr;
rb_nativethread_lock_lock(&arg->lock);
while (!arg->done && !arg->cancelled) {
- rb_native_cond_wait(&arg->cond, &arg->lock);
+ long msec = arg->timeout;
+ if (msec == 0) {
+ arg->cancelled = 1;
+ arg->timedout = 1;
+ } else if (msec > 0) {
+ rb_native_cond_timedwait(&arg->cond, &arg->lock, msec);
+ if (!arg->done) {
+ arg->cancelled = 1;
+ arg->timedout = 1;
+ }
+ } else {
+ rb_native_cond_wait(&arg->cond, &arg->lock);
+ }
}
rb_nativethread_lock_unlock(&arg->lock);
return 0;
@@ -473,13 +499,49 @@ int
raddrinfo_pthread_create(pthread_t *th, void *(*start_routine) (void *), void *arg)
{
int limit = 3, ret;
+ int saved_errno;
+#ifdef HAVE_PTHREAD_ATTR_SETDETACHSTATE
+ pthread_attr_t attr;
+ pthread_attr_t *attr_p = &attr;
+ int err;
+ int init_retries = 0;
+ int init_retries_max = 3;
+retry_attr_init:
+ if ((err = pthread_attr_init(attr_p)) != 0) {
+ if (err == ENOMEM && init_retries < init_retries_max) {
+ init_retries++;
+ rb_gc();
+ goto retry_attr_init;
+ }
+ return err;
+ }
+ if ((err = pthread_attr_setdetachstate(attr_p, PTHREAD_CREATE_DETACHED)) != 0) {
+ saved_errno = errno;
+ pthread_attr_destroy(attr_p);
+ errno = saved_errno;
+ return err; // EINVAL - shouldn't happen
+ }
+#else
+ pthread_attr_t *attr_p = NULL;
+#endif
do {
// It is said that pthread_create may fail spuriously, so we follow the JDK and retry several times.
//
// https://bugs.openjdk.org/browse/JDK-8268605
// https://github.com/openjdk/jdk/commit/e35005d5ce383ddd108096a3079b17cb0bcf76f1
- ret = pthread_create(th, 0, start_routine, arg);
+ ret = pthread_create(th, attr_p, start_routine, arg);
} while (ret == EAGAIN && limit-- > 0);
+#ifdef HAVE_PTHREAD_ATTR_SETDETACHSTATE
+ saved_errno = errno;
+ pthread_attr_destroy(attr_p);
+ if (ret != 0) {
+ errno = saved_errno;
+ }
+#else
+ if (ret == 0) {
+ pthread_detach(th); // this can race with shutdown routine of thread in some glibc versions
+ }
+#endif
return ret;
}
@@ -490,16 +552,16 @@ fork_safe_do_getaddrinfo(void *ptr)
}
static int
-rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai)
+rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, int timeout)
{
int retry;
struct getaddrinfo_arg *arg;
- int err = 0, gai_errno = 0;
+ int err = 0, gai_errno = 0, timedout = 0;
start:
retry = 0;
- arg = allocate_getaddrinfo_arg(hostp, portp, hints);
+ arg = allocate_getaddrinfo_arg(hostp, portp, hints, timeout);
if (!arg) {
return EAI_MEMORY;
}
@@ -511,7 +573,6 @@ start:
errno = err;
return EAI_SYSTEM;
}
- pthread_detach(th);
rb_thread_call_without_gvl2(wait_getaddrinfo, arg, cancel_getaddrinfo, arg);
@@ -525,6 +586,7 @@ start:
}
else if (arg->cancelled) {
retry = 1;
+ timedout = arg->timedout;
}
else {
// If already interrupted, rb_thread_call_without_gvl2 may return without calling wait_getaddrinfo.
@@ -538,6 +600,16 @@ start:
if (need_free) free_getaddrinfo_arg(arg);
+ if (timedout) {
+ if (arg->ai) {
+ rsock_raise_user_specified_timeout(arg->ai, Qnil, Qnil);
+ } else {
+ VALUE host = rb_str_new_cstr(hostp);
+ VALUE port = rb_str_new_cstr(portp);
+ rsock_raise_user_specified_timeout(NULL, host, port);
+ }
+ }
+
// If the current thread is interrupted by asynchronous exception, the following raises the exception.
// But if the current thread is interrupted by timer thread, the following returns; we need to manually retry.
rb_thread_check_ints();
@@ -552,6 +624,10 @@ start:
#endif
+#define GETNAMEINFO_WONT_BLOCK(host, serv, flags) \
+ ((!(host) || ((flags) & NI_NUMERICHOST)) && \
+ (!(serv) || ((flags) & NI_NUMERICSERV)))
+
#if GETADDRINFO_IMPL == 0
int
@@ -559,7 +635,7 @@ rb_getnameinfo(const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen,
char *serv, size_t servlen, int flags)
{
- return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
+ return getnameinfo(sa, salen, host, (socklen_t)hostlen, serv, (socklen_t)servlen, flags);
}
#elif GETADDRINFO_IMPL == 1
@@ -589,6 +665,10 @@ rb_getnameinfo(const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen,
char *serv, size_t servlen, int flags)
{
+ if (GETNAMEINFO_WONT_BLOCK(host, serv, flags)) {
+ return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
+ }
+
struct getnameinfo_arg arg;
int ret;
arg.sa = sa;
@@ -715,7 +795,11 @@ rb_getnameinfo(const struct sockaddr *sa, socklen_t salen,
{
int retry;
struct getnameinfo_arg *arg;
- int err, gni_errno = 0;
+ int err = 0, gni_errno = 0;
+
+ if (GETNAMEINFO_WONT_BLOCK(host, serv, flags)) {
+ return getnameinfo(sa, salen, host, (socklen_t)hostlen, serv, (socklen_t)servlen, flags);
+ }
start:
retry = 0;
@@ -732,7 +816,6 @@ start:
errno = err;
return EAI_SYSTEM;
}
- pthread_detach(th);
rb_thread_call_without_gvl2(wait_getnameinfo, arg, cancel_getnameinfo, arg);
@@ -823,7 +906,7 @@ str_is_number(const char *p)
rb_strlen_lit(name) == (len) && memcmp(ptr, name, len) == 0)
char*
-host_str(VALUE host, char *hbuf, size_t hbuflen, int *flags_ptr)
+raddrinfo_host_str(VALUE host, char *hbuf, size_t hbuflen, int *flags_ptr)
{
if (NIL_P(host)) {
return NULL;
@@ -862,7 +945,7 @@ host_str(VALUE host, char *hbuf, size_t hbuflen, int *flags_ptr)
}
char*
-port_str(VALUE port, char *pbuf, size_t pbuflen, int *flags_ptr)
+raddrinfo_port_str(VALUE port, char *pbuf, size_t pbuflen, int *flags_ptr)
{
if (NIL_P(port)) {
return 0;
@@ -914,7 +997,7 @@ rb_scheduler_getaddrinfo(VALUE scheduler, VALUE host, const char *service,
for(i=0; i<len; i++) {
ip_address = rb_ary_entry(ip_addresses_array, i);
- hostp = host_str(ip_address, _hbuf, sizeof(_hbuf), &_additional_flags);
+ hostp = raddrinfo_host_str(ip_address, _hbuf, sizeof(_hbuf), &_additional_flags);
error = numeric_getaddrinfo(hostp, service, hints, &ai);
if (error == 0) {
if (!res_allocated) {
@@ -941,7 +1024,7 @@ rb_scheduler_getaddrinfo(VALUE scheduler, VALUE host, const char *service,
}
struct rb_addrinfo*
-rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack)
+rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack, VALUE timeout)
{
struct rb_addrinfo* res = NULL;
struct addrinfo *ai;
@@ -950,8 +1033,8 @@ rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_h
char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
int additional_flags = 0;
- hostp = host_str(host, hbuf, sizeof(hbuf), &additional_flags);
- portp = port_str(port, pbuf, sizeof(pbuf), &additional_flags);
+ hostp = raddrinfo_host_str(host, hbuf, sizeof(hbuf), &additional_flags);
+ portp = raddrinfo_port_str(port, pbuf, sizeof(pbuf), &additional_flags);
if (socktype_hack && hints->ai_socktype == 0 && str_is_number(portp)) {
hints->ai_socktype = SOCK_DGRAM;
@@ -976,7 +1059,8 @@ rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_h
}
if (!resolved) {
- error = rb_getaddrinfo(hostp, portp, hints, &ai);
+ int t = NIL_P(timeout) ? -1 : rsock_value_timeout_to_msec(timeout);
+ error = rb_getaddrinfo(hostp, portp, hints, &ai, t);
if (error == 0) {
res = (struct rb_addrinfo *)xmalloc(sizeof(struct rb_addrinfo));
res->allocated_by_malloc = 0;
@@ -1009,7 +1093,7 @@ rsock_fd_family(int fd)
}
struct rb_addrinfo*
-rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags)
+rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags, VALUE timeout)
{
struct addrinfo hints;
@@ -1017,7 +1101,7 @@ rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags)
hints.ai_family = family;
hints.ai_socktype = socktype;
hints.ai_flags = flags;
- return rsock_getaddrinfo(host, port, &hints, 1);
+ return rsock_getaddrinfo(host, port, &hints, 1, timeout);
}
VALUE
@@ -1137,7 +1221,7 @@ make_hostent_internal(VALUE v)
hostp = addr->ai_canonname;
}
else {
- hostp = host_str(host, hbuf, sizeof(hbuf), NULL);
+ hostp = raddrinfo_host_str(host, hbuf, sizeof(hbuf), NULL);
}
rb_ary_push(ary, rb_str_new2(hostp));
@@ -1211,6 +1295,7 @@ addrinfo_memsize(const void *ptr)
static const rb_data_type_t addrinfo_type = {
"socket/addrinfo",
{addrinfo_mark, addrinfo_free, addrinfo_memsize,},
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_WB_PROTECTED,
};
static VALUE
@@ -1248,7 +1333,7 @@ alloc_addrinfo(void)
}
static void
-init_addrinfo(rb_addrinfo_t *rai, struct sockaddr *sa, socklen_t len,
+init_addrinfo(VALUE self, rb_addrinfo_t *rai, struct sockaddr *sa, socklen_t len,
int pfamily, int socktype, int protocol,
VALUE canonname, VALUE inspectname)
{
@@ -1260,8 +1345,8 @@ init_addrinfo(rb_addrinfo_t *rai, struct sockaddr *sa, socklen_t len,
rai->pfamily = pfamily;
rai->socktype = socktype;
rai->protocol = protocol;
- rai->canonname = canonname;
- rai->inspectname = inspectname;
+ RB_OBJ_WRITE(self, &rai->canonname, canonname);
+ RB_OBJ_WRITE(self, &rai->inspectname, inspectname);
}
VALUE
@@ -1274,7 +1359,7 @@ rsock_addrinfo_new(struct sockaddr *addr, socklen_t len,
a = addrinfo_s_allocate(rb_cAddrinfo);
DATA_PTR(a) = rai = alloc_addrinfo();
- init_addrinfo(rai, addr, len, family, socktype, protocol, canonname, inspectname);
+ init_addrinfo(a, rai, addr, len, family, socktype, protocol, canonname, inspectname);
return a;
}
@@ -1299,7 +1384,7 @@ call_getaddrinfo(VALUE node, VALUE service,
hints.ai_flags = NUM2INT(flags);
}
- res = rsock_getaddrinfo(node, service, &hints, socktype_hack);
+ res = rsock_getaddrinfo(node, service, &hints, socktype_hack, timeout);
if (res == NULL)
rb_raise(rb_eSocket, "host not found");
@@ -1309,7 +1394,7 @@ call_getaddrinfo(VALUE node, VALUE service,
static VALUE make_inspectname(VALUE node, VALUE service, struct addrinfo *res);
static void
-init_addrinfo_getaddrinfo(rb_addrinfo_t *rai, VALUE node, VALUE service,
+init_addrinfo_getaddrinfo(VALUE self, rb_addrinfo_t *rai, VALUE node, VALUE service,
VALUE family, VALUE socktype, VALUE protocol, VALUE flags,
VALUE inspectnode, VALUE inspectservice)
{
@@ -1323,7 +1408,7 @@ init_addrinfo_getaddrinfo(rb_addrinfo_t *rai, VALUE node, VALUE service,
OBJ_FREEZE(canonname);
}
- init_addrinfo(rai, res->ai->ai_addr, res->ai->ai_addrlen,
+ init_addrinfo(self, rai, res->ai->ai_addr, res->ai->ai_addrlen,
NUM2INT(family), NUM2INT(socktype), NUM2INT(protocol),
canonname, inspectname);
@@ -1435,7 +1520,7 @@ addrinfo_list_new(VALUE node, VALUE service, VALUE family, VALUE socktype, VALUE
#ifdef HAVE_TYPE_STRUCT_SOCKADDR_UN
static void
-init_unix_addrinfo(rb_addrinfo_t *rai, VALUE path, int socktype)
+init_unix_addrinfo(VALUE self, rb_addrinfo_t *rai, VALUE path, int socktype)
{
struct sockaddr_un un;
socklen_t len;
@@ -1451,7 +1536,7 @@ init_unix_addrinfo(rb_addrinfo_t *rai, VALUE path, int socktype)
memcpy((void*)&un.sun_path, RSTRING_PTR(path), RSTRING_LEN(path));
len = rsock_unix_sockaddr_len(path);
- init_addrinfo(rai, (struct sockaddr *)&un, len,
+ init_addrinfo(self, rai, (struct sockaddr *)&un, len,
PF_UNIX, socktype, 0, Qnil, Qnil);
}
@@ -1555,7 +1640,7 @@ addrinfo_initialize(int argc, VALUE *argv, VALUE self)
flags |= AI_NUMERICSERV;
#endif
- init_addrinfo_getaddrinfo(rai, numericnode, service,
+ init_addrinfo_getaddrinfo(self, rai, numericnode, service,
INT2NUM(i_pfamily ? i_pfamily : af), INT2NUM(i_socktype), INT2NUM(i_protocol),
INT2NUM(flags),
nodename, service);
@@ -1567,7 +1652,7 @@ addrinfo_initialize(int argc, VALUE *argv, VALUE self)
{
VALUE path = rb_ary_entry(sockaddr_ary, 1);
StringValue(path);
- init_unix_addrinfo(rai, path, SOCK_STREAM);
+ init_unix_addrinfo(self, rai, path, SOCK_STREAM);
break;
}
#endif
@@ -1580,7 +1665,7 @@ addrinfo_initialize(int argc, VALUE *argv, VALUE self)
StringValue(sockaddr_arg);
sockaddr_ptr = (struct sockaddr *)RSTRING_PTR(sockaddr_arg);
sockaddr_len = RSTRING_SOCKLEN(sockaddr_arg);
- init_addrinfo(rai, sockaddr_ptr, sockaddr_len,
+ init_addrinfo(self, rai, sockaddr_ptr, sockaddr_len,
i_pfamily, i_socktype, i_protocol,
canonname, inspectname);
}
@@ -2169,7 +2254,7 @@ addrinfo_mload(VALUE self, VALUE ary)
}
DATA_PTR(self) = rai = alloc_addrinfo();
- init_addrinfo(rai, &ss.addr, len,
+ init_addrinfo(self, rai, &ss.addr, len,
pfamily, socktype, protocol,
canonname, inspectname);
return self;
@@ -2937,7 +3022,7 @@ addrinfo_s_unix(int argc, VALUE *argv, VALUE self)
addr = addrinfo_s_allocate(rb_cAddrinfo);
DATA_PTR(addr) = rai = alloc_addrinfo();
- init_unix_addrinfo(rai, path, socktype);
+ init_unix_addrinfo(self, rai, path, socktype);
return addr;
}
@@ -3038,22 +3123,13 @@ free_fast_fallback_getaddrinfo_shared(struct fast_fallback_getaddrinfo_shared **
*shared = NULL;
}
-void
-free_fast_fallback_getaddrinfo_entry(struct fast_fallback_getaddrinfo_entry **entry)
-{
- if ((*entry)->ai) {
- freeaddrinfo((*entry)->ai);
- (*entry)->ai = NULL;
- }
- *entry = NULL;
-}
-
static void *
do_fast_fallback_getaddrinfo(void *ptr)
{
struct fast_fallback_getaddrinfo_entry *entry = (struct fast_fallback_getaddrinfo_entry *)ptr;
struct fast_fallback_getaddrinfo_shared *shared = entry->shared;
- int err = 0, need_free = 0, shared_need_free = 0;
+ int err = 0, shared_need_free = 0;
+ struct addrinfo *ai = NULL;
sigset_t set;
sigemptyset(&set);
@@ -3102,14 +3178,15 @@ do_fast_fallback_getaddrinfo(void *ptr)
entry->err = errno;
entry->has_syserr = true;
}
- if (--(entry->refcount) == 0) need_free = 1;
+ if (--(entry->refcount) == 0) {
+ ai = entry->ai;
+ entry->ai = NULL;
+ }
if (--(shared->refcount) == 0) shared_need_free = 1;
}
rb_nativethread_lock_unlock(&shared->lock);
- if (need_free && entry) {
- free_fast_fallback_getaddrinfo_entry(&entry);
- }
+ if (ai) freeaddrinfo(ai);
if (shared_need_free && shared) {
free_fast_fallback_getaddrinfo_shared(&shared);
}
diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h
index 92e0f2604d..2ec3ab335a 100644
--- a/ext/socket/rubysocket.h
+++ b/ext/socket/rubysocket.h
@@ -292,8 +292,8 @@ extern VALUE rb_eResolution;
#ifdef SOCKS
extern VALUE rb_cSOCKSSocket;
# ifndef SOCKS5
-void SOCKSinit();
-int Rconnect();
+void SOCKSinit(char *);
+int Rconnect(int, const struct sockaddr *, socklen_t);
# endif
#endif
@@ -327,8 +327,8 @@ void rb_freeaddrinfo(struct rb_addrinfo *ai);
VALUE rsock_freeaddrinfo(VALUE arg);
int rb_getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);
int rsock_fd_family(int fd);
-struct rb_addrinfo *rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags);
-struct rb_addrinfo *rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack);
+struct rb_addrinfo *rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags, VALUE timeout);
+struct rb_addrinfo *rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack, VALUE timeout);
VALUE rsock_fd_socket_addrinfo(int fd, struct sockaddr *addr, socklen_t len);
VALUE rsock_io_socket_addrinfo(VALUE io, struct sockaddr *addr, socklen_t len);
@@ -355,7 +355,7 @@ int rsock_socket(int domain, int type, int proto);
int rsock_detect_cloexec(int fd);
VALUE rsock_init_sock(VALUE sock, int fd);
VALUE rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass);
-VALUE rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type, VALUE resolv_timeout, VALUE connect_timeout, VALUE fast_fallback, VALUE test_mode_settings);
+VALUE rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type, VALUE resolv_timeout, VALUE connect_timeout, VALUE open_timeout, VALUE fast_fallback, VALUE test_mode_settings);
VALUE rsock_init_unixsock(VALUE sock, VALUE path, int server);
struct rsock_send_arg {
@@ -414,8 +414,8 @@ ssize_t rsock_recvmsg(int socket, struct msghdr *message, int flags);
void rsock_discard_cmsg_resource(struct msghdr *mh, int msg_peek_p);
#endif
-char *host_str(VALUE host, char *hbuf, size_t hbuflen, int *flags_ptr);
-char *port_str(VALUE port, char *pbuf, size_t pbuflen, int *flags_ptr);
+char *raddrinfo_host_str(VALUE host, char *hbuf, size_t hbuflen, int *flags_ptr);
+char *raddrinfo_port_str(VALUE port, char *pbuf, size_t pbuflen, int *flags_ptr);
#ifndef FAST_FALLBACK_INIT_INETSOCK_IMPL
# if !defined(HAVE_PTHREAD_CREATE) || !defined(HAVE_PTHREAD_DETACH) || defined(__MINGW32__) || defined(__MINGW64__)
@@ -453,6 +453,8 @@ void free_fast_fallback_getaddrinfo_shared(struct fast_fallback_getaddrinfo_shar
# endif
#endif
+NORETURN(void rsock_raise_user_specified_timeout(struct addrinfo *ai, VALUE host, VALUE port));
+
void rsock_init_basicsocket(void);
void rsock_init_ipsocket(void);
void rsock_init_tcpsocket(void);
@@ -507,8 +509,6 @@ extern ID tcp_fast_fallback;
const char *inet_ntop(int, const void *, char *, size_t);
#elif defined __MINGW32__
# define inet_ntop(f,a,n,l) rb_w32_inet_ntop(f,a,n,l)
-#elif defined _MSC_VER && RUBY_MSVCRT_VERSION < 90
-const char *WSAAPI inet_ntop(int, const void *, char *, size_t);
#endif
#endif
diff --git a/ext/socket/socket.c b/ext/socket/socket.c
index 8f593ca0bd..a8e5ae8119 100644
--- a/ext/socket/socket.c
+++ b/ext/socket/socket.c
@@ -965,7 +965,7 @@ sock_s_gethostbyname(VALUE obj, VALUE host)
{
rb_warn("Socket.gethostbyname is deprecated; use Addrinfo.getaddrinfo instead.");
struct rb_addrinfo *res =
- rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME);
+ rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME, Qnil);
return rsock_make_hostent(host, res, sock_sockaddr);
}
@@ -1183,7 +1183,7 @@ sock_s_getaddrinfo(int argc, VALUE *argv, VALUE _)
norevlookup = rsock_do_not_reverse_lookup;
}
- res = rsock_getaddrinfo(host, port, &hints, 0);
+ res = rsock_getaddrinfo(host, port, &hints, 0, Qnil);
ret = make_addrinfo(res, norevlookup);
rb_freeaddrinfo(res);
@@ -1279,7 +1279,7 @@ sock_s_getnameinfo(int argc, VALUE *argv, VALUE _)
hints.ai_socktype = (fl & NI_DGRAM) ? SOCK_DGRAM : SOCK_STREAM;
/* af */
hints.ai_family = NIL_P(af) ? PF_UNSPEC : rsock_family_arg(af);
- res = rsock_getaddrinfo(host, port, &hints, 0);
+ res = rsock_getaddrinfo(host, port, &hints, 0, Qnil);
sap = res->ai->ai_addr;
salen = res->ai->ai_addrlen;
}
@@ -1335,7 +1335,7 @@ sock_s_getnameinfo(int argc, VALUE *argv, VALUE _)
static VALUE
sock_s_pack_sockaddr_in(VALUE self, VALUE port, VALUE host)
{
- struct rb_addrinfo *res = rsock_addrinfo(host, port, AF_UNSPEC, 0, 0);
+ struct rb_addrinfo *res = rsock_addrinfo(host, port, AF_UNSPEC, 0, 0, Qnil);
VALUE addr = rb_str_new((char*)res->ai->ai_addr, res->ai->ai_addrlen);
rb_freeaddrinfo(res);
diff --git a/ext/socket/sockssocket.c b/ext/socket/sockssocket.c
index 1031812bef..30860ea257 100644
--- a/ext/socket/sockssocket.c
+++ b/ext/socket/sockssocket.c
@@ -30,11 +30,12 @@ socks_init(VALUE sock, VALUE host, VALUE port)
static int init = 0;
if (init == 0) {
- SOCKSinit("ruby");
+ char progname[] = "ruby";
+ SOCKSinit(progname);
init = 1;
}
- return rsock_init_inetsock(sock, host, port, Qnil, Qnil, INET_SOCKS, Qnil, Qnil, Qfalse, Qnil);
+ return rsock_init_inetsock(sock, host, port, Qnil, Qnil, INET_SOCKS, Qnil, Qnil, Qnil, Qfalse, Qnil);
}
#ifdef SOCKS5
diff --git a/ext/socket/tcpserver.c b/ext/socket/tcpserver.c
index 8206fe46a9..0069f3c703 100644
--- a/ext/socket/tcpserver.c
+++ b/ext/socket/tcpserver.c
@@ -36,7 +36,7 @@ tcp_svr_init(int argc, VALUE *argv, VALUE sock)
VALUE hostname, port;
rb_scan_args(argc, argv, "011", &hostname, &port);
- return rsock_init_inetsock(sock, hostname, port, Qnil, Qnil, INET_SERVER, Qnil, Qnil, Qfalse, Qnil);
+ return rsock_init_inetsock(sock, hostname, port, Qnil, Qnil, INET_SERVER, Qnil, Qnil, Qnil, Qfalse, Qnil);
}
/*
diff --git a/ext/socket/tcpsocket.c b/ext/socket/tcpsocket.c
index 28527f632f..7ce536e0af 100644
--- a/ext/socket/tcpsocket.c
+++ b/ext/socket/tcpsocket.c
@@ -12,7 +12,7 @@
/*
* call-seq:
- * TCPSocket.new(remote_host, remote_port, local_host=nil, local_port=nil, resolv_timeout: nil, connect_timeout: nil, fast_fallback: true)
+ * TCPSocket.new(remote_host, remote_port, local_host=nil, local_port=nil, resolv_timeout: nil, connect_timeout: nil, open_timeout: nil, fast_fallback: true)
*
* Opens a TCP connection to +remote_host+ on +remote_port+. If +local_host+
* and +local_port+ are specified, then those parameters are used on the local
@@ -35,6 +35,7 @@
*
* [:resolv_timeout] Specifies the timeout in seconds from when the hostname resolution starts.
* [:connect_timeout] This method sequentially attempts connecting to all candidate destination addresses.<br>The +connect_timeout+ specifies the timeout in seconds from the start of the connection attempt to the last candidate.<br>By default, all connection attempts continue until the timeout occurs.<br>When +fast_fallback:false+ is explicitly specified,<br>a timeout is set for each connection attempt and any connection attempt that exceeds its timeout will be canceled.
+ * [:open_timeout] Specifies the timeout in seconds from the start of the method execution.<br>If this timeout is reached while there are still addresses that have not yet been attempted for connection, no further attempts will be made.<br>If this option is specified together with other timeout options, an +ArgumentError+ will be raised.
* [:fast_fallback] Enables the Happy Eyeballs Version 2 algorithm (enabled by default).
*/
static VALUE
@@ -43,29 +44,32 @@ tcp_init(int argc, VALUE *argv, VALUE sock)
VALUE remote_host, remote_serv;
VALUE local_host, local_serv;
VALUE opt;
- static ID keyword_ids[4];
- VALUE kwargs[4];
+ static ID keyword_ids[5];
+ VALUE kwargs[5];
VALUE resolv_timeout = Qnil;
VALUE connect_timeout = Qnil;
+ VALUE open_timeout = Qnil;
VALUE fast_fallback = Qnil;
VALUE test_mode_settings = Qnil;
if (!keyword_ids[0]) {
CONST_ID(keyword_ids[0], "resolv_timeout");
CONST_ID(keyword_ids[1], "connect_timeout");
- CONST_ID(keyword_ids[2], "fast_fallback");
- CONST_ID(keyword_ids[3], "test_mode_settings");
+ CONST_ID(keyword_ids[2], "open_timeout");
+ CONST_ID(keyword_ids[3], "fast_fallback");
+ CONST_ID(keyword_ids[4], "test_mode_settings");
}
rb_scan_args(argc, argv, "22:", &remote_host, &remote_serv,
&local_host, &local_serv, &opt);
if (!NIL_P(opt)) {
- rb_get_kwargs(opt, keyword_ids, 0, 4, kwargs);
+ rb_get_kwargs(opt, keyword_ids, 0, 5, kwargs);
if (kwargs[0] != Qundef) { resolv_timeout = kwargs[0]; }
if (kwargs[1] != Qundef) { connect_timeout = kwargs[1]; }
- if (kwargs[2] != Qundef) { fast_fallback = kwargs[2]; }
- if (kwargs[3] != Qundef) { test_mode_settings = kwargs[3]; }
+ if (kwargs[2] != Qundef) { open_timeout = kwargs[2]; }
+ if (kwargs[3] != Qundef) { fast_fallback = kwargs[3]; }
+ if (kwargs[4] != Qundef) { test_mode_settings = kwargs[4]; }
}
if (fast_fallback == Qnil) {
@@ -75,8 +79,8 @@ tcp_init(int argc, VALUE *argv, VALUE sock)
return rsock_init_inetsock(sock, remote_host, remote_serv,
local_host, local_serv, INET_CLIENT,
- resolv_timeout, connect_timeout, fast_fallback,
- test_mode_settings);
+ resolv_timeout, connect_timeout, open_timeout,
+ fast_fallback, test_mode_settings);
}
static VALUE
@@ -109,7 +113,7 @@ tcp_s_gethostbyname(VALUE obj, VALUE host)
{
rb_warn("TCPSocket.gethostbyname is deprecated; use Addrinfo.getaddrinfo instead.");
struct rb_addrinfo *res =
- rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME);
+ rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME, Qnil);
return rsock_make_hostent(host, res, tcp_sockaddr);
}
diff --git a/ext/socket/udpsocket.c b/ext/socket/udpsocket.c
index a984933c9f..b2bc925538 100644
--- a/ext/socket/udpsocket.c
+++ b/ext/socket/udpsocket.c
@@ -84,7 +84,7 @@ udp_connect(VALUE self, VALUE host, VALUE port)
{
struct udp_arg arg = {.io = self};
- arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0);
+ arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0, Qnil);
int result = (int)rb_ensure(udp_connect_internal, (VALUE)&arg, rsock_freeaddrinfo, (VALUE)arg.res);
if (!result) {
@@ -129,7 +129,7 @@ udp_bind(VALUE self, VALUE host, VALUE port)
{
struct udp_arg arg = {.io = self};
- arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0);
+ arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0, Qnil);
VALUE result = rb_ensure(udp_bind_internal, (VALUE)&arg, rsock_freeaddrinfo, (VALUE)arg.res);
if (!result) {
@@ -212,7 +212,7 @@ udp_send(int argc, VALUE *argv, VALUE sock)
GetOpenFile(sock, arg.fptr);
arg.sarg.fd = arg.fptr->fd;
arg.sarg.flags = NUM2INT(flags);
- arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0);
+ arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0, Qnil);
ret = rb_ensure(udp_send_internal, (VALUE)&arg,
rsock_freeaddrinfo, (VALUE)arg.res);
if (!ret) rsock_sys_fail_host_port("sendto(2)", host, port);
diff --git a/ext/socket/unixsocket.c b/ext/socket/unixsocket.c
index 31e2acee04..2ec9376074 100644
--- a/ext/socket/unixsocket.c
+++ b/ext/socket/unixsocket.c
@@ -42,11 +42,12 @@ unixsock_path_value(VALUE path)
}
}
#endif
+ path = rb_get_path(path);
#ifdef _WIN32
/* UNIXSocket requires UTF-8 per spec. */
path = rb_str_export_to_enc(path, rb_utf8_encoding());
#endif
- return rb_get_path(path);
+ return path;
}
VALUE