Project

General

Profile

Feature #6583 ยป socket.improve_bind_error.patch

drbrain (Eric Hodel), 06/13/2012 11:42 AM

View differences:

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)