Re: "connection refused" on recvfrom!?

Avery Pennarun (apenwarr@foxnet.net)
Tue, 1 Aug 1995 15:32:33 -0400 (EDT)


On Mon, 31 Jul 1995, Alan Cox wrote:

> > - sendto() some IP address, first to the ECHO port, then to a
> > nonexistent port (ie connection would be refused). Both
> > sendto's return successfully. Okay, I can understand that,
> > UDP is supposed to be an unreliable protocol.
> > - delay a bit to let internet do its thing
> >
> > - recvfrom() on the socket returns error; errno is ECONNREFUSED (!)
> > and there's nothing valid in the "from" address. (ie.
> > we don't know who refused the connection!)
>
> You received an ICMP_UNREACH for the unreachable port. RFC 1122 states that
> this information MUST be reported to the user.

Oops.

Actually, after closer examination the ytalk case is slightly different than
I stated last time; it actually opens _two_ sockets, and sends a datagram on
each (one sends to port 517, the other to port 518).

It then does a select() on _both_ sockets, and the unreachable one always
seems to indicate it has data ready first.

Should select() say there's data ready and then cause recv() to return an
error? Seems rather strange. (although this approach in ytalk is better
than I had explained before, since at least we _can_ tell which port had the
error).

> > On a SunOS 4.1.3_U1 system I tried, the sendto() a nonexistent port returned
> > ECONNREFUSED right away; does this mean it delayed until it got a response
> > back? The result code makes perfect sense and is understandable, but how
> > does it manage this with UDP, which isn't guaranteed to respond with
> > anything at all?
>
> It's time dependant on how fast the UNREACH is returned. Also some systems
> don't report them to the user at all. In the SunOS case from memory the sendto
> reports nothing if the target is remote.

No, I did a sendto() for a _very_ remote site, on the order of Texas, USA to
Calgary, Canada, and still got an error - that's why I thought it was
strange.

I also tried with Linux between two computers a single ARCnet hop away
(about 3.5 milliseconds) and sendto() still didn't return the error
immediately, whereas it did with localhost.

> > - otherwise, at least never return ECONNREFUSED on a recvfrom. It
> > wasn't the recvfrom that caused the error, after all.
>
> The error has to be returned somehow. Sockets make no guarantee that error
> returns are synchronous in UDP or TCP. You don't for example know which block
> of bytes in a TCP stream got received by the other end last when a link
> dies.

It just seemed strange to me that recvfrom(), which has nothing to do with
the error in the first place, should be given the error code - especially
when there may be valid data waiting. Is there no better way?

> > I include a patch below to make ytalk try the select()/recvfrom() pair again
> > if it gets ECONNREFUSED. I don't think it's the right solution, though
> > (particularly since I used a goto... yecch :))
>
> To my knowledge it is the right solution.

Maybe I should clean it up (ie. get rid of the nasty goto) and send it to
the author, then...

Interesting.

Avery