UDPSocket broadcast to 127.0.0.255

J

Joel VanderWerf

Is my network stack screwy, or is there something strange about
UDPSockets in ruby when broadcasting to 127.0.0.255?


irb(main):001:0> require 'socket'
=> true
irb(main):002:0> s = UDPSocket.open
=> #<UDPSocket:0xb7d5f9cc>
irb(main):003:0> s.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST,
true)
=> 0
irb(main):004:0> s.connect '127.0.0.255', 12345
=> 0
irb(main):005:0> s.send "foo", 0
=> 3
irb(main):006:0> s.send "foo", 0
Errno::ECONNREFUSED: Connection refused - send(2)
from (irb):6:in `send'
from (irb):6
irb(main):007:0> s.send "foo", 0
=> 3
irb(main):008:0> s.send "foo", 0
Errno::ECONNREFUSED: Connection refused - send(2)
from (irb):8:in `send'
from (irb):8
irb(main):009:0> s.send "foo", 0
=> 3
irb(main):010:0> s.send "foo", 0
Errno::ECONNREFUSED: Connection refused - send(2)
from (irb):10:in `send'
from (irb):10
irb(main):011:0> s.send "foo", 0
=> 3
irb(main):012:0> s.send "foo", 0
Errno::ECONNREFUSED: Connection refused - send(2)
from (irb):12:in `send'
from (irb):12


and it just keeps on alternating, more or less the same as that...

There's no problem when I broadcast on a *real* network, like 192.168.1.255.
 
J

Joel VanderWerf

Daniel said:
Joel,




I don't think it's supposed to be possible to send broadcasts
to loopback interfaces, going by what ifconfig tells me.
But if it were, I'd think they should go to 127.255.255.255.
That's the obvious choice of a broadcast address here.

Any address can function as the broadcast address for the
network that it's part of, and any address ending in 255
that isn't the broadcast address is just a normal address.
So I think 127.0.0.255 is just another loopback address.

Ah, you're right, of course. The mask for lo is 255.0.0.0, so of course
the broadcast addr has to be 127.255.255.255. Funny that it sorta worked
with 127.0.0.255, though.

Thanks!
 
J

Joel VanderWerf

Ok, a new problem. The following program outputs "received: foo". But if
I uncomment the s.connect line in the fork code, it hangs in #recv. Why
should connecting a UDPSocket to _another_ broadcast port interfere with
receiving? (I see the same behavior with 192.168.1.255 broadcasts after
turning off my firewall.)

require 'socket'

broadcast_addr = '127.255.255.255'

fork do
s = UDPSocket.open
s.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
s.bind(broadcast_addr, 44891)
#s.connect(broadcast_addr, 44890)
puts "received: #{s.recv(100)}"
end

sleep 0.1

s = UDPSocket.open
s.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
#s.bind(broadcast_addr, 44890) # this has no effect either way
s.connect(broadcast_addr, 44891)
s.send "foo", 0

Process.wait
 
D

Daniel Brockman

Joel VanderWerf said:
Why should connecting a UDPSocket to _another_ broadcast
port interfere with receiving?

CONNECT(2) Linux Programmers Manual CONNECT(2)

NAME
connect - initiate a connection on a socket

SYNOPSIS
#include <sys/types.h>
#include <sys/socket.h>

int connect(int sockfd, const struct sockaddr
*serv_addr, socklen_t addrlen);

DESCRIPTION
The file descriptor sockfd must refer to a socket.
If the socket is of type SOCK_DGRAM then the
serv_addr address is the address to which datagrams
are sent by default, and the only address from which
datagrams are received.

[...]
 
J

Joel VanderWerf

Daniel said:
Why should connecting a UDPSocket to _another_ broadcast
port interfere with receiving?


CONNECT(2) Linux Programmers Manual CONNECT(2)

NAME
connect - initiate a connection on a socket

SYNOPSIS
#include <sys/types.h>
#include <sys/socket.h>

int connect(int sockfd, const struct sockaddr
*serv_addr, socklen_t addrlen);

DESCRIPTION
The file descriptor sockfd must refer to a socket.
If the socket is of type SOCK_DGRAM then the
serv_addr address is the address to which datagrams
are sent by default, and the only address from which
datagrams are received.

[...]

Hm, so linux connect() implies bind() on UDP sockets?

Then is ruby doing something funny on top of the linux socket API? Why
does the following code work? (It sets up two sockets that connect to
the port each other is listening on, which should not be possible, if I
understand man connect.)

require 'socket'

Socket.do_not_reverse_lookup = true

addr = '127.0.0.1'

socks = (0..1).map {UDPSocket.open()}
socks.each {|s| s.bind(addr, 0)}
ports = socks.map {|s| s.addr[1]}

socks.each_with_index {|s,i| s.connect(addr, ports[1-i])}
puts socks.map{|s| [s.addr, s.peeraddr].inspect}

s0, s1 = socks

t0 = Thread.new do
puts "s1 received: #{s1.recv(100)}"
end
sleep 0.1

s0.send "foo", 0

t0.join


t1 = Thread.new do
puts "s0 received: #{s0.recv(100)}"
end
sleep 0.1

s1.send "bar", 0

t1.join

__END__

output:

[["AF_INET", 33223, "127.0.0.1", "127.0.0.1"], ["AF_INET", 33224,
"127.0.0.1", "127.0.0.1"]]
[["AF_INET", 33224, "127.0.0.1", "127.0.0.1"], ["AF_INET", 33223,
"127.0.0.1", "127.0.0.1"]]
s1 received: foo
s0 received: bar
 
J

Joel VanderWerf

Joel said:
Ok, a new problem. The following program outputs "received: foo". But if
I uncomment the s.connect line in the fork code, it hangs in #recv. Why
should connecting a UDPSocket to _another_ broadcast port interfere with
receiving? (I see the same behavior with 192.168.1.255 broadcasts after
turning off my firewall.)

require 'socket'

broadcast_addr = '127.255.255.255'

fork do
s = UDPSocket.open
s.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
s.bind(broadcast_addr, 44891)
#s.connect(broadcast_addr, 44890)
puts "received: #{s.recv(100)}"
end

sleep 0.1

s = UDPSocket.open
s.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, true)
#s.bind(broadcast_addr, 44890) # this has no effect either way

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Wrong. Binding this socket lets the packet go through, when the
s.connect line is also enabled, but only if I use a non-broadcast
address, like 127.0.0.1.

I guess #connect just doesn't mix well with broadcast UDP?

Well, fortunately, I don't need to use the combination of (broadcast,
UDP, connect) in my application code. I was just using it in a unit
test, but it's not necessary.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,763
Messages
2,569,563
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top