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);
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 */
* 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);
+ }
}
}
/* 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;
}
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],
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;