summaryrefslogtreecommitdiff
path: root/spec/ruby/library/socket/socket/bind_spec.rb
blob: 4465a3dafacb5b27b748b0114af438a590a3386b (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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
require_relative '../spec_helper'
require_relative '../fixtures/classes'

describe "Socket#bind on SOCK_DGRAM socket" do
  before :each do
    @sock = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0)
    @sockaddr = Socket.pack_sockaddr_in(0, "127.0.0.1")
  end

  after :each do
    @sock.closed?.should be_false
    @sock.close
  end

  it "binds to a port" do
    -> { @sock.bind(@sockaddr) }.should_not raise_error
  end

  it "returns 0 if successful" do
    @sock.bind(@sockaddr).should == 0
  end

  it "raises Errno::EINVAL when already bound" do
    @sock.bind(@sockaddr)

    -> { @sock.bind(@sockaddr) }.should raise_error(Errno::EINVAL)
  end

  it "raises Errno::EADDRNOTAVAIL when the specified sockaddr is not available from the local machine" do
    sockaddr1 = Socket.pack_sockaddr_in(0, "4.3.2.1")
    -> { @sock.bind(sockaddr1) }.should raise_error(Errno::EADDRNOTAVAIL)
  end

  platform_is_not :windows, :cygwin do
    as_user do
      break if File.read('/proc/sys/net/ipv4/ip_unprivileged_port_start').to_i <= 1 rescue nil
      it "raises Errno::EACCES when the current user does not have permission to bind" do
        sockaddr1 = Socket.pack_sockaddr_in(1, "127.0.0.1")
        -> { @sock.bind(sockaddr1) }.should raise_error(Errno::EACCES)
      end
    end
  end
end

describe "Socket#bind on SOCK_STREAM socket" do
  before :each do
    @sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
    @sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
    @sockaddr = Socket.pack_sockaddr_in(0, "127.0.0.1")
  end

  after :each do
    @sock.closed?.should be_false
    @sock.close
  end

  it "binds to a port" do
    -> { @sock.bind(@sockaddr) }.should_not raise_error
  end

  it "returns 0 if successful" do
    @sock.bind(@sockaddr).should == 0
  end

  it "raises Errno::EINVAL when already bound" do
    @sock.bind(@sockaddr)

    -> { @sock.bind(@sockaddr) }.should raise_error(Errno::EINVAL)
  end

  it "raises Errno::EADDRNOTAVAIL when the specified sockaddr is not available from the local machine" do
    sockaddr1 = Socket.pack_sockaddr_in(0, "4.3.2.1")
    -> { @sock.bind(sockaddr1) }.should raise_error(Errno::EADDRNOTAVAIL)
  end

  platform_is_not :windows, :cygwin do
    as_user do
      break if File.read('/proc/sys/net/ipv4/ip_unprivileged_port_start').to_i <= 1 rescue nil
      it "raises Errno::EACCES when the current user does not have permission to bind" do
        sockaddr1 = Socket.pack_sockaddr_in(1, "127.0.0.1")
        -> { @sock.bind(sockaddr1) }.should raise_error(Errno::EACCES)
      end
    end
  end
end

describe 'Socket#bind' do
  SocketSpecs.each_ip_protocol do |family, ip_address|
    describe 'using a packed socket address' do
      before do
        @socket = Socket.new(family, :DGRAM)
        @sockaddr = Socket.sockaddr_in(0, ip_address)
      end

      after do
        @socket.close
      end

      it 'returns 0 when successfully bound' do
        @socket.bind(@sockaddr).should == 0
      end

      it 'raises Errno::EINVAL when binding to an already bound port' do
        @socket.bind(@sockaddr)

        -> { @socket.bind(@sockaddr) }.should raise_error(Errno::EINVAL)
      end

      it 'raises Errno::EADDRNOTAVAIL when the specified sockaddr is not available' do
        ip = family == Socket::AF_INET ? '4.3.2.1' : '::2'
        sockaddr1 = Socket.sockaddr_in(0, ip)

        -> { @socket.bind(sockaddr1) }.should raise_error(Errno::EADDRNOTAVAIL)
      end

      platform_is_not :windows do
        as_user do
          break if File.read('/proc/sys/net/ipv4/ip_unprivileged_port_start').to_i <= 1 rescue nil

          it 'raises Errno::EACCES when the user is not allowed to bind to the port' do
            sockaddr1 = Socket.pack_sockaddr_in(1, ip_address)

            -> { @socket.bind(sockaddr1) }.should raise_error(Errno::EACCES)
          end
       end
      end
    end

    describe 'using an Addrinfo' do
      before do
        @addr   = Addrinfo.udp(ip_address, 0)
        @socket = Socket.new(@addr.afamily, @addr.socktype)
      end

      after do
        @socket.close
      end

      it 'binds to an Addrinfo' do
        @socket.bind(@addr).should == 0
        @socket.local_address.should be_an_instance_of(Addrinfo)
      end

      it 'uses a new Addrinfo for the local address' do
        @socket.bind(@addr)
        @socket.local_address.should_not == @addr
      end
    end
  end
end