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

Cannot connect to CoilMQ: "Failed to connect at web socket level" #261

Closed
EugeneSid opened this issue Sep 12, 2022 · 9 comments
Closed

Cannot connect to CoilMQ: "Failed to connect at web socket level" #261

EugeneSid opened this issue Sep 12, 2022 · 9 comments
Labels
question Further information is requested

Comments

@EugeneSid
Copy link

I'm using STOMP for interaction between android device and raspberry pi. As a server I have Coilmq STOMP server this installed on RPi4 and successfully tested with stomp.py - a python library of STOMP client.

By using krossbow STOMP client library I receive "GET" command only with URL and headers which doesn't have STOMP initial commands (STOMP or CONNECT) but instead it looks like WEB STOMP version:

b'GET /queue/camera HTTP/1.1\r\nHost: 172.18.5.38:61613\r\nAccept-Charset: UTF-8\r\nAccept: */*\r\nUpgrade: websocket\r\nConnection: upgrade\r\nSec-WebSocket-Key: ZDEzNzIyYzEwOGU5MDdkNw==\r\nSec-WebSocket-Version: 13\r\nUser-Agent: Ktor client\r\n\r\n'

And because of this I'm unable to connect to the server..
Android log info:

Failure(org.hildan.krossbow.stomp.WebSocketConnectionException: Failed to connect at web socket level to ws://172.18.5.38:61613/queue/cam)

The coilmq log shorted info:

Exception occurred during processing of request from ('172.18.4.14', 17474)
Traceback (most recent call last):
...
  File "/usr/local/lib/python3.9/dist-packages/coilmq/util/frames.py", line 51, in parse_headers
    return preamble_lines[0], OrderedDict([l.split(':') for l in preamble_lines[1:]])
ValueError: too many values to unpack (expected 2)

On the other hand, when I run python STOMP client, there is STOMP command and the message looks like:

b'STOMP\naccept-version:1.1\nlogin:admin\npasscode:password\n\n\x00'

And after that I'm successfully connected to the server.

Stomp client have been build on KtorWebSocketClient as in official documentation and using that I attempted to connect via local network.

Any Idea what I'm doing wrong? Thank you!

@joffrey-bion
Copy link
Owner

Hi, thanks a lot for this report and the details in it.

By using krossbow STOMP client library I receive "GET" command only with URL and headers which doesn't have STOMP initial commands (STOMP or CONNECT) but instead it looks like WEB STOMP version

Could you please clarify what you mean by "WEB STOMP"? Do you mean this?

I think this might be the source of the issue here. STOMP is an application-level protocol, so it needs a transport. The STOMP or CONNECT frame is sent on the wire via this transport. The protocol specification doesn't force the use of a particular network protocol underneath, but usually it's raw TCP or web socket. Web sockets are convenient because they already provide some framing on top of TCP.

Krossbow is a STOMP client using web socket as transport (or an emulated version of websocket via SockJS). In order to send STOMP frames (like STOMP or CONNECT), the Krossbow client first needs to connect at the web socket level. This is done via an HTTP request with an Upgrade header (as defined by the websocket RFC).

Does your STOMP server only support raw TCP connections?

@EugeneSid
Copy link
Author

Sorry for delay..

Could you please clarify what you mean by "WEB STOMP"? Do you mean this?

Yes, right.

Does your STOMP server only support raw TCP connections?

I checked CoilMQ STOMP server and I see that it listens for web socket frames.
CoilMQ STOMP server received that "GET" command inside a socket frame.
But this is the only command it gets. No other frames are coming - so no connection frame (STOMP or CONNECT command).

@joffrey-bion
Copy link
Owner

CoilMQ STOMP server received that "GET" command inside a socket frame.

Now that is quite unexpected. I'm sorry to ask you for more, but you could you please share the code using Krossbow to connect to the server? I would really like to be able to understand or reproduce the issue myself.

@EugeneSid
Copy link
Author

Yes sure.

    private val RPI_EM_LOCALHOST = "172.18.5.38"
    private val SERVER_PORT = "61613"
    private var WEBSOCKET_TOPIC = "/queue/cam"
    private var WEBSOCKET_URI = "ws://$RPI_EM_LOCALHOST:$SERVER_PORT"

    @Inject
    lateinit var stompClient: StompClient

    @Inject
    lateinit var stompSession: StompSession

    private fun connectToEm() { //called from init function
        lifecycleScope.launch {
            try {
                //val webSocket = OkHttpWebSocketClient(okHttpClient)
                stompClient = StompClient(KtorWebSocketClient())
                stompSession = stompClient.connect(
                    "$WEBSOCKET_URI$WEBSOCKET_TOPIC",
                    "admin",
                    "password"
                )
            } catch (ex: Exception) {
                when (ex) {
                    is WebSocketConnectionException, is ClassNotFoundException -> {
                        Log.e("Error:", ex.message.toString())
                    }
                    else -> throw ex
                }
            }
        }
    }

This is separated simplified part of code for RPi connection test but has problem described above.

@joffrey-bion
Copy link
Owner

joffrey-bion commented Sep 14, 2022

Thanks a lot for the quick response and the extra code.

I checked CoilMQ STOMP server and I see that it listens for web socket frames.

My Python level is close to 0, but from what I can see in the CoilMQ code, they really are just streaming a TCP connection without any web socket layer.

  • they seem to use a raw TCPServer here
  • here they receive raw bytes (it's still unclear to me what request is at that point)
  • here they directly append the raw bytes (without framing) to their custom FrameBuffer
  • then in extract_frame they directly read the raw bytes from the buffer until they get a complete STOMP frame - no websocket frame involved.

This explains why this server doesn't speak HTTP nor websocket, it is a raw TCP server. When receiving an HTTP request to open a web socket connection, the server tries to interpret the raw bytes of the HTTP protocol as a STOMP frame and fails.

Unfortunately Krossbow is a client that relies on web socket at the moment, and it is not a short term goal to support raw TCP sockets. That said, I could consider implementing it if you need it.

@joffrey-bion joffrey-bion changed the title Connect to the STOMP server problem. Cannot connect to CoilMQ "Failed to connect at web socket level" Sep 14, 2022
@joffrey-bion joffrey-bion changed the title Cannot connect to CoilMQ "Failed to connect at web socket level" Cannot connect to CoilMQ: "Failed to connect at web socket level" Sep 14, 2022
@EugeneSid
Copy link
Author

EugeneSid commented Sep 14, 2022

Now everything became clear thanks to you.
I think I'd looking for some other solution for CoilMQ communication. I really appreciate your help and I'll keep monitoring krossbow updates at least because we are using it in our main project and it works well. Also I really like how quick and good support are. Thanks a lot!

@joffrey-bion
Copy link
Owner

That's heartwarming, thanks! I try to do my best, and this kind of message really motivates me to do more!

I hope you'll find a nice alternative for this use case. Have a good one!

@charlie-niekirk
Copy link

Thanks a lot for the quick response and the extra code.

I checked CoilMQ STOMP server and I see that it listens for web socket frames.

My Python level is close to 0, but from what I can see in the CoilMQ code, they really are just streaming a TCP connection without any web socket layer.

  • they seem to use a raw TCPServer here
  • here they receive raw bytes (it's still unclear to me what request is at that point)
  • here they directly append the raw bytes (without framing) to their custom FrameBuffer
  • then in extract_frame they directly read the raw bytes from the buffer until they get a complete STOMP frame - no websocket frame involved.

This explains why this server doesn't speak HTTP nor websocket, it is a raw TCP server. When receiving an HTTP request to open a web socket connection, the server tries to interpret the raw bytes of the HTTP protocol as a STOMP frame and fails.

Unfortunately Krossbow is a client that relies on web socket at the moment, and it is not a short term goal to support raw TCP sockets. That said, I could consider implementing it if you need it.

It would be really helpful for me, I'm trying to consume a STOMP server using raw TCP sockets.

@joffrey-bion
Copy link
Owner

Thanks for letting me know. I opened the following issue, which you can upvote:
#287

@joffrey-bion joffrey-bion added the question Further information is requested label Feb 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants