uNetworking / uWebSockets

Simple, secure & standards compliant web server for the most demanding of applications
Apache License 2.0
17.29k stars 1.75k forks source link

Encounter "Error: Cork buffer must not be acquired without checking canCork!" #1774

Closed twenty2811 closed 1 month ago

twenty2811 commented 1 month ago

Description:

When using uWebSockets as a server, I had occasionally encountered the following message:

"Error: Cork buffer must not be acquired without checking canCork!"

it would stop my whole program.

Since the "bug" is not easily reproduced, I traced the source code and try to figure out what might be the reason for the error.

The error message comes from "AsyncSocket.h", and the "cork()" function might be called from the following code from "WebSocketContext.h" (the other place is "HttpContext.h", but that has less possibility in my use case):

/* Handle WebSocket data streams */
        us_socket_context_on_data(SSL, getSocketContext(), [](auto *s, char *data, int length) {

            /* We need the websocket data */
            WebSocketData *webSocketData = (WebSocketData *) (us_socket_ext(SSL, s));

            /* When in websocket shutdown mode, we do not care for ANY message, whether responding close frame or not.
             * We only care for the TCP FIN really, not emitting any message after closing is key */
            if (webSocketData->isShuttingDown) {
                return s;
            }

            auto *webSocketContextData = (WebSocketContextData<SSL, USERDATA> *) us_socket_context_ext(SSL, us_socket_context(SSL, (us_socket_t *) s));
            auto *asyncSocket = (AsyncSocket<SSL> *) s;

            /* Every time we get data and not in shutdown state we simply reset the timeout */
            asyncSocket->timeout(webSocketContextData->idleTimeoutComponents.first);
            webSocketData->hasTimedOut = false;

            /* We always cork on data */
            asyncSocket->cork();
...

Questions:

The error message states that "canCork()" should always be called before "cork()", but here "asyncSocket->cork();" without this check beforehand. So, my questions are the following:

Environment:

uNetworkingAB commented 1 month ago

You can't leave a socket corked, if you cork it you need to uncork it before returning from whatever event you were called

uNetworkingAB commented 1 month ago

It can also be that you have some threading misuse. Nobody in JavaScript camp has reported this issue, but I have seen it reported by C++ users who play with corking / threading. You are doing C++, yes?

twenty2811 commented 1 month ago

Thank you for you reply. Yes, I'm using in C++ environment. I'm still thinking your first reply and trying to figure out what could the the reasons.

Environment:

twenty2811 commented 1 month ago

By the way, uWebSockets is not multithreaded in my use case, though for each new connection, I started a websocket connection with another websocket server.

Correction:

twenty2811 commented 1 month ago

The problem seems to relate to the new threads that holds the "uWS::WebSocket<_> *ws" pointer for later use, which is against the rule of this library "isolated to only one thread".