summaryrefslogtreecommitdiff
path: root/spec/ruby/library/socket/socket/connect_nonblock_spec.rb
blob: 21ef2b4a9403d0f206677d66acc215ac8f464ce6 (plain)
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
require_relative '../spec_helper'
require_relative '../fixtures/classes'

describe "Socket#connect_nonblock" do
  before :each do
    @hostname = "127.0.0.1"
    @server = TCPServer.new(@hostname, 0) # started, but no accept
    @addr = Socket.sockaddr_in(@server.addr[1], @hostname)
    @socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
    @thread = nil
  end

  after :each do
    @socket.close
    @server.close
    @thread.join if @thread
  end

  it "connects the socket to the remote side" do
    port = nil
    accept = false
    @thread = Thread.new do
      server = TCPServer.new(@hostname, 0)
      port = server.addr[1]
      Thread.pass until accept
      conn = server.accept
      conn << "hello!"
      conn.close
      server.close
    end

    Thread.pass until port

    addr = Socket.sockaddr_in(port, @hostname)
    begin
      @socket.connect_nonblock(addr)
    rescue Errno::EINPROGRESS
    end

    accept = true
    IO.select nil, [@socket]

    begin
      @socket.connect_nonblock(addr)
    rescue Errno::EISCONN
      # Not all OS's use this errno, so we trap and ignore it
    end

    @socket.read(6).should == "hello!"
  end

  platform_is_not :freebsd, :solaris, :aix do
    it "raises Errno::EINPROGRESS when the connect would block" do
      lambda do
        @socket.connect_nonblock(@addr)
      end.should raise_error(Errno::EINPROGRESS)
    end

    it "raises Errno::EINPROGRESS with IO::WaitWritable mixed in when the connect would block" do
      lambda do
        @socket.connect_nonblock(@addr)
      end.should raise_error(IO::WaitWritable)
    end

    it "returns :wait_writable in exceptionless mode when the connect would block" do
      @socket.connect_nonblock(@addr, exception: false).should == :wait_writable
    end
  end
end

describe 'Socket#connect_nonblock' do
  SocketSpecs.each_ip_protocol do |family, ip_address|
    describe 'using a DGRAM socket' do
      before do
        @server   = Socket.new(family, :DGRAM)
        @client   = Socket.new(family, :DGRAM)
        @sockaddr = Socket.sockaddr_in(0, ip_address)

        @server.bind(@sockaddr)
      end

      after do
        @client.close
        @server.close
      end

      it 'returns 0 when successfully connected using a String' do
        @client.connect_nonblock(@server.getsockname).should == 0
      end

      it 'returns 0 when successfully connected using an Addrinfo' do
        @client.connect_nonblock(@server.connect_address).should == 0
      end

      it 'raises TypeError when passed a Fixnum' do
        lambda { @client.connect_nonblock(666) }.should raise_error(TypeError)
      end
    end

    describe 'using a STREAM socket' do
      before do
        @server   = Socket.new(family, :STREAM)
        @client   = Socket.new(family, :STREAM)
        @sockaddr = Socket.sockaddr_in(0, ip_address)
      end

      after do
        @client.close
        @server.close
      end

      it 'raises IO:EINPROGRESSWaitWritable when the connection would block' do
        @server.bind(@sockaddr)

        lambda {
          @client.connect_nonblock(@server.getsockname)
        }.should raise_error(IO::EINPROGRESSWaitWritable)
      end
    end
  end
end