int websocket_parse(Websocket *websocket, void *buffer, int length) { switch (websocket->state) { case WEBSOCKET_STATE_WAIT_FOR_HANDSHAKE: case WEBSOCKET_STATE_FOUND_HANDSHAKE_KEY: return websocket_parse_handshake(websocket, buffer, length); case WEBSOCKET_STATE_HANDSHAKE_DONE: return websocket_parse_header(websocket, buffer, length); case WEBSOCKET_STATE_HEADER_DONE: return websocket_parse_data(websocket, buffer, length); } log_error("In invalid WebSocket state (%d)", websocket->state); return -1; }
uint8_t ethernet_websocket_read_data_tcp(const uint8_t socket, uint8_t *buffer, const uint8_t length) { uint8_t read_length = 0; switch(ethernet_websocket_state[socket]) { case WEBSOCKET_STATE_WAIT_FOR_HANDSHAKE: { uint8_t data[100]; uint8_t handshake_length = ethernet_low_level_read_data_tcp(socket, data, 100); if(handshake_length != 0) { websocket_parse_handshake((char*)data, handshake_length, ethernet_websocket_answer_callback, ethernet_websocket_answer_error, socket); } return 0; } case WEBSOCKET_STATE_HANDSHAKE_DONE: { // buffer with max possible size of websocket header ethernet_websocket_frame[socket].fin = 1; ethernet_websocket_to_read[socket] -= ethernet_low_level_read_data_tcp(socket, ((uint8_t*)ðernet_websocket_frame[socket]) + (sizeof(WebsocketFrame) - ethernet_websocket_to_read[socket]), ethernet_websocket_to_read[socket]); if(ethernet_websocket_to_read[socket] != 0) { return 0; } ethernet_websocket_state[socket] = WEBSOCKET_STATE_WEBSOCKET_HEADER_DONE; if(ethernet_websocket_frame[socket].mask != 1) { // mask = 0 from browser is not allowed! logethe("Mask=0 not allowed\n\r"); ethernet_low_level_emergency_disconnect(socket); return 0; } // We currently don't support 16 bit or 64 bit length if(ethernet_websocket_frame[socket].payload_length == 126 || ethernet_websocket_frame[socket].payload_length == 127) { ethernet_low_level_emergency_disconnect(socket); return 0; } switch(ethernet_websocket_frame[socket].opcode) { case WEBSOCKET_OPCODE_CONTINUATION_FRAME: case WEBSOCKET_OPCODE_TEXT_FRAME: { // Continuation and text frame not allowed logethe("Opcode not supported: %d\n\r", ethernet_websocket_frame[socket].opcode); ethernet_low_level_emergency_disconnect(socket); return 0; } case WEBSOCKET_OPCODE_BINARY_FRAME: { ethernet_websocket_mask_mod[socket] = 0; ethernet_websocket_to_read[socket] = ethernet_websocket_frame[socket].payload_length; break; } case WEBSOCKET_OPCODE_CLOSE_FRAME: { ethernet_websocket_close_frame(ðernet_websocket_frame[socket], socket); break; } case WEBSOCKET_OPCODE_PING_FRAME: { logethe("Opcode not supported: %d\n\r", ethernet_websocket_frame[socket].opcode); ethernet_low_level_emergency_disconnect(socket); break; } case WEBSCOKET_OPCODE_PONG_FRAME: { logethe("Opcode not supported: %d\n\r", ethernet_websocket_frame[socket].opcode); ethernet_low_level_emergency_disconnect(socket); break; } } return 0; } case WEBSOCKET_STATE_WEBSOCKET_HEADER_DONE: { // Websocket header is done, we can just read the data read_length = ethernet_low_level_read_data_tcp(socket, buffer, MIN(length, ethernet_websocket_to_read[socket])); for(uint8_t i = 0; i < read_length; i++) { buffer[i] ^= ethernet_websocket_frame[socket].masking_key[ethernet_websocket_mask_mod[socket]]; ethernet_websocket_mask_mod[socket]++; if(ethernet_websocket_mask_mod[socket] >= WEBSOCKET_MASK_LENGTH) { ethernet_websocket_mask_mod[socket] = 0; } } ethernet_websocket_to_read[socket] -= read_length; if(ethernet_websocket_to_read[socket] == 0) { ethernet_websocket_state[socket] = WEBSOCKET_STATE_HANDSHAKE_DONE; ethernet_websocket_to_read[socket] = sizeof(WebsocketFrame); } break; } default: { logethe("Invalid Ethernet Websocket state: %d\n\r", (int)ethernet_websocket_state); break; } } return read_length; }