machinezone / IXWebSocket

websocket and http client and server library, with TLS support and very few dependencies
BSD 3-Clause "New" or "Revised" License
546 stars 174 forks source link

Windows: Basic echo fails to connect on 5.0.4 #103

Closed LunarWatcher closed 5 years ago

LunarWatcher commented 5 years ago

5.0.4 and Windows don't appear to get along. All my unit tests are failing on 5.0.4, and attempting to compile it locally (git clone https://github.com/lunarwatcher/conan-ixwebsocket && cd conan-ixwebsocket && conan create . IXWebSocket/LunarWatcher) successfully compiles it, but prints errors:

ERROR: Unable to connect to echo.websocket.org on port 80, error: Connect error: No error
ERROR: Unable to connect to echo.websocket.org on port 80, error: Connect error: No error
ERROR: Unable to connect to echo.websocket.org on port 80, error: Connect error: No error
ERROR: Unable to connect to echo.websocket.org on port 80, error: Connect error: No error
ERROR: Unable to connect to echo.websocket.org on port 80, error: Connect error: No error
ERROR: Unable to connect to echo.websocket.org on port 80, error: Connect error: No error
ERROR: Unable to connect to echo.websocket.org on port 80, error: Connect error: No error

These aren't visible in the CI builds (I have no idea why)

For reproducibility, the code:

#include <iostream>
#include <ixwebsocket/IXWebSocket.h>
#include <string>
#include <vector>
#include <chrono>
#include <thread>
#include <ixwebsocket/IXNetSystem.h>

class SocketWrapper {
private:
    ix::WebSocket webSocket;
    std::vector<std::string> receivedMessages;
public:
    SocketWrapper() {
        webSocket.setUrl(std::string("ws://echo.websocket.org"));
        webSocket.setOnMessageCallback(
            [this](const ix::WebSocketMessagePtr& message) {
                if (message->type == ix::WebSocketMessageType::Open) {
                    std::cout << "Connected\n";
                    //webSocket.send(std::string("Congrats, your local version of IXWebSocket works!"));
                } else if (message->type == ix::WebSocketMessageType::Close) {
                    std::cout << "Closing socket...\n";
                } else if (message->type == ix::WebSocketMessageType::Message) {
                    std::cout << "Message received from server: " << message->str << std::endl;
                    receivedMessages.push_back(message->str);
                } else if (message->type == ix::WebSocketMessageType::Error) {
                    std::cout << "ERROR: " << message->errorInfo.reason << std::endl;
                } 
            });
        webSocket.start();

    }

    bool hasReceived() { return receivedMessages.size() > 0; }
    void close() { this->webSocket.close(); }
    bool ready() { 
        return this->webSocket.getReadyState() == ix::ReadyState::Open; 
    }
    void send(std::string message) { this->webSocket.send(message); }
};

int main() {
    std::cout << "Starting socket..." << std::endl;
    ix::initNetSystem(); // required for Windows
    SocketWrapper socketWrapper;
    int counter = 0;
    while(true) {
        std::this_thread::sleep_for(std::chrono::milliseconds(2000));
        counter++;
        if (socketWrapper.hasReceived()) {
            break;
        } else if (counter >= 5) {
            socketWrapper.close();
            ix::uninitNetSystem(); 
            throw "No response for 10 seconds: assuming failure";
        }

        if (socketWrapper.ready()) {
            socketWrapper.send("Congrats, your local version of IXWebSocket works!");
        }
    }
    std::cout << "Message received! Closing socket." << std::endl;
    socketWrapper.close();
    std::cout << "Socket disconnected." << std::endl;

    ix::uninitNetSystem(); // required for Windows.
}

For context, all the builds on 5.0.4 pass on Linux and Mac. The code is also identical in the 5.0.0 build and 5.0.4 build. I'm pretty sure this is triggered by v5.0.4 (or one of the versions in between that didn't work on Windows), but it could of course be my fault, but when it works on the other two operating systems and I have ix::initNetSystem(), I can't find anything else that could trigger it

bsergean commented 5 years ago

I have a feeling it relates to using poll instead of select now to react on network.

I need to repair CI for Windows. I still don't have access to a Windows box easily (I periodically download a Windows 10 VM). Last time I tried with travis I had issues, I will try to setup AppVeyor support when I get a chance.

If you want to mess around, this is what I would do.

add a new function mimicking poll using select under the hood, in IXNetSystem.cpp

On Aug 21, 2019, at 11:08 AM, Olivia Zoe notifications@github.com wrote:

5.0.4 and Windows don't appear to get along. All my unit tests are failing https://ci.appveyor.com/project/LunarWatcher/conan-ixwebsocket on 5.0.4, and attempting to compile it locally (git clone https://github.com/lunarwatcher/conan-ixwebsocket && cd conan-ixwebsocket && conan create . IXWebSocket/LunarWatcher) successfully compiles it, but prints errors:

ERROR: Unable to connect to echo.websocket.org on port 80, error: Connect error: No error ERROR: Unable to connect to echo.websocket.org on port 80, error: Connect error: No error ERROR: Unable to connect to echo.websocket.org on port 80, error: Connect error: No error ERROR: Unable to connect to echo.websocket.org on port 80, error: Connect error: No error ERROR: Unable to connect to echo.websocket.org on port 80, error: Connect error: No error ERROR: Unable to connect to echo.websocket.org on port 80, error: Connect error: No error ERROR: Unable to connect to echo.websocket.org on port 80, error: Connect error: No error These aren't visible in the CI builds (I have no idea why)

For reproducibility, the code:

include

include <ixwebsocket/IXWebSocket.h>

include

include

include

include

include <ixwebsocket/IXNetSystem.h>

class SocketWrapper { private: ix::WebSocket webSocket; std::vector receivedMessages; public: SocketWrapper() { webSocket.setUrl(std::string("ws://echo.websocket.org")); webSocket.setOnMessageCallback( [this](const ix::WebSocketMessagePtr& message) { if (message->type == ix::WebSocketMessageType::Open) { std::cout << "Connected\n"; //webSocket.send(std::string("Congrats, your local version of IXWebSocket works!")); } else if (message->type == ix::WebSocketMessageType::Close) { std::cout << "Closing socket...\n"; } else if (message->type == ix::WebSocketMessageType::Message) { std::cout << "Message received from server: " << message->str << std::endl; receivedMessages.push_back(message->str); } else if (message->type == ix::WebSocketMessageType::Error) { std::cout << "ERROR: " << message->errorInfo.reason << std::endl; } }); webSocket.start();

}

bool hasReceived() { return receivedMessages.size() > 0; }
void close() { this->webSocket.close(); }
bool ready() { 
    return this->webSocket.getReadyState() == ix::ReadyState::Open; 
}
void send(std::string message) { this->webSocket.send(message); }

};

int main() { std::cout << "Starting socket..." << std::endl; ix::initNetSystem(); // required for Windows SocketWrapper socketWrapper; int counter = 0; while(true) { std::this_thread::sleep_for(std::chrono::milliseconds(2000)); counter++; if (socketWrapper.hasReceived()) { break; } else if (counter >= 5) { socketWrapper.close(); ix::uninitNetSystem(); throw "No response for 10 seconds: assuming failure"; }

    if (socketWrapper.ready()) {
        socketWrapper.send("Congrats, your local version of IXWebSocket works!");
    }
}
std::cout << "Message received! Closing socket." << std::endl;
socketWrapper.close();
std::cout << "Socket disconnected." << std::endl;

ix::uninitNetSystem(); // required for Windows.

} For context, all the builds on 5.0.4 pass on Linux and Mac https://travis-ci.org/LunarWatcher/conan-IXWebSocket/builds/574497963. The code is also identical in the 5.0.0 build and 5.0.4 build. I'm pretty sure this is triggered by v5.0.4 (or one of the versions in between that didn't work on Windows), but it could of course be my fault, but when it works on the other two operating systems and I have ix::initNetSystem(), I can't find anything else that could trigger it

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/machinezone/IXWebSocket/issues/103?email_source=notifications&email_token=AC2O6UKHCWS3N6BHZYNATXLQFWAAXA5CNFSM4IOLRE72YY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4HGSXFWA, or mute the thread https://github.com/notifications/unsubscribe-auth/AC2O6UPLZ5AEEOCSBVCV6ODQFWAAXANCNFSM4IOLRE7Q.

bsergean commented 5 years ago

Double checking:

version = "5.0.0"

I found this in one of the conan files (the one from the master branch), you're using 5.0.4 right ?

On Aug 21, 2019, at 11:39 AM, Benjamin Sergeant bsergean@gmail.com wrote:

I have a feeling it relates to using poll instead of select now to react on network.

I need to repair CI for Windows. I still don't have access to a Windows box easily (I periodically download a Windows 10 VM). Last time I tried with travis I had issues, I will try to setup AppVeyor support when I get a chance.

If you want to mess around, this is what I would do.

add a new function mimicking poll using select under the hood, in IXNetSystem.cpp

(see https://github.com/mpv-player/mpv/pull/5203/files https://github.com/mpv-player/mpv/pull/5203/files)

On Aug 21, 2019, at 11:08 AM, Olivia Zoe <notifications@github.com mailto:notifications@github.com> wrote:

5.0.4 and Windows don't appear to get along. All my unit tests are failing https://ci.appveyor.com/project/LunarWatcher/conan-ixwebsocket on 5.0.4, and attempting to compile it locally (git clone https://github.com/lunarwatcher/conan-ixwebsocket https://github.com/lunarwatcher/conan-ixwebsocket && cd conan-ixwebsocket && conan create . IXWebSocket/LunarWatcher) successfully compiles it, but prints errors:

ERROR: Unable to connect to echo.websocket.org http://echo.websocket.org/ on port 80, error: Connect error: No error ERROR: Unable to connect to echo.websocket.org http://echo.websocket.org/ on port 80, error: Connect error: No error ERROR: Unable to connect to echo.websocket.org http://echo.websocket.org/ on port 80, error: Connect error: No error ERROR: Unable to connect to echo.websocket.org http://echo.websocket.org/ on port 80, error: Connect error: No error ERROR: Unable to connect to echo.websocket.org http://echo.websocket.org/ on port 80, error: Connect error: No error ERROR: Unable to connect to echo.websocket.org http://echo.websocket.org/ on port 80, error: Connect error: No error ERROR: Unable to connect to echo.websocket.org http://echo.websocket.org/ on port 80, error: Connect error: No error These aren't visible in the CI builds (I have no idea why)

For reproducibility, the code:

include

include <ixwebsocket/IXWebSocket.h>

include

include

include

include

include <ixwebsocket/IXNetSystem.h>

class SocketWrapper { private: ix::WebSocket webSocket; std::vector receivedMessages; public: SocketWrapper() { webSocket.setUrl(std::string("ws://echo.websocket.org ws://echo.websocket.org/")); webSocket.setOnMessageCallback( [this](const ix::WebSocketMessagePtr& message) { if (message->type == ix::WebSocketMessageType::Open) { std::cout << "Connected\n"; //webSocket.send(std::string("Congrats, your local version of IXWebSocket works!")); } else if (message->type == ix::WebSocketMessageType::Close) { std::cout << "Closing socket...\n"; } else if (message->type == ix::WebSocketMessageType::Message) { std::cout << "Message received from server: " << message->str << std::endl; receivedMessages.push_back(message->str); } else if (message->type == ix::WebSocketMessageType::Error) { std::cout << "ERROR: " << message->errorInfo.reason << std::endl; } }); webSocket.start();

}

bool hasReceived() { return receivedMessages.size() > 0; }
void close() { this->webSocket.close(); }
bool ready() { 
    return this->webSocket.getReadyState() == ix::ReadyState::Open; 
}
void send(std::string message) { this->webSocket.send(message); }

};

int main() { std::cout << "Starting socket..." << std::endl; ix::initNetSystem(); // required for Windows SocketWrapper socketWrapper; int counter = 0; while(true) { std::this_thread::sleep_for(std::chrono::milliseconds(2000)); counter++; if (socketWrapper.hasReceived()) { break; } else if (counter >= 5) { socketWrapper.close(); ix::uninitNetSystem(); throw "No response for 10 seconds: assuming failure"; }

    if (socketWrapper.ready()) {
        socketWrapper.send("Congrats, your local version of IXWebSocket works!");
    }
}
std::cout << "Message received! Closing socket." << std::endl;
socketWrapper.close();
std::cout << "Socket disconnected." << std::endl;

ix::uninitNetSystem(); // required for Windows.

} For context, all the builds on 5.0.4 pass on Linux and Mac https://travis-ci.org/LunarWatcher/conan-IXWebSocket/builds/574497963. The code is also identical in the 5.0.0 build and 5.0.4 build. I'm pretty sure this is triggered by v5.0.4 (or one of the versions in between that didn't work on Windows), but it could of course be my fault, but when it works on the other two operating systems and I have ix::initNetSystem(), I can't find anything else that could trigger it

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/machinezone/IXWebSocket/issues/103?email_source=notifications&email_token=AC2O6UKHCWS3N6BHZYNATXLQFWAAXA5CNFSM4IOLRE72YY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4HGSXFWA, or mute the thread https://github.com/notifications/unsubscribe-auth/AC2O6UPLZ5AEEOCSBVCV6ODQFWAAXANCNFSM4IOLRE7Q.

LunarWatcher commented 5 years ago

Whoops, my bad. I forgot to mention git checkout release/5.0.4. I keep the master branch up to date on the code itself, but keep versions in separate branches. The relevant code is on master, but to build 5.0.4, see the release/5.0.4 branch

bsergean commented 5 years ago

I just made a v5.0.5 with the potential fix I was talking about. Can you give it a try ?

bsergean commented 5 years ago

See https://github.com/machinezone/IXWebSocket/commit/193da820b271ad2d64914517472d3f6dfa83323b

LunarWatcher commented 5 years ago

Great, thanks! I've pushed the v5.0.5 branch. I'll update this reply when I start getting a status on them. It might take a few minutes before the first builds start succeeding.

LunarWatcher commented 5 years ago

This triggered a compile-time error when linking:

ixwebsocket.lib(IXSocket.obj) : error LNK2019: unresolved external symbol "int __cdecl poll(struct pollfd *,unsigned long,int)" (?poll@@YAHPEAUpollfd@@KH@Z) referenced in function "public: static enum ix::PollResultType __cdecl ix::Sock
et::poll(bool,int,int,class std::shared_ptr<class ix::SelectInterrupt>)" (?poll@Socket@ix@@SA?AW4PollResultType@2@_NHHV?$shared_ptr@VSelectInterrupt@ix@@@std@@@Z) [D:\programming\projects\cpp\conan-IXWebSocket\test_package\build\ecbfb49
a4e2ea8618319be5f9e02c8e0621391fb\tests.vcxproj]
    Hint on symbols that are defined and could potentially match:
      "public: static enum ix::PollResultType __cdecl ix::Socket::poll(bool,int,int,class std::shared_ptr<class ix::SelectInterrupt>)" (?poll@Socket@ix@@SA?AW4PollResultType@2@_NHHV?$shared_ptr@VSelectInterrupt@ix@@@std@@@Z)
      "public: enum ix::WebSocketTransport::PollResult __cdecl ix::WebSocketTransport::poll(void)" (?poll@WebSocketTransport@ix@@QEAA?AW4PollResult@12@XZ)
      "int __cdecl ix::poll(struct pollfd *,unsigned long,int)" (?poll@ix@@YAHPEAUpollfd@@KH@Z)

I also see why - the poll function isn't defined in the ix namespace, but the declaration in the cpp file is.

bsergean commented 5 years ago

Oops ... I just made v5.0.6 to fix that (87a45a2)

On Aug 22, 2019, at 11:01 AM, Olivia Zoe notifications@github.com wrote:

This triggered a compile-time error when linking:

ixwebsocket.lib(IXSocket.obj) : error LNK2019: unresolved external symbol "int cdecl poll(struct pollfd *,unsigned long,int)" (?poll@@YAHPEAUpollfd@@KH@Z) referenced in function "public: static enum ix::PollResultType cdecl ix::Sock et::poll(bool,int,int,class std::shared_ptr)" (?poll@Socket@ix@@SA?AW4PollResultType@2@_NHHV?$shared_ptr@VSelectInterrupt@ix@@@std@@@Z) [D:\programming\projects\cpp\conan-IXWebSocket\test_package\build\ecbfb49 a4e2ea8618319be5f9e02c8e0621391fb\tests.vcxproj] Hint on symbols that are defined and could potentially match: "public: static enum ix::PollResultType __cdecl ix::Socket::poll(bool,int,int,class std::shared_ptr)" (?poll@Socket@ix@@SA?AW4PollResultType@2@_NHHV?$shared_ptr@VSelectInterrupt@ix@@@std@@@Z) "public: enum ix::WebSocketTransport::PollResult cdecl ix::WebSocketTransport::poll(void)" (?poll@WebSocketTransport@ix@@QEAA?AW4PollResult@12@XZ) "int cdecl ix::poll(struct pollfd *,unsigned long,int)" (?poll@ix@@YAHPEAUpollfd@@KH@Z) I also see why - the poll function isn't defined in the ix namespace, but the declaration in the cpp file is.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/machinezone/IXWebSocket/issues/103?email_source=notifications&email_token=AC2O6UPIIGL2SVYMQRQI4Q3QF3H6VA5CNFSM4IOLRE72YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD45457Q#issuecomment-524013310, or mute the thread https://github.com/notifications/unsubscribe-auth/AC2O6ULFR5BU4QS2Q5ZUKT3QF3H6VANCNFSM4IOLRE7Q.

bsergean commented 5 years ago

It's a bit gross to redefine my global poll btw, in the future I might have a named wrapper for it. But right now I'm just interested in seeing if this fixes your problem.

LunarWatcher commented 5 years ago

Yep, that did the trick. It builds locally, and the CI build is looking good so far (built x86 and some of the x86_64 configurations on one of the MSVC versions). It prints output from the tests when expected to as well. Thanks!

These are also being pushed to conan as the soon as the CI builds finish.

bsergean commented 5 years ago

Excellent. Thanks for reporting the problem !!