Skip to main content
GameDev.net gamedev.net
🔒 Locked

ECONNREFUSED

Started by DrHalan Sep 3, 2008 at 6:18 PM 18 replies 2.9k views
Original Post
DrHalan
DrHalan
Hey, after implenting sucessfully a Reliable UDP Port into my network lib. I wanted to implent a TCP one also. It's already pretty close to completition but on connect im stuck with an ECONNREFUSED on the client side. I don't really understand why. When is ECONNREFUSED produced? The client, as it's non blocking, basically calls this function until it creates a valid filedescriptor.
bool CTCPPort::connectLoop(PeerID id)
{
    if(this->isIPv6())
    {
        sockaddr_in6 tmpAddr;

        if(getSockAddress6(tmpAddr, peers[id]->address))
        {
            if( ::connect ( peers[id]->socketfd, (sockaddr*)&tmpAddr , sizeof(tmpAddr)) == 0)
            {
                peers[id]->connected = true;

                this->getCallback()->onPeerConnect(id);

                return true;
            }
        }
    }
    else
    {
        sockaddr_in tmpAddr;

        if(getSockAddress(tmpAddr, peers[id]->address))
        {
            if( ::connect ( peers[id]->socketfd, (sockaddr*)&tmpAddr , sizeof(tmpAddr)) == 0)
            {
                peers[id]->connected = true;

                this->getCallback()->onPeerConnect(id);

                return true;
            }
        }
    }

    // We just have to call connect again and then it should be fine
    if(errno == EINPROGRESS || errno == EWOULDBLOCK)
        return true;

    #ifdef WINDOWS
        if(errno == WSAEWOULDBLOCK)
            return true;
    #endif
    
    if(errno == ECONNREFUSED)
        callback->onConnectionFailed(ECFR_Denied);

    // print out the error
    perror("connect");

    delete peers[id];
    peers[id] = 0;

    peerCount--;

    return false;
}


The listener/server does this to accept

    if(this->isListening())
    {
        while((::listen( listenfd, 5) == 0) && (peerCount < maxPeers))
        {
            for(u32 u = 0; (u < maxPeers); u++)
            {
                if(!peers)
                {
                    s32 socketfd = -1;

                    if(this->isIPv6())
                    {
                        sockaddr_in6 tmpAddr;
                        socklen_t tmpSize;

                        socketfd = accept( listenfd, (sockaddr*)&tmpAddr, &tmpSize);

                        if(socketfd == -1)
                        {
                            if(errno != EWOULDBLOCK)
                                perror("accept");
                        }
                        else
                        {
                            SNetworkAddress addr;
                            getNetworkAddress6(tmpAddr, addr);

                            peers = new STCPPeer(addr, socketfd);
                        }
                    }
                    else
                    {
                        sockaddr_in tmpAddr;
                        socklen_t tmpSize;

                        socketfd = accept( listenfd, (sockaddr*)&tmpAddr, &tmpSize);

                        if(socketfd == -1)
                        {
                            if(errno != EWOULDBLOCK)
                                perror("accept");
                        }
                        else
                        {
                            SNetworkAddress addr;
                            getNetworkAddress(tmpAddr, addr);

                            peers = new STCPPeer(addr, socketfd);
                        }
                    }

                    if(socketfd >= 0)
                    {
                        peers->connected = true;
                        peerCount++;
                    }

                    break;
                }
            }
        }

        if(errno != EWOULDBLOCK && errno != ECONNREFUSED && errno != EINPROGRESS)
            perror("listen");
    }


I know im using some internal stuff liek SNetworkAddress and whatsoever but i think it should be understandable. thanks in advance, DrHalan
My Blog - http://www.freakybytes.org
Hacksaw2201
Hacksaw2201
This is the messages for Winsock and I had a similar problem:

http://msdn.microsoft.com/en-us/library/ms740668.aspx

WSAECONNREFUSED
10061

Connection refused.
No connection could be made because the target computer actively refused it. This usually results from trying to connect to a service that is inactive on the foreign host—that is, one with no server application running.


Doesn't really say much other than the client didn't find the application it needed on the server. Check your IP's and ports to make sure that they match or your client won't be able to connect. Perhaps the protocol as well since you have UDP and TCP both in your application.
hplus0603
hplus0603
Note that you can't test the result of a non-blocking connect() immediately. You'll have to use select(), and test for readable/writable vs exception condition, or use a function like getpeername().
enum Bool { True, False, FileNotFound };
DrHalan
DrHalan
Quote:
Original post by hplus0603
Note that you can't test the result of a non-blocking connect() immediately. You'll have to use select(), and test for readable/writable vs exception condition, or use a function like getpeername().


If i just ignore ECONNREFUSED like i did with EWOULDBLOCK i get a valid file descriptor on the client side but not on the server.

Can you recommend any tutorial for select(). Btw this happens too with blocking sockets...

Gonna paste my connect()-function

//! Connect to an address//! Returns false if already connected or some error occuredbool CTCPPort::connect(const SNetworkAddress& address){    if(this->isConnected(address))        return false;    for(u16 u = 0; u < this->getMaxPeers(); u++)    {        if(!peers)        {            s32 socketFd;            if(this->isIPv6())                socketFd = socket(PF_INET6, SOCK_STREAM, 0);            else                socketFd = socket(PF_INET, SOCK_STREAM, 0);            if(socketFd == -1)            {                perror("socket");                return false;            }            peers = new STCPPeer(address, socketFd);            peerCount++;            #ifdef _ONET_NON_BLOCKING_                // Make the socket non blocking                s32 save_fd = fcntl( socketFd, F_GETFL );                save_fd |= O_NONBLOCK;                fcntl( socketFd , F_SETFL, save_fd );            #endif            return this->connectLoop(u);        }    }    return false;}


greets,
DrHalan
My Blog - http://www.freakybytes.org
hplus0603
hplus0603
Does the connection specify a valid IP address and port number? Are you properly htons()-ing the port number?
At this point, I would run a copy of Wireshark on the client (and perhaps on the server, too) and look at the packets that get sent, to figure out what's going wrong.
enum Bool { True, False, FileNotFound };
DrHalan
DrHalan
Quote:
Original post by hplus0603
Does the connection specify a valid IP address and port number? Are you properly htons()-ing the port number?
At this point, I would run a copy of Wireshark on the client (and perhaps on the server, too) and look at the packets that get sent, to figure out what's going wrong.


thanks for the advice.

after struggeling a bit (had to run wireshark as root (wth?) to see the network devices). i made it capture.

the port is set correct random -> 60,001 (i choose i high one to ensure its unused).

But theres also somethign else appearing "csms2".
I don't think its releated to my prob (different port/different ip) but on the other hand I don't know what that is, so i uploaded a screenshot of wireshark capturing.
http://img502.imageshack.us/my.php?image=captureiw1.png
My Blog - http://www.freakybytes.org
hplus0603
hplus0603
csms2 is just a name for port 3400. What that actually is, I don't know -- and it may not be the actual protocol spoken; it's just a symbolic name for "port 3400."

The packet highlighted in RED is the response from port 60001 saying "connection refused," so I would look on the server side. For example, it's trying to connect to interface 127.0.0.1 -- is the server bound to port 60001 on interface 127.0.0.1 and listening on that machine? You can use "netstat" to find all currently bound ports.
enum Bool { True, False, FileNotFound };
DrHalan
DrHalan
Quote:
Original post by hplus0603
csms2 is just a name for port 3400. What that actually is, I don't know -- and it may not be the actual protocol spoken; it's just a symbolic name for "port 3400."

The packet highlighted in RED is the response from port 60001 saying "connection refused," so I would look on the server side. For example, it's trying to connect to interface 127.0.0.1 -- is the server bound to port 60001 on interface 127.0.0.1 and listening on that machine? You can use "netstat" to find all currently bound ports.



I used netstat -l and it listet my port. I don't really understand why this isn't working.
Maybe theres something worng about the socket creation? ( see connect() )

greets,
DrHalan
My Blog - http://www.freakybytes.org
hplus0603
hplus0603
Quote:
I used netstat -l and it listet my port.


Was it in the LISTENING state?
Also, was it bound to *, or to 0.0.0.0? Or was it only bound on the external IP address interface?
Do you have a firewall running on the machine?
enum Bool { True, False, FileNotFound };
DrHalan
DrHalan
yes it was on LISTENING.

i DO have a firewall here on ubuntu i think its ufw, but UDP worked fine on the same ports so can this be the problem?

greets,
DrHalan

EDIT: just found out that iptables are DISABLED by default on ubuntu. so that shouldnt be a problem...

[Edited by - DrHalan on September 6, 2008 12:41:10 PM]
My Blog - http://www.freakybytes.org
DrHalan
DrHalan
Okay i now compared non-blocking and blocking and continued even if there was a ECONNREFUSED

this is what i found out:
on blocking it first says "connection refused" and then "illegal seek"
on non-blocking it first says "operation in progress" (EWOULDBLOCK / EAGAIN) and then also "illegal seek"

so what is this "illegal seek" all about?

greets,
DrHalan

My Blog - http://www.freakybytes.org
hplus0603
hplus0603
It might be used as a catch-all error for operations on file descriptors that are not allowed.
enum Bool { True, False, FileNotFound };
DrHalan
DrHalan
Quote:
Original post by hplus0603
It might be used as a catch-all error for operations on file descriptors that are not allowed.


Yeah i guessed that the filedescriptor is already broken at that point...

I feel like im stuck with the TCP implementation at this point as i can't find a way to fix it.

thanks for your kind support anyways,
DrHalan
My Blog - http://www.freakybytes.org
DrHalan
DrHalan
i thought of something.

in my test app (worked with UDP) i created both ports in one process.

is that a problem in TCP?

greets,
DrHalan
My Blog - http://www.freakybytes.org
hplus0603
hplus0603
In TCP, you cannot bind two sockets to the same port on the same machine, whereas on UDP, you can.
enum Bool { True, False, FileNotFound };
DrHalan
DrHalan
Quote:
Original post by hplus0603
In TCP, you cannot bind two sockets to the same port on the same machine, whereas on UDP, you can.


no im not doing that.

but i create two ports in one process. only one gets a bind call (the listening one)

im thinking about rewriting my tcp part with boost::asio as i want to support more implemenetations anyways :)

greets,
DrHalan
My Blog - http://www.freakybytes.org
hplus0603
hplus0603
Of course you can have multiple sockets in a single process, and each socket can be bound to a port of its own (either one you choose through bind(), or some random port chosen by the implementation when you call connect() or sendto()).
enum Bool { True, False, FileNotFound };
DrHalan
DrHalan
Hey,

I switched the whole TCP Port to select() but now i never have any descriptor in the write or read set.

Maybe you wanna take a look at my source?
http://code.google.com/p/open-network/source/browse/
My Blog - http://www.freakybytes.org
Drew_Benton
Drew_Benton
Looking at what you have and sort of following this thread, it seems you are using the server as a 'client' as well as a server, and I think that's where your problems are coming in.

I think this because:

CTCPPort::init()

contains the line

if(bind(listenfd, (struct sockaddr*)&myaddr, sizeof(myaddr)) == -1)

yet you have a function

bool CTCPPort::connect(const SNetworkAddress& address)

that creates a socket,

socketFd = socket(PF_INET, SOCK_STREAM, 0);,

but in

void CTCPPort::work(void),

you have calls to

if( ::connect ( peers->socketfd, (sockaddr*)&tmpAddr , sizeof(tmpAddr)) == 0)

being called if the condition

if(peers->connected)

is false.

If I am on the right track, the client should be calling connect and the server should call accept, which accept will return the socket you should be send/recv to and from, not a new socket you create from insides the server.

I don't have any suggestions on fixing this though, I've only used Win32 Async sockets with events through a HWND, so you might need to consult a few resources in the FAQ to get some more tips. Good luck!
DrHalan
DrHalan
Oh sorry,

i think my code isn't documented good.

When you create a TCP-Port it will also create a listening socket on the portnumber you specified. But also when you try to connect it will create new sockets.
The behaviour is that a TCPPeer-Struct exists which holds a boolean for being connected or not. If this one is false the class will make an attempt to connect if the fildescriptor is writeable. If there was a success the peer will be set to connected = true if not it will be removed from the peer-array.
If there is a connect attempt on the listening socket it will try to call accept and also get a new socket out of this event. Of course the TCPPeer will be set to connected = true directly.

Hope that helped

greets,
DrHalan
My Blog - http://www.freakybytes.org

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.