Skip to content

Commit 8ec080b

Browse files
refactor: websocket; allow passing the frame type up the stack
1 parent 27ae746 commit 8ec080b

File tree

9 files changed

+40
-36
lines changed

9 files changed

+40
-36
lines changed

include/dpp/discordclient.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ class DPP_EXPORT discord_client : public websocket_client
483483
* @param buffer The entire buffer content from the websocket client
484484
* @returns True if a frame has been handled
485485
*/
486-
virtual bool handle_frame(const std::string &buffer);
486+
virtual bool handle_frame(const std::string &buffer, ws_opcode opcode);
487487

488488
/**
489489
* @brief Handle a websocket error.

include/dpp/discordvoiceclient.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -780,7 +780,7 @@ class DPP_EXPORT discord_voice_client : public websocket_client
780780
* @return bool True if a frame has been handled
781781
* @throw dpp::exception If there was an error processing the frame, or connection to UDP socket failed
782782
*/
783-
virtual bool handle_frame(const std::string &buffer);
783+
virtual bool handle_frame(const std::string &buffer, ws_opcode opcode);
784784

785785
/**
786786
* @brief Handle a websocket error.

include/dpp/sslclient.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ class DPP_EXPORT ssl_client
242242
* @param data Data to be written to the buffer.
243243
* @note The data may not be written immediately and may be written at a later time to the socket.
244244
*/
245-
virtual void write(const std::string_view data);
245+
void socket_write(const std::string_view data);
246246

247247
/**
248248
* @brief Close socket connection

include/dpp/wsclient.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,12 @@ enum ws_opcode : uint8_t {
9191
/**
9292
* @brief Low level pong.
9393
*/
94-
OP_PONG = 0x0a
94+
OP_PONG = 0x0a,
95+
96+
/**
97+
* @brief Automatic selection of type
98+
*/
99+
OP_AUTO = 0xff,
95100
};
96101

97102
/**
@@ -189,7 +194,7 @@ class DPP_EXPORT websocket_client : public ssl_client {
189194
* @brief Write to websocket. Encapsulates data in frames if the status is CONNECTED.
190195
* @param data The data to send.
191196
*/
192-
virtual void write(const std::string_view data);
197+
virtual void write(const std::string_view data, ws_opcode _opcode = OP_AUTO);
193198

194199
/**
195200
* @brief Processes incoming frames from the SSL socket input buffer.
@@ -206,9 +211,10 @@ class DPP_EXPORT websocket_client : public ssl_client {
206211
* @brief Receives raw frame content only without headers
207212
*
208213
* @param buffer The buffer contents
214+
* @param opcode Frame type, e.g. OP_TEXT, OP_BINARY
209215
* @return True if the frame was successfully handled. False if no valid frame is in the buffer.
210216
*/
211-
virtual bool handle_frame(const std::string& buffer);
217+
virtual bool handle_frame(const std::string& buffer, ws_opcode opcode);
212218

213219
/**
214220
* @brief Called upon error frame.

src/dpp/discordclient.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ void discord_client::run()
220220
this->thread_id = runner->native_handle();
221221
}
222222

223-
bool discord_client::handle_frame(const std::string &buffer)
223+
bool discord_client::handle_frame(const std::string &buffer, ws_opcode opcode)
224224
{
225225
std::string& data = (std::string&)buffer;
226226

@@ -340,7 +340,7 @@ bool discord_client::handle_frame(const std::string &buffer)
340340
}
341341
}
342342
};
343-
this->write(jsonobj_to_string(obj));
343+
this->write(jsonobj_to_string(obj), protocol == ws_etf ? OP_BINARY : OP_TEXT);
344344
resumes++;
345345
} else {
346346
/* Full connect */
@@ -369,7 +369,7 @@ bool discord_client::handle_frame(const std::string &buffer)
369369
}
370370
}
371371
};
372-
this->write(jsonobj_to_string(obj));
372+
this->write(jsonobj_to_string(obj), protocol == ws_etf ? OP_BINARY : OP_TEXT);
373373
this->connect_time = creator->last_identify = time(nullptr);
374374
reconnects++;
375375
}
@@ -539,7 +539,7 @@ void discord_client::one_second_timer()
539539
ping_start = utility::time_f();
540540
last_ping_message.clear();
541541
}
542-
this->write(message);
542+
this->write(message, protocol == ws_etf ? OP_BINARY : OP_TEXT);
543543
}
544544
}
545545

src/dpp/discordvoiceclient.cpp

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -486,17 +486,15 @@ int discord_voice_client::udp_recv(char* data, size_t max_length)
486486
return (int) recv(this->fd, data, (int)max_length, 0);
487487
}
488488

489-
bool discord_voice_client::handle_frame(const std::string &data)
489+
bool discord_voice_client::handle_frame(const std::string &data, ws_opcode opcode)
490490
{
491491
log(dpp::ll_trace, std::string("R: ") + data);
492492
json j;
493493

494494
/**
495-
* Because all discord JSON must be valid UTF-8, if we see a packet with the 2nd character
496-
* being less than 32 (' '), then we know it is a binary MLS frame, as all the binary frame
497-
* opcodes are purposefully less than 32. We then try and parse it as MLS binary.
495+
* MLS frames come in as type OP_BINARY, we can also reply to them as type OP_BINARY.
498496
*/
499-
if (data.size() >= sizeof(dave_binary_header_t) && data[2] <= voice_client_dave_mls_invalid_commit_welcome) {
497+
if (opcode == OP_BINARY && data.size() >= sizeof(dave_binary_header_t)) {
500498

501499
/* Debug, remove once this is working */
502500
std::cout << dpp::utility::debug_dump((uint8_t*)(data.data()), data.length()) << "\n";
@@ -627,7 +625,7 @@ bool discord_voice_client::handle_frame(const std::string &data)
627625
}
628626
}
629627
};
630-
this->write(obj.dump(-1, ' ', false, json::error_handler_t::replace));
628+
this->write(obj.dump(-1, ' ', false, json::error_handler_t::replace), OP_TEXT);
631629
} else {
632630
log(dpp::ll_debug, "Connecting new voice session (DAVE: " + std::string(dave_version == dave_version_1 ? "Enabled" : "Disabled") + ")...");
633631
json obj = {
@@ -643,7 +641,7 @@ bool discord_voice_client::handle_frame(const std::string &data)
643641
}
644642
}
645643
};
646-
this->write(obj.dump(-1, ' ', false, json::error_handler_t::replace));
644+
this->write(obj.dump(-1, ' ', false, json::error_handler_t::replace), OP_TEXT);
647645
}
648646
this->connect_time = time(nullptr);
649647
}
@@ -744,7 +742,7 @@ bool discord_voice_client::handle_frame(const std::string &data)
744742
}
745743
}
746744
}
747-
}).dump(-1, ' ', false, json::error_handler_t::replace));
745+
}).dump(-1, ' ', false, json::error_handler_t::replace), OP_TEXT);
748746
}
749747
}
750748
break;
@@ -1204,7 +1202,7 @@ void discord_voice_client::one_second_timer()
12041202
if (!message_queue.empty()) {
12051203
std::string message = message_queue.front();
12061204
message_queue.pop_front();
1207-
this->write(message);
1205+
this->write(message, OP_TEXT);
12081206
}
12091207
}
12101208

src/dpp/httpsclient.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ void https_client::connect()
5858
map_headers += k + ": " + v + "\r\n";
5959
}
6060
if (this->sfd != SOCKET_ERROR) {
61-
this->write(
61+
this->socket_write(
6262
this->request_type + " " + this->path + " HTTP/" + http_protocol + "\r\n"
6363
"Host: " + this->hostname + "\r\n"
6464
"pragma: no-cache\r\n"

src/dpp/sslclient.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ void ssl_client::connect()
379379
}
380380
}
381381

382-
void ssl_client::write(const std::string_view data)
382+
void ssl_client::socket_write(const std::string_view data)
383383
{
384384
/* If we are in nonblocking mode, append to the buffer,
385385
* otherwise just use SSL_write directly. The only time we

src/dpp/wsclient.cpp

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ void websocket_client::connect()
6161
{
6262
state = HTTP_HEADERS;
6363
/* Send headers synchronously */
64-
this->write(
64+
this->socket_write(
6565
"GET " + this->path + " HTTP/1.1\r\n"
6666
"Host: " + this->hostname + "\r\n"
6767
"pragma: no-cache\r\n"
@@ -73,7 +73,7 @@ void websocket_client::connect()
7373
);
7474
}
7575

76-
bool websocket_client::handle_frame(const std::string& buffer)
76+
bool websocket_client::handle_frame(const std::string& buffer, ws_opcode opcode)
7777
{
7878
/* This is a stub for classes that derive the websocket client */
7979
return true;
@@ -111,17 +111,17 @@ size_t websocket_client::fill_header(unsigned char* outbuf, size_t sendlength, w
111111
}
112112

113113

114-
void websocket_client::write(const std::string_view data)
114+
void websocket_client::write(const std::string_view data, ws_opcode _opcode)
115115
{
116116
if (state == HTTP_HEADERS) {
117117
/* Simple write */
118-
ssl_client::write(data);
118+
ssl_client::socket_write(data);
119119
} else {
120120
unsigned char out[MAXHEADERSIZE];
121-
size_t s = this->fill_header(out, data.length(), this->data_opcode);
121+
size_t s = this->fill_header(out, data.length(), _opcode == OP_AUTO ? this->data_opcode : _opcode);
122122
std::string header((const char*)out, s);
123-
ssl_client::write(header);
124-
ssl_client::write(data);
123+
ssl_client::socket_write(header);
124+
ssl_client::socket_write(data);
125125
}
126126
}
127127

@@ -175,7 +175,7 @@ bool websocket_client::handle_buffer(std::string& buffer)
175175
}
176176
} else if (state == CONNECTED) {
177177
/* Process packets until we can't (buffer will erase data until parseheader returns false) */
178-
while (this->parseheader(buffer)){}
178+
while (this->parseheader(buffer)) { }
179179
}
180180

181181
return true;
@@ -249,7 +249,7 @@ bool websocket_client::parseheader(std::string& data)
249249
handle_ping(data.substr(payloadstartoffset, len));
250250
} else if ((opcode & ~WS_FINBIT) != OP_PONG) { /* Otherwise, handle everything else apart from a PONG. */
251251
/* Pass this frame to the deriving class */
252-
this->handle_frame(data.substr(payloadstartoffset, len));
252+
this->handle_frame(data.substr(payloadstartoffset, len), static_cast<ws_opcode>(opcode & ~WS_FINBIT));
253253
}
254254

255255
/* Remove this frame from the input buffer */
@@ -286,8 +286,8 @@ void websocket_client::one_second_timer()
286286
std::string payload = "keepalive";
287287
size_t s = this->fill_header(out, payload.length(), OP_PING);
288288
std::string header((const char*)out, s);
289-
ssl_client::write(header);
290-
ssl_client::write(payload);
289+
ssl_client::socket_write(header);
290+
ssl_client::socket_write(payload);
291291
}
292292
}
293293

@@ -297,8 +297,8 @@ void websocket_client::handle_ping(const std::string &payload)
297297
unsigned char out[MAXHEADERSIZE];
298298
size_t s = this->fill_header(out, payload.length(), OP_PONG);
299299
std::string header((const char*)out, s);
300-
ssl_client::write(header);
301-
ssl_client::write(payload);
300+
ssl_client::socket_write(header);
301+
ssl_client::socket_write(payload);
302302
}
303303

304304
void websocket_client::send_close_packet()
@@ -312,8 +312,8 @@ void websocket_client::send_close_packet()
312312

313313
size_t s = this->fill_header(out, payload.length(), OP_CLOSE);
314314
std::string header((const char*)out, s);
315-
ssl_client::write(header);
316-
ssl_client::write(payload);
315+
ssl_client::socket_write(header);
316+
ssl_client::socket_write(payload);
317317
}
318318

319319
void websocket_client::error(uint32_t errorcode)

0 commit comments

Comments
 (0)