1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
require 'socket'
module SocketSpecs
# helper to get the hostname associated to 127.0.0.1
def self.hostname
# Calculate each time, without caching, since the result might
# depend on things like do_not_reverse_lookup mode, which is
# changing from test to test
Socket.getaddrinfo("127.0.0.1", nil)[0][2]
end
def self.hostnamev6
Socket.getaddrinfo("::1", nil)[0][2]
end
def self.addr(which=:ipv4)
case which
when :ipv4
host = "127.0.0.1"
when :ipv6
host = "::1"
end
Socket.getaddrinfo(host, nil)[0][3]
end
def self.find_available_port
begin
s = TCPServer.open(0)
port = s.addr[1]
s.close
port
rescue
43191
end
end
def self.port
@@_port ||= find_available_port
end
def self.str_port
port.to_s
end
def self.local_port
find_available_port
end
def self.reserved_unused_port
# https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers
0
end
def self.sockaddr_in(port, host)
Socket::SockAddr_In.new(Socket.sockaddr_in(port, host))
end
def self.socket_path
path = tmp("unix.sock", false)
# Check for too long unix socket path (max 108 bytes including \0 => 107)
# Note that Linux accepts not null-terminated paths but the man page advises against it.
if path.bytesize > 107
path = "/tmp/unix_server_spec.socket"
end
rm_socket(path)
path
end
def self.rm_socket(path)
File.delete(path) if File.exist?(path)
end
# TCPServer echo server accepting one connection
class SpecTCPServer
attr_accessor :hostname, :port, :logger
def initialize(host=nil, port=nil, logger=nil)
@hostname = host || SocketSpecs.hostname
@port = port || SocketSpecs.port
@logger = logger
start
end
def start
log "SpecTCPServer starting on #{@hostname}:#{@port}"
@server = TCPServer.new @hostname, @port
@thread = Thread.new do
socket = @server.accept
log "SpecTCPServer accepted connection: #{socket}"
service socket
end
self
end
def service(socket)
begin
data = socket.recv(1024)
return if data.empty?
log "SpecTCPServer received: #{data.inspect}"
return if data == "QUIT"
socket.send data, 0
ensure
socket.close
end
end
def shutdown
log "SpecTCPServer shutting down"
@thread.join
@server.close
end
def log(message)
@logger.puts message if @logger
end
end
end
|