Commit 411412f90296ed596340fe3928d6b9a46934f39f

Authored by Wiebe Cazemier
1 parent 67df67f0

Fix length bug in sending websocket frames

One part is a fix, where the frame was advertised to be bigger than it
was.

The other change is making it possible to send chunks larger than the
initial buffer size, by resizing the buffer (and resetting it later).
client.cpp
... ... @@ -315,6 +315,7 @@ std::string Client::getKeepAliveInfoString() const
315 315 void Client::resetBuffersIfEligible()
316 316 {
317 317 readbuf.resetSizeIfEligable(initialBufferSize);
  318 + ioWrapper.resetBuffersIfEligible();
318 319  
319 320 // Write buffers are written to from other threads, and this resetting takes place from the Client's own thread, so we need to lock.
320 321 std::lock_guard<std::mutex> locker(writeBufMutex);
... ...
iowrapper.cpp
... ... @@ -579,27 +579,28 @@ ssize_t IoWrapper::websocketBytesToReadBuffer(void *buf, const size_t nbytes, Io
579 579 * @param nbytes. The amount of bytes. Can be 0, for just an empty websocket frame.
580 580 * @return
581 581 */
582   -ssize_t IoWrapper::writeAsMuchOfBufAsWebsocketFrame(const void *buf, size_t nbytes, WebsocketOpcode opcode)
  582 +ssize_t IoWrapper::writeAsMuchOfBufAsWebsocketFrame(const void *buf, const size_t nbytes, WebsocketOpcode opcode)
583 583 {
584 584 // We do allow pong frames to generate a zero payload packet, but for binary, that's not necessary.
585 585 if (nbytes == 0 && opcode == WebsocketOpcode::Binary)
586 586 return 0;
587 587  
588   - ssize_t nBytesReal = 0;
  588 + websocketWriteRemainder.ensureFreeSpace(nbytes + WEBSOCKET_MAX_SENDING_HEADER_SIZE, 131072);
  589 + const ssize_t nBytesReal = std::min<size_t>(nbytes, websocketWriteRemainder.freeSpace() - WEBSOCKET_MAX_SENDING_HEADER_SIZE);
589 590  
590 591 // We normally wrap each write in a frame, but if a previous one didn't fit in the system's write buffers, we're still working on it.
591 592 if (websocketWriteRemainder.freeSpace() > WEBSOCKET_MAX_SENDING_HEADER_SIZE)
592 593 {
593 594 uint8_t extended_payload_length_num_bytes = 0;
594 595 uint8_t payload_length = 0;
595   - if (nbytes < 126)
596   - payload_length = nbytes;
597   - else if (nbytes >= 126 && nbytes <= 0xFFFF)
  596 + if (nBytesReal < 126)
  597 + payload_length = nBytesReal;
  598 + else if (nBytesReal >= 126 && nBytesReal <= 0xFFFF)
598 599 {
599 600 payload_length = 126;
600 601 extended_payload_length_num_bytes = 2;
601 602 }
602   - else if (nbytes > 0xFFFF)
  603 + else if (nBytesReal > 0xFFFF)
603 604 {
604 605 payload_length = 127;
605 606 extended_payload_length_num_bytes = 8;
... ... @@ -613,7 +614,6 @@ ssize_t IoWrapper::writeAsMuchOfBufAsWebsocketFrame(const void *buf, size_t nbyt
613 614 const int header_length = x + extended_payload_length_num_bytes;
614 615  
615 616 // This block writes the extended payload length.
616   - nBytesReal = std::min<size_t>(nbytes, websocketWriteRemainder.freeSpace() - header_length);
617 617 const uint64_t nbytes64 = nBytesReal;
618 618 for (int z = extended_payload_length_num_bytes - 1; z >= 0; z--)
619 619 {
... ... @@ -667,3 +667,10 @@ ssize_t IoWrapper::writeWebsocketAndOrSsl(int fd, const void *buf, size_t nbytes
667 667 return n;
668 668 }
669 669 }
  670 +
  671 +void IoWrapper::resetBuffersIfEligible()
  672 +{
  673 + const size_t sz = websocket ? initialBufferSize : 0;
  674 + websocketPendingBytes.resetSizeIfEligable(sz),
  675 + websocketWriteRemainder.resetSizeIfEligable(sz);
  676 +}
... ...
iowrapper.h
... ... @@ -118,7 +118,7 @@ class IoWrapper
118 118 ssize_t websocketBytesToReadBuffer(void *buf, const size_t nbytes, IoWrapResult *error);
119 119 ssize_t readOrSslRead(int fd, void *buf, size_t nbytes, IoWrapResult *error);
120 120 ssize_t writeOrSslWrite(int fd, const void *buf, size_t nbytes, IoWrapResult *error);
121   - ssize_t writeAsMuchOfBufAsWebsocketFrame(const void *buf, size_t nbytes, WebsocketOpcode opcode = WebsocketOpcode::Binary);
  121 + ssize_t writeAsMuchOfBufAsWebsocketFrame(const void *buf, const size_t nbytes, WebsocketOpcode opcode = WebsocketOpcode::Binary);
122 122 public:
123 123 IoWrapper(SSL *ssl, bool websocket, const size_t initialBufferSize, Client *parent);
124 124 ~IoWrapper();
... ... @@ -138,6 +138,8 @@ public:
138 138  
139 139 ssize_t readWebsocketAndOrSsl(int fd, void *buf, size_t nbytes, IoWrapResult *error);
140 140 ssize_t writeWebsocketAndOrSsl(int fd, const void *buf, size_t nbytes, IoWrapResult *error);
  141 +
  142 + void resetBuffersIfEligible();
141 143 };
142 144  
143 145 #endif // IOWRAPPER_H
... ...