Moonlight (Gamestream client) Socket Error

Hello to the Haiku community

I am trying to port Moonlight Embedded to be able to stream video games from a PC to a client with Haiku, I managed to make it compile the project by eliminating some dependencies that are not entirely necessary.

Moonlight is capable of recognizing my PC, pairing, and also listing the video games I have installed.

But when I want to stream I get an error related to the sockets.

These are the messages it initially throws.
How do I know it’s something related to sockets? When reviewing the file
third_party\moonlight-common-c\src\PlatformSockets.c
I find the error messages.

The first: setsockopt(TCP_NOOPT, 1), I find it on line 489 when executing the instruction:

setsockopt(s, IPPROTO_TCP, TCP_NOOPT, (char*)&val, sizeof(val))

And the second error: connect() failed: -2147454932, I find it on line 502, when executing the instruction:

err = connect(s, (struct sockaddr*) &addr, addrlen);

If I add the perror() command below those lines I get the following error message:
connect(): : Socket operation on non-socket

I don’t have much knowledge of Sockets or how they are implemented in Haiku, but studying the function I have not found any unusual parameters, but I hope a more experienced developer can help me correct this problem.

I attach a link to the Github repo to replicate the problem:
moonlight-embedded

On the server computer you can install sunshine to make the connection

1 Like

Wild guess, but did you link the binary with “libnetwork”?

Could you try this instead of the patch you used? (not sure it fixes anything aside from the socklen_t error in the build).

#if defined(__HAIKU__)
    #include <sys/sockio.h>
#endif

#if !defined(HAS_SOCKLEN_T) && !defined(__socklen_t_defined) && !defined(__HAIKU__)
typedef int socklen_t;
#endif

EDIT: without it (or your patch) it fails with:

[  1%] Building C object libgamestream/CMakeFiles/moonlight-common.dir/__/third_party/moonlight-common-c/enet/unix.c.o
/Opslag/wip/moonlight-embedded/third_party/moonlight-common-c/enet/unix.c:172:13: error: conflicting types for 'socklen_t'; have 'int'
  172 | typedef int socklen_t;
      |             ^~~~~~~~~
In file included from /Opslag/wip/moonlight-embedded/third_party/moonlight-common-c/enet/unix.c:18:
/boot/system/develop/headers/posix/sys/socket.h:15:18: note: previous declaration of 'socklen_t' with type 'socklen_t' {aka 'unsigned int'}
   15 | typedef uint32_t socklen_t;
      |                  ^~~~~~~~~
/Opslag/wip/moonlight-embedded/third_party/moonlight-common-c/enet/unix.c:304:1: error: conflicting types for 'enet_address_set_address'; have 'int(ENetAddress *, struct sockaddr *, socklen_t)' {aka 'int(struct _ENetAddress *, struct sockaddr *, int)'}
  304 | enet_address_set_address (ENetAddress * address, struct sockaddr * addr, socklen_t addrlen)
      | ^~~~~~~~~~~~~~~~~~~~~~~~

So I see some of the errors mentioned earlier.

connect() tells you that the value in “s” is not a socket (created with socket()). So, you can look at that variable: how was it initialized? What value does it have?

I can think of 3 options here:

  • it was not initialized at all, or it was corrupted by somethinge and it is a value that doesn’t make any sense
  • there was an error and it is set to -1
  • it is not a socket, but a regular file descriptor

The variable “s” is created with this code:

// Create a non-blocking TCP socket
s = createSocket(dstaddr->ss_family, SOCK_STREAM, IPPROTO_TCP, true);
if (s == INVALID_SOCKET) {
    return INVALID_SOCKET;
}

And the createSocket() function is this:

SOCKET createSocket(int addressFamily, int socketType, int protocol, bool nonBlocking) {
    SOCKET s;

    s = socket(addressFamily, socketType, protocol);
    if (s == INVALID_SOCKET) {
        Limelog("socket() failed: %d\n", (int)LastSocketError());
        return INVALID_SOCKET;
    }

#ifdef LC_DARWIN
    {
        // Disable SIGPIPE on iOS
        int val = 1;
        setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (char*)&val, sizeof(val));
    }
#endif

    if (nonBlocking) {
        setSocketNonBlocking(s, true);
    }

    return s;
}

I attach the complete code of the three functions involved: connectTcpSocket(), createSocket(), setSocketNonBlocking()

https://pastebin.com/1nH7Yq02

From what I was reading in the documentation, the socket seems to be correctly initialized.

I tried this change in unix.c and it fixes the compilation issue, but has no effect on the socket issue

1 Like

Was worth a try. :slight_smile:

Do you actually get a valid socket back from socket() though? strace may help in diagnosing problems here.

With the help from @cocobean I managed to make it work, in a slightly tricky way.
When I compile with the following commands:

cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build .

It generates an executable that works, even without modifying CMakeLists.txt or adding the line:

target_link_libraries(moonlight network)

I imagine that internally CMake is doing a different linking when adding the Release flag. Although this is a temporary “solution”, I do not think it is the most appropriate, nor the final solution

If I compile with the Debug flag it stops working, or if I don’t specify any flag it doesn’t work either, I don’t know what to modify in the CMakeLists.txt so that it works in all scenarios :sweat_smile:

2 Likes

cmake build in release mode will enable -DNDEBUG, which will disable all calls to assert() in the code.

It’s quite possible that the code has assert() on things that fails on Haiku, but are not that important after all, since the thing still works :slight_smile:

2 Likes