Search code examples
c++linuxtcppayloadlibwebsockets

libwebsocket: unable to write frame bigger than 7160 bytes


I'm addressing an issue with WebSocket that I'm not able to understand.
Please, use the code below as reference:

int write_buffer_size = 8000 +
                LWS_SEND_BUFFER_PRE_PADDING +
                LWS_SEND_BUFFER_POST_PADDING;

char *write_buffer = new unsigned char[write_buffer_size];

/* ... other code
   write_buffer is filled in some way that is not important for the question
*/

n = libwebsocket_write(wsi, &write_buffer[LWS_SEND_BUFFER_PRE_PADDING], write_len,
            (libwebsocket_write_protocol)write_mode);
    if (n < 0) {
        cerr << "ERROR " << n << " writing to socket, hanging up" << endl;
        if (utils) {
            log = "wsmanager::error: hanging up writing to websocket";
            utils->writeLog(log);
        }
        return -1;
    }
    if (n < write_len) {
        cerr << "Partial write: " << n << " < " << write_len << endl;
        if (utils) {
            log = "wsmanager-error: websocket partial write";
            utils->writeLog(log);
        }
        return -1;
    }

When I try to send data bigger than 7160 bytes I receive always the same error, e.g. Partial write: 7160 < 8000.
Do you have any kind of explanation for that behavior?
I have allocated a buffer with 8000 bytes reserved for the payload so I was expecting to be able to send a maximum amount of data of 8K, but 7160 (bytes) seems to be the maximum amount of data I can send.
Any help is appreciated, thanks!


Solution

  • We solved the issue updating libwebsockets to 1.7.3 version.
    We also optimized the code using a custom callback called when the channel is writable

    void
    WSManager::onWritable() {
        int ret, n;
        struct fragment *frg;
    
        pthread_mutex_lock(&send_queue_mutex);
    
        if (!send_queue.empty() && !lws_partial_buffered(wsi)) {
            frg = send_queue.front();
    
            n = lws_write(wsi, frg->content + LWS_PRE, frg->len, (lws_write_protocol)frg->mode);
            ret = checkWsWrite(n, frg->len);
    
            if (ret >= 0 && !lws_partial_buffered(wsi)) {
                if (frg->mode == WS_SINGLE_FRAGMENT || frg->mode == WS_LAST_FRAGMENT)
                    signalResponseSent();
    
                // pop fragment and free memory only if lws_write was successful
                send_queue.pop();
                delete(frg);
            }
        }
        pthread_mutex_unlock(&send_queue_mutex);
    }