1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

add extra state for waiting on close ack with timeout

Signed-off-by: Andy Green <andy@warmcat.com>
This commit is contained in:
Andy Green 2011-03-07 07:08:12 +00:00
parent 69758fa809
commit da527dfdee
4 changed files with 76 additions and 20 deletions

View file

@ -686,6 +686,7 @@ libwebsocket_read(struct libwebsocket_context *context, struct libwebsocket *wsi
break;
case WSI_STATE_AWAITING_CLOSE_ACK:
case WSI_STATE_ESTABLISHED:
switch (wsi->mode) {
case LWS_CONNMODE_WS_CLIENT:

View file

@ -158,7 +158,49 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context,
if (old_state == WSI_STATE_DEAD_SOCKET)
return;
/* remove this fd from wsi mapping hashtable */
wsi->close_reason = reason;
/*
* signal we are closing, libsocket_write will
* add any necessary version-specific stuff. If the write fails,
* no worries we are closing anyway. If we didn't initiate this
* close, then our state has been changed to
* WSI_STATE_RETURNED_CLOSE_ALREADY and we will skip this.
*
* Likewise if it's a second call to close this connection after we
* sent the close indication to the peer already, we are in state
* WSI_STATE_AWAITING_CLOSE_ACK and will skip doing this a second time.
*/
if (old_state == WSI_STATE_ESTABLISHED &&
reason != LWS_CLOSE_STATUS_NOSTATUS) {
n = libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING],
0, LWS_WRITE_CLOSE);
if (!n) {
/*
* we have sent a nice protocol level indication we
* now wish to close, we should not send anything more
*/
wsi->state = WSI_STATE_AWAITING_CLOSE_ACK;
/* and we should wait for a reply for a bit */
libwebsocket_set_timeout(wsi,
PENDING_TIMEOUT_CLOSE_ACK, 5);
fprintf(stderr, "sent close indication, awaiting ack\n");
return;
}
/* else, the send failed and we should just hang up */
}
/*
* we won't be servicing or receiving anything further from this guy
* remove this fd from wsi mapping hashtable
*/
delete_from_fd(context, wsi->sock);
@ -181,20 +223,6 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context,
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_DEL_POLL_FD, (void *)(long)wsi->sock, NULL, 0);
wsi->close_reason = reason;
/*
* signal we are closing, libsocket_write will
* add any necessary version-specific stuff. If the write fails,
* no worries we are closing anyway. If we didn't initiate this
* close, then our state has been changed to
* WSI_STATE_RETURNED_CLOSE_ALREADY and we will skip this
*/
if (old_state == WSI_STATE_ESTABLISHED)
libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], 0,
LWS_WRITE_CLOSE);
wsi->state = WSI_STATE_DEAD_SOCKET;
/* tell the user it's all over for this guy */
@ -586,9 +614,11 @@ libwebsocket_service_fd(struct libwebsocket_context *context,
* connection
*/
if (tv.tv_sec > wsi->pending_timeout_limit)
if (tv.tv_sec > wsi->pending_timeout_limit) {
fprintf(stderr, "TIMEDOUT WAITING\n");
libwebsocket_close_and_free_session(context,
wsi, LWS_CLOSE_STATUS_NOSTATUS);
}
}
}
@ -1607,10 +1637,12 @@ bail2:
/* the guy requested a callback when it was OK to write */
if (pollfd->revents & POLLOUT)
if (lws_handle_POLLOUT_event(context, wsi, pollfd) < 0) {
libwebsocket_close_and_free_session(context, wsi,
LWS_CLOSE_STATUS_NORMAL);
if ((pollfd->revents & POLLOUT) &&
wsi->state == WSI_STATE_ESTABLISHED)
if (lws_handle_POLLOUT_event(context, wsi,
pollfd) < 0) {
libwebsocket_close_and_free_session(
context, wsi, LWS_CLOSE_STATUS_NORMAL);
return 1;
}

View file

@ -617,6 +617,16 @@ spill:
switch (wsi->opcode) {
case LWS_WS_OPCODE_04__CLOSE:
/* is this an acknowledgement of our close? */
if (wsi->state == WSI_STATE_AWAITING_CLOSE_ACK) {
/*
* fine he has told us he is closing too, let's
* finish our close
*/
fprintf(stderr, "seen client close ack\n");
return -1;
}
fprintf(stderr, "server sees client close packet\n");
/* parrot the close packet payload back */
n = libwebsocket_write(wsi, (unsigned char *)
&wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
@ -940,10 +950,21 @@ spill:
switch (wsi->opcode) {
case LWS_WS_OPCODE_04__CLOSE:
/* is this an acknowledgement of our close? */
if (wsi->state == WSI_STATE_AWAITING_CLOSE_ACK) {
/*
* fine he has told us he is closing too, let's
* finish our close
*/
fprintf(stderr, "seen server's close ack\n");
return -1;
}
fprintf(stderr, "client sees server close packet len = %d\n", wsi->rx_user_buffer_head);
/* parrot the close packet payload back */
n = libwebsocket_write(wsi, (unsigned char *)
&wsi->rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
wsi->rx_user_buffer_head, LWS_WRITE_CLOSE);
fprintf(stderr, "client writing close ack returned %d\n", n);
wsi->state = WSI_STATE_RETURNED_CLOSE_ALREADY;
/* close the connection */
return -1;

View file

@ -129,6 +129,7 @@ enum lws_connection_states {
WSI_STATE_ESTABLISHED,
WSI_STATE_CLIENT_UNCONNECTED,
WSI_STATE_RETURNED_CLOSE_ALREADY,
WSI_STATE_AWAITING_CLOSE_ACK
};
enum lws_rx_parse_state {
@ -214,6 +215,7 @@ enum pending_timeout {
PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
PENDING_TIMEOUT_AWAITING_PING,
PENDING_TIMEOUT_CLOSE_ACK,
};