Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Socket.Connection refused on linux and osx #923

Closed
dv00d00 opened this issue Jul 19, 2018 · 12 comments
Closed

Socket.Connection refused on linux and osx #923

dv00d00 opened this issue Jul 19, 2018 · 12 comments
Labels
area-System.Net.Sockets backlog-cleanup-candidate An inactive issue that has been marked for automated closure. bug no-recent-activity os-linux Linux OS (any supported distro) tenet-compatibility Incompatibility with previous versions or .NET Framework

Comments

@dv00d00
Copy link

dv00d00 commented Jul 19, 2018

Not sure if it is a bug but this code works perfectly fine on windows:

[Fact]
public static void UDP_MultipleSends()
{
    var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
    socket.Connect(new IPEndPoint(IPAddress.Loopback, 12345));

    for (int i = 0; i < 100; i++)
    {
        socket.Send(Encoding.ASCII.GetBytes("hello world"));
    }
}

but fails on linux

Operating System Details
Distributor ID:	Ubuntu
Description:	Ubuntu 14.04.5 LTS
Release:	14.04
Codename:	trusty

and OSX

instance: 6963e4a4-daa1-404d-b285-a2db097e200f travis-ci-macos10.12-xcode8.3-1507738863 (via amqp)

dotnet version: 2.1.302

Error Message:
 System.Net.Sockets.SocketException : Connection refused

Related fact

SendTo behaves differently - see https://github.com/dotnet/corefx/issues/31206#issuecomment-406515367

@dv00d00 dv00d00 changed the title Connection refused on linux and osx System.Net.Sockets.Socket Connection refused on linux and osx Jul 19, 2018
@davidsh
Copy link
Contributor

davidsh commented Jul 19, 2018

cc: @wfurt

@wfurt
Copy link
Member

wfurt commented Jul 19, 2018

Do you have anything listening on that port @dv00d00 ?
You may run tcpdump -ni lo port 12345 (or strace)

@wfurt
Copy link
Member

wfurt commented Jul 19, 2018

It seems like the error is coming from OS:

strace -f -e network ~/dotnet-2.1.302/dotnet run
[pid 28081] connect(26, {sa_family=AF_INET, sin_port=htons(12345), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
Connect OK
[pid 28081] sendmsg(26, {msg_name(0)=NULL, msg_iov(1)=[{"hello world", 11}], msg_controllen=0, msg_flags=0}, 0) = 11
[pid 28081] sendmsg(26, {msg_name(0)=NULL, msg_iov(1)=[{"hello world", 11}], msg_controllen=0, msg_flags=MSG_DONTWAIT|MSG_WAITALL|MSG_CONFIRM|MSG_ERRQUEUE|MSG_NOSIGNAL|MSG_WAITFORONE|0x85500000}, 0) = -1 ECONNREFUSED (Connection refused)

When sending data locally, kernel can probably detect that port is closed and the sendmsg() call fails. That does not looks like problem with the runtime, more difference in how OS handle I/O.

@dv00d00
Copy link
Author

dv00d00 commented Jul 20, 2018

On the other hand

[Fact]
public static void UDP_MultipleSends()
{
    var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
    var ep = new IPEndPoint(IPAddress.Loopback, 12345);

    for (int i = 0; i < 100; i++)
    {
        socket.SendTo(Encoding.ASCII.GetBytes("hello world"), ep);
    }
}

works without throwing exceptions. I don't believe anything is on that specific port, this was happening on a travis CI machine, but the same happened on my mac.

@wfurt
Copy link
Member

wfurt commented Sep 19, 2018

I did more testing with C and C# as well as I looked at Linux kernel code.
This seems to be way how Unix works. when sendto() is used, individual chunks of data are submitted independently and the call succeeds as long as there is space in socket buffer.
Since UDP is unreliable, this is has nothing to do with actual delivery.

I did also packet capture for both calls. In both cases I see:

furt@Ubuntu:~/git/wfurt-corefx-serial/src/System.Diagnostics.Process/src$ sudo tcpdump -eni lo
[sudo] password for furt:
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
14:48:23.512034 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 53: 127.0.0.1.46992 > 127.0.0.1.12345: UDP, length 11
14:48:23.512043 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 81: 127.0.0.1 > 127.0.0.1: ICMP 127.0.0.1 udp port 12345 unreachable, length 47

When sendmsg() is trying to send data following happens: first message goes out without error.
When the ICMP error get's back it is remembered on "connection" (internal socket structure)
Subsequent sendmsg() calls fail.

Since this is OS behavior, I don't think it make sense to hide underlying error.
It seems that raising exception and allowing caller to deal with it is better approach.

I'm proposing to close this unless somebody objects. cc: @karelz
(note that linked PR does not change this behavior)

@Krummelz
Copy link

Krummelz commented Sep 2, 2019

Hi all, please take a look at this same issue over on the NpgSql repo - npgsql/npgsql#2198. I'm experiencing the same thing. And their code is using the same Socket class to make the connections. You can look at the relevant Connect method code here: https://github.com/npgsql/npgsql/blob/91d23f90ef00eadc7c07966833959a5b3f877127/src/Npgsql/NpgsqlConnector.cs#L642.

"System.Net.Sockets.SocketException (111): Connection refused" error,
at Npgsql.NpgsqlConnector.Connect(NpgsqlTimeout timeout)

I've run tcpdump -ni lo port 5432, and I get the following:

root@ubuntu-app-vm:~# tcpdump -ni lo port 5432
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
10:18:57.878227 IP 127.0.0.1.50184 > 127.0.0.1.5432: Flags [S], seq 4146525521, win 43690, options [mss 65495,sackOK,TS val 2214584442 ecr 0,nop,wscale 7], length 0
10:18:57.878242 IP 127.0.0.1.5432 > 127.0.0.1.50184: Flags [R.], seq 0, ack 4146525522, win 0, length 0

@wfurt
Copy link
Member

wfurt commented Sep 2, 2019

From the dump it is clear that the port you trying to connect to is not listening and sends back RST. It is correct to throw.
Also note that this issue is about UDP.

@karelz
Copy link
Member

karelz commented Sep 9, 2019

Triage: We need to understand why Send and SendTo behave differently.
We need either doc change, or product change, or test added.

@karelz karelz changed the title System.Net.Sockets.Socket Connection refused on linux and osx Socket.Connection refused on linux and osx Sep 9, 2019
@maryamariyan maryamariyan transferred this issue from dotnet/corefx Dec 16, 2019
@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added area-System.Net.Sockets untriaged New issue has not been triaged by the area owner labels Dec 16, 2019
@maryamariyan maryamariyan added bug os-linux Linux OS (any supported distro) tenet-compatibility Incompatibility with previous versions or .NET Framework labels Dec 16, 2019
@maryamariyan maryamariyan modified the milestones: 5.0, Future Dec 16, 2019
@karelz karelz removed the untriaged New issue has not been triaged by the area owner label Jan 7, 2020
@vindicatorr
Copy link

I'm only just now getting into this as well and it looks like SCM_RIGHTS is going to be key:
Send or receive a set of open file descriptors from another process. The data portion contains an integer array of the file descriptors.(unix.7)
https://stackoverflow.com/questions/28003921/sending-file-descriptor-by-linux-socket/

@tmds
Copy link
Member

tmds commented Jun 25, 2020

This issue is unrelated to SCM_RIGHTS.

On Linux, Socket.Send throws a SocketException if there is no peer, while on Windows it does not.

Windows WSASend documentation suggests it could do the same thing:

WSAECONNRESET | For a stream socket, the virtual circuit was reset by the remote side. The application should close the socket as it is no longer usable. For a UDP datagram socket, this error would indicate that a previous send operation resulted in an ICMP "Port Unreachable" message.
-- | --

Maybe this error is only generated for non-localhost communication on Windows?

You can add an extension method if you always want to ignore the error, and avoid the cost of throwing (and catching) Exceptions for it.

    static class SocketExtensions
    {
        public static int SendUdp(this Socket socket, ReadOnlySpan<byte> buffer)
        {
            int rv = socket.Send(buffer, SocketFlags.None, out SocketError socketError);
            return socketError switch
            {
                SocketError.Success => rv,
                SocketError.ConnectionRefused => 0,
                _ => throw new SocketException((int)socketError),
            };
        }
    }

Copy link
Contributor

Due to lack of recent activity, this issue has been marked as a candidate for backlog cleanup. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will undo this process.

This process is part of our issue cleanup automation.

@dotnet-policy-service dotnet-policy-service bot added backlog-cleanup-candidate An inactive issue that has been marked for automated closure. no-recent-activity labels Dec 25, 2024
Copy link
Contributor

This issue will now be closed since it had been marked no-recent-activity but received no further activity in the past 14 days. It is still possible to reopen or comment on the issue, but please note that the issue will be locked if it remains inactive for another 30 days.

@dotnet-policy-service dotnet-policy-service bot removed this from the Future milestone Jan 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-System.Net.Sockets backlog-cleanup-candidate An inactive issue that has been marked for automated closure. bug no-recent-activity os-linux Linux OS (any supported distro) tenet-compatibility Incompatibility with previous versions or .NET Framework
Projects
None yet
Development

No branches or pull requests

9 participants