diff --git a/wled00/e131.cpp b/wled00/e131.cpp index a6123e7a..27ce1e3c 100644 --- a/wled00/e131.cpp +++ b/wled00/e131.cpp @@ -31,11 +31,19 @@ void handleDDPPacket(e131_packet_t* p) { uint32_t start = htonl(p->channelOffset) / ddpChannelsPerLed; start += DMXAddress / ddpChannelsPerLed; - uint16_t stop = start + htons(p->dataLen) / ddpChannelsPerLed; + uint16_t dataLen = htons(p->dataLen); + unsigned stop = start + dataLen / ddpChannelsPerLed; uint8_t* data = p->data; uint16_t c = 0; if (p->flags & DDP_TIMECODE_FLAG) c = 4; //packet has timecode flag, we do not support it, but data starts 4 bytes later + unsigned numLeds = stop - start; // stop >= start is guaranteed + unsigned maxDataIndex = c + numLeds * ddpChannelsPerLed; // validate bounds before accessing data array + if (maxDataIndex > dataLen) { + DEBUG_PRINTLN(F("DDP packet data bounds exceeded, rejecting.")); + return; + } + if (realtimeMode != REALTIME_MODE_DDP) ddpSeenPush = false; // just starting, no push yet realtimeLock(realtimeTimeoutMs, REALTIME_MODE_DDP); diff --git a/wled00/ws.cpp b/wled00/ws.cpp index e061b6a6..0c819934 100644 --- a/wled00/ws.cpp +++ b/wled00/ws.cpp @@ -7,6 +7,16 @@ static volatile uint16_t wsLiveClientId = 0; // WLEDMM added "static" static volatile unsigned long wsLastLiveTime = 0; // WLEDMM + +// define some constants for binary protocols, dont use defines but C++ style constexpr +constexpr uint8_t BINARY_PROTOCOL_GENERIC = 0xFF; // generic / auto detect NOT IMPLEMENTED +constexpr uint8_t BINARY_PROTOCOL_E131 = P_E131; // = 0, untested! +constexpr uint8_t BINARY_PROTOCOL_ARTNET = P_ARTNET; // = 1, untested! +constexpr uint8_t BINARY_PROTOCOL_DDP = P_DDP; // = 2 + +uint16_t wsLiveClientId = 0; +unsigned long wsLastLiveTime = 0; + //uint8_t* wsFrameBuffer = nullptr; #if !defined(ARDUINO_ARCH_ESP32) || defined(WLEDMM_FASTPATH) // WLEDMM @@ -32,7 +42,7 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp // data packet AwsFrameInfo * info = (AwsFrameInfo*)arg; if(info->final && info->index == 0 && info->len == len){ - // the whole message is in a single frame and we got all of its data (max. 1450 bytes) + // the whole message is in a single frame and we got all of its data (max. 1428 bytes / ESP8266: 528 bytes) if(info->opcode == WS_TEXT) { if (len > 0 && len < 10 && data[0] == 'p') { @@ -74,8 +84,29 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp // force broadcast in 500ms after updating client //lastInterfaceUpdate = millis() - (INTERFACE_UPDATE_COOLDOWN -500); // ESP8266 does not like this } + }else if (info->opcode == WS_BINARY) { + // first byte determines protocol. Note: since e131_packet_t is "packed", the compiler handles alignment issues + //DEBUG_PRINTF_P(PSTR("WS binary message: len %u, byte0: %u\n"), len, data[0]); + int offset = 1; // offset to skip protocol byte + switch (data[0]) { + case BINARY_PROTOCOL_E131: + handleE131Packet((e131_packet_t*)&data[offset], client->remoteIP(), P_E131); + break; + case BINARY_PROTOCOL_ARTNET: + handleE131Packet((e131_packet_t*)&data[offset], client->remoteIP(), P_ARTNET); + break; + case BINARY_PROTOCOL_DDP: + if (len < 10 + offset) return; // DDP header is 10 bytes (+1 protocol byte) + size_t ddpDataLen = (data[8+offset] << 8) | data[9+offset]; // data length in bytes from DDP header + uint8_t flags = data[0+offset]; + if ((flags & DDP_TIMECODE_FLAG) ) ddpDataLen += 4; // timecode flag adds 4 bytes to data length + if (len < (10 + offset + ddpDataLen)) return; // not enough data, prevent out of bounds read + // could be a valid DDP packet, forward to handler + handleE131Packet((e131_packet_t*)&data[offset], client->remoteIP(), P_DDP); + } } } else { + DEBUG_PRINTF_P(PSTR("WS multipart message: final %u index %u len %u total %u\n"), info->final, info->index, len, (uint32_t)info->len); //message is comprised of multiple frames or the frame is split into multiple packets //if(info->index == 0){ //if (!wsFrameBuffer && len < 4096) wsFrameBuffer = new uint8_t[4096];