Feature #6583 ยป socket.improve_bind_error.patch
ext/socket/udpsocket.c (working copy) | ||
---|---|---|
112 | 112 |
static VALUE |
113 | 113 |
udp_bind(VALUE sock, VALUE host, VALUE port) |
114 | 114 |
{ |
115 |
VALUE mesg; |
|
115 | 116 |
rb_io_t *fptr; |
116 | 117 |
struct addrinfo *res0, *res; |
117 | 118 | |
... | ... | |
126 | 127 |
return INT2FIX(0); |
127 | 128 |
} |
128 | 129 |
freeaddrinfo(res0); |
129 |
rb_sys_fail("bind(2)"); |
|
130 | ||
131 |
port = rb_String(port); |
|
132 |
mesg = rb_sprintf("bind(2) for \"%s\" port %s", |
|
133 |
StringValueCStr(host), |
|
134 |
StringValueCStr(port)); |
|
135 |
rb_sys_fail_str(mesg); |
|
136 | ||
130 | 137 |
return INT2FIX(0); |
131 | 138 |
} |
132 | 139 |
ext/socket/ipsocket.c (working copy) | ||
---|---|---|
43 | 43 |
{ |
44 | 44 |
int type = arg->type; |
45 | 45 |
struct addrinfo *res; |
46 |
int fd, status = 0; |
|
46 |
int fd, status = 0, local = 0;
|
|
47 | 47 |
const char *syscall = 0; |
48 | 48 | |
49 | 49 |
arg->remote.res = rsock_addrinfo(arg->remote.host, arg->remote.serv, SOCK_STREAM, |
... | ... | |
81 | 81 |
else { |
82 | 82 |
if (arg->local.res) { |
83 | 83 |
status = bind(fd, arg->local.res->ai_addr, arg->local.res->ai_addrlen); |
84 |
local = status; |
|
84 | 85 |
syscall = "bind(2)"; |
85 | 86 |
} |
86 | 87 | |
... | ... | |
99 | 100 |
break; |
100 | 101 |
} |
101 | 102 |
if (status < 0) { |
102 |
rb_sys_fail(syscall); |
|
103 |
VALUE host, port, mesg; |
|
104 |
const char * local_mesg; |
|
105 | ||
106 |
if (local < 0) { |
|
107 |
host = arg->local.host; |
|
108 |
port = rb_String(arg->local.serv); |
|
109 |
local_mesg = " (local address)"; |
|
110 |
} else { |
|
111 |
host = arg->remote.host; |
|
112 |
port = rb_String(arg->remote.serv); |
|
113 |
local_mesg = ""; |
|
114 |
} |
|
115 | ||
116 |
mesg = rb_sprintf("%s for \"%s\" port %s%s", |
|
117 |
syscall, StringValuePtr(host), StringValuePtr(port), |
|
118 |
local_mesg); |
|
119 | ||
120 |
rb_sys_fail_str(mesg); |
|
103 | 121 |
} |
104 | 122 | |
105 | 123 |
arg->fd = -1; |
ext/socket/socket.c (working copy) | ||
---|---|---|
10 | 10 | |
11 | 11 |
#include "rubysocket.h" |
12 | 12 | |
13 |
static VALUE sock_s_unpack_sockaddr_in(VALUE, VALUE); |
|
14 | ||
13 | 15 |
static void |
14 | 16 |
setup_domain_and_type(VALUE domain, int *dv, VALUE type, int *tv) |
15 | 17 |
{ |
... | ... | |
467 | 469 | |
468 | 470 |
SockAddrStringValue(addr); |
469 | 471 |
GetOpenFile(sock, fptr); |
470 |
if (bind(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_LENINT(addr)) < 0) |
|
471 |
rb_sys_fail("bind(2)"); |
|
472 |
if (bind(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_LENINT(addr)) < 0) { |
|
473 |
VALUE host_port = sock_s_unpack_sockaddr_in(sock, addr); |
|
474 |
VALUE mesg = rb_sprintf("bind(2) for \"%s\" port %d", |
|
475 |
StringValueCStr(RARRAY_PTR(host_port)[1]), |
|
476 |
NUM2INT(RARRAY_PTR(host_port)[0])); |
|
477 | ||
478 |
rb_sys_fail_str(mesg); |
|
479 |
} |
|
472 | 480 | |
473 | 481 |
return INT2FIX(0); |
474 | 482 |
} |
test/socket/test_tcp.rb (working copy) | ||
---|---|---|
6 | 6 | |
7 | 7 | |
8 | 8 |
class TestSocket_TCPSocket < Test::Unit::TestCase |
9 |
def test_initialize_failure |
|
10 |
s = TCPServer.new("localhost", nil) |
|
11 |
server_port = s.addr[1] |
|
12 | ||
13 |
c = TCPSocket.new("localhost", server_port) |
|
14 |
client_port = c.addr[1] |
|
15 | ||
16 |
begin |
|
17 |
# TCPServer.new uses SO_REUSEADDR so we must create a failure on the |
|
18 |
# local address. |
|
19 |
TCPSocket.new("localhost", server_port, "localhost", client_port) |
|
20 |
flunk "expected SystemCallError" |
|
21 |
rescue SystemCallError => e |
|
22 |
assert_match "for \"localhost\" port #{client_port}", e.message |
|
23 |
end |
|
24 |
end |
|
25 | ||
9 | 26 |
def test_recvfrom |
10 | 27 |
svr = TCPServer.new("localhost", 0) |
11 | 28 |
th = Thread.new { |
test/socket/test_socket.rb (working copy) | ||
---|---|---|
70 | 70 |
} |
71 | 71 |
end |
72 | 72 | |
73 |
def test_bind |
|
74 |
Socket.open(Socket::AF_INET, Socket::SOCK_STREAM, 0) {|bound| |
|
75 |
bound.bind(Socket.sockaddr_in(0, "127.0.0.1")) |
|
76 |
addr = bound.getsockname |
|
77 |
port, = Socket.unpack_sockaddr_in(addr) |
|
78 | ||
79 |
Socket.open(Socket::AF_INET, Socket::SOCK_STREAM, 0) {|s| |
|
80 |
e = assert_raises(Errno::EADDRINUSE) do |
|
81 |
s.bind(Socket.sockaddr_in(port, "127.0.0.1")) |
|
82 |
end |
|
83 | ||
84 |
assert_match "bind(2) for \"127.0.0.1\" port #{port}", e.message |
|
85 |
} |
|
86 |
} |
|
87 |
end |
|
88 | ||
73 | 89 |
def test_getaddrinfo |
74 | 90 |
# This should not send a DNS query because AF_UNIX. |
75 | 91 |
assert_raise(SocketError) { Socket.getaddrinfo("www.kame.net", 80, "AF_UNIX") } |
test/socket/test_udp.rb (working copy) | ||
---|---|---|
36 | 36 |
s.bind(host, 2000) |
37 | 37 |
} |
38 | 38 |
end |
39 | ||
40 |
def test_bind_addrinuse |
|
41 |
host = "127.0.0.1" |
|
42 |
port = 2001 |
|
43 | ||
44 |
in_use = UDPSocket.new |
|
45 |
in_use.bind(host, port) |
|
46 | ||
47 |
s = UDPSocket.new |
|
48 |
|
|
49 |
e = assert_raises(Errno::EADDRINUSE) do |
|
50 |
s.bind(host, port) |
|
51 |
end |
|
52 | ||
53 |
assert_match "bind(2) for \"#{host}\" port #{port}", e.message |
|
54 |
end |
|
39 | 55 |
end if defined?(UDPSocket) |