Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Weird behaviour on sf::TcpSocket wenn connecting from a connected socket  (Read 3769 times)

0 Members and 1 Guest are viewing this topic.

Raincode

  • Full Member
  • ***
  • Posts: 118
    • View Profile
Hi,

I came across something very puzzling while working with sockets. Check out the following example:
   
#include <iostream>

#include <SFML/Network.hpp>

int main()
{
    sf::TcpListener l;
    l.listen(2017);

    sf::TcpSocket sock;
    if (sock.connect(sf::IpAddress::LocalHost, 2017) == sf::Socket::Done)
        std::cout << "Connected!\n";

    if (sock.connect({1,2,3,4}, 2017) == sf::Socket::Done)
        std::cout << "???\n";

    char ch;
    std::cin >> ch;
}
This gives me
Connected!
???

I would very much expect the second call to connect to fail. Can anyone explain what's going on? Is this a bug? I understand that further calls to connect disconnect the socket first, but the second connection should obviously fail.

Edit:
Equally confusing behaviour, I would expect the second call to connect to succeed, yet I get no output:
    sf::TcpListener l;
    l.listen(2017);

    sf::TcpSocket s;
    if (s.connect({1,2,3,4}, 2017, sf::milliseconds(200)) == sf::Socket::Done)
        std::cout << "???\n";

    if (s.connect(sf::IpAddress::LocalHost, 2017) == sf::Socket::Done)
        std::cout << "Connected\n";

    char ch;
    std::cin >> ch;

I'm compiling with mingw-w64 GCC 7.2.0 on Windows 10 with SFML from github master


I'm trying to loop through a range of IpAddresses e.g. 192.168.178.2 - 192.168.178.99 and attempt to connect with the same socket for each address. At first I thought I was making some mistake using multiple threads, but then I tried a small example in a single main().

Edit2:
Calling disconnect seems to work for me to "handle" a failed connection, kind of like this:
   
sf::Uint8 b1{192}, b2{168}, b3{178};
socks.push_back(std::make_unique<sf::TcpSocket>());
for (sf::Uint8 b4 = 2; b4 < 100; ++b4) {
    if (socks.back()->connect({b1,b2,b3,b4}, port, sf::milliseconds(100)) == sf::Socket::Done) {
        chat.queue("Connected");
        socks.push_back(std::make_unique<sf::TcpSocket>());
    } else
        socks.back()->disconnect();
}
« Last Edit: October 22, 2017, 07:43:31 pm by Raincode »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: Weird behaviour on sf::TcpSocket wenn connecting from a connected socket
« Reply #1 on: November 16, 2017, 07:29:43 pm »
I've kept this thread open since the first time it popped up, as it sounded suspicious. Only now did I have the time to look into it and this indeed seems like a bug.

When the socket is already connected and you try to establish a new connection, the ::connect() actually fails, but then the error code is wrongfully matched (for blocking sockets).

This condition is true and the if-body is entered:
        if (::connect(getHandle(), reinterpret_cast<sockaddr*>(&address), sizeof(address)) == -1)
            return priv::SocketImpl::getErrorStatus();

But the returned status code seems to be WSAEISCONN, I assume since the socket is still connected. Which then gets mapped wrongly to Socket::Done. Even though the comment states that this only applies to non-blocking sockets, there's no check, to ensure that we do have a non-blocking socket.
    switch (WSAGetLastError())
    {
        case WSAEWOULDBLOCK:  return Socket::NotReady;
        case WSAEALREADY:     return Socket::NotReady;
        case WSAECONNABORTED: return Socket::Disconnected;
        case WSAECONNRESET:   return Socket::Disconnected;
        case WSAETIMEDOUT:    return Socket::Disconnected;
        case WSAENETRESET:    return Socket::Disconnected;
        case WSAENOTCONN:     return Socket::Disconnected;
        case WSAEISCONN:      return Socket::Done; // when connecting a non-blocking socket
        default:              return Socket::Error;
    }

Even though the documentation states:
Quote from: Docu
If the socket was previously connected, it is first disconnected.
(Which by the way can be misunderstood when 'disconnected' is understood as adjective instead of verb)
We're not actively doing a disconnect, but the code just tries to run a new connect. I wonder if the assumption that doing a new connection will close the old connection is correct/good enough.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Weird behaviour on sf::TcpSocket wenn connecting from a connected socket
« Reply #2 on: November 16, 2017, 07:45:29 pm »
Isn't there a call to "close()" at the beginning of the function? That one is supposed to disconnet the socket (it kills it and recreates it).
Laurent Gomila - SFML developer

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: Weird behaviour on sf::TcpSocket wenn connecting from a connected socket
« Reply #3 on: November 16, 2017, 08:13:45 pm »
No, there isn't. Neither does create() close it or similar.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Weird behaviour on sf::TcpSocket wenn connecting from a connected socket
« Reply #4 on: November 17, 2017, 06:57:12 am »
Ah, right, I should have looked first.

I guess we can create a github issue to review this code.
Laurent Gomila - SFML developer