mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-12 21:09:00 +00:00
Merge "res_http_websocket.c: prevent avoidable disconnections caused by write errors" into 13
This commit is contained in:
@@ -265,12 +265,12 @@ AST_OPTIONAL_API(int, ast_websocket_read_string,
|
|||||||
* \param session Pointer to the WebSocket session
|
* \param session Pointer to the WebSocket session
|
||||||
* \param opcode WebSocket operation code to place in the frame
|
* \param opcode WebSocket operation code to place in the frame
|
||||||
* \param payload Optional pointer to a payload to add to the frame
|
* \param payload Optional pointer to a payload to add to the frame
|
||||||
* \param actual_length Length of the payload (0 if no payload)
|
* \param payload_size Length of the payload (0 if no payload)
|
||||||
*
|
*
|
||||||
* \retval 0 if successfully written
|
* \retval 0 if successfully written
|
||||||
* \retval -1 if error occurred
|
* \retval -1 if error occurred
|
||||||
*/
|
*/
|
||||||
AST_OPTIONAL_API(int, ast_websocket_write, (struct ast_websocket *session, enum ast_websocket_opcode opcode, char *payload, uint64_t actual_length), { errno = ENOSYS; return -1;});
|
AST_OPTIONAL_API(int, ast_websocket_write, (struct ast_websocket *session, enum ast_websocket_opcode opcode, char *payload, uint64_t payload_size), { errno = ENOSYS; return -1;});
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Construct and transmit a WebSocket frame containing string data.
|
* \brief Construct and transmit a WebSocket frame containing string data.
|
||||||
|
|||||||
@@ -330,18 +330,19 @@ static const char *websocket_opcode2str(enum ast_websocket_opcode opcode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Write function for websocket traffic */
|
/*! \brief Write function for websocket traffic */
|
||||||
int AST_OPTIONAL_API_NAME(ast_websocket_write)(struct ast_websocket *session, enum ast_websocket_opcode opcode, char *payload, uint64_t actual_length)
|
int AST_OPTIONAL_API_NAME(ast_websocket_write)(struct ast_websocket *session, enum ast_websocket_opcode opcode, char *payload, uint64_t payload_size)
|
||||||
{
|
{
|
||||||
size_t header_size = 2; /* The minimum size of a websocket frame is 2 bytes */
|
size_t header_size = 2; /* The minimum size of a websocket frame is 2 bytes */
|
||||||
char *frame;
|
char *frame;
|
||||||
uint64_t length;
|
uint64_t length;
|
||||||
|
uint64_t frame_size;
|
||||||
|
|
||||||
ast_debug(3, "Writing websocket %s frame, length %" PRIu64 "\n",
|
ast_debug(3, "Writing websocket %s frame, length %" PRIu64 "\n",
|
||||||
websocket_opcode2str(opcode), actual_length);
|
websocket_opcode2str(opcode), payload_size);
|
||||||
|
|
||||||
if (actual_length < 126) {
|
if (payload_size < 126) {
|
||||||
length = actual_length;
|
length = payload_size;
|
||||||
} else if (actual_length < (1 << 16)) {
|
} else if (payload_size < (1 << 16)) {
|
||||||
length = 126;
|
length = 126;
|
||||||
/* We need an additional 2 bytes to store the extended length */
|
/* We need an additional 2 bytes to store the extended length */
|
||||||
header_size += 2;
|
header_size += 2;
|
||||||
@@ -351,37 +352,37 @@ int AST_OPTIONAL_API_NAME(ast_websocket_write)(struct ast_websocket *session, en
|
|||||||
header_size += 8;
|
header_size += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame = ast_alloca(header_size);
|
frame_size = header_size + payload_size;
|
||||||
memset(frame, 0, header_size);
|
|
||||||
|
frame = ast_alloca(frame_size + 1);
|
||||||
|
memset(frame, 0, frame_size + 1);
|
||||||
|
|
||||||
frame[0] = opcode | 0x80;
|
frame[0] = opcode | 0x80;
|
||||||
frame[1] = length;
|
frame[1] = length;
|
||||||
|
|
||||||
/* Use the additional available bytes to store the length */
|
/* Use the additional available bytes to store the length */
|
||||||
if (length == 126) {
|
if (length == 126) {
|
||||||
put_unaligned_uint16(&frame[2], htons(actual_length));
|
put_unaligned_uint16(&frame[2], htons(payload_size));
|
||||||
} else if (length == 127) {
|
} else if (length == 127) {
|
||||||
put_unaligned_uint64(&frame[2], htonll(actual_length));
|
put_unaligned_uint64(&frame[2], htonll(payload_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memcpy(&frame[header_size], payload, payload_size);
|
||||||
|
|
||||||
ao2_lock(session);
|
ao2_lock(session);
|
||||||
if (session->closing) {
|
if (session->closing) {
|
||||||
ao2_unlock(session);
|
ao2_unlock(session);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (ast_careful_fwrite(session->f, session->fd, frame, header_size, session->timeout)) {
|
|
||||||
|
if (ast_careful_fwrite(session->f, session->fd, frame, frame_size, session->timeout)) {
|
||||||
ao2_unlock(session);
|
ao2_unlock(session);
|
||||||
/* 1011 - server terminating connection due to not being able to fulfill the request */
|
/* 1011 - server terminating connection due to not being able to fulfill the request */
|
||||||
|
ast_debug(1, "Closing WS with 1011 because we can't fulfill a write request\n");
|
||||||
ast_websocket_close(session, 1011);
|
ast_websocket_close(session, 1011);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ast_careful_fwrite(session->f, session->fd, payload, actual_length, session->timeout)) {
|
|
||||||
ao2_unlock(session);
|
|
||||||
/* 1011 - server terminating connection due to not being able to fulfill the request */
|
|
||||||
ast_websocket_close(session, 1011);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
fflush(session->f);
|
fflush(session->f);
|
||||||
ao2_unlock(session);
|
ao2_unlock(session);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user