+ if (wsi->u.hdr.ah) {
+ wsi->u.hdr.ah->rxpos = -1;
+ wsi->u.hdr.ah->rxlen = -1;
+ wsi->hdr_parsing_completed = 1;
+ }
+}
+
+int
+lws_header_table_is_in_detachable_state(struct lws *wsi)
+{
+ struct allocated_headers *ah = wsi->u.hdr.ah;
+
+ return ah && ah->rxpos == ah->rxlen && wsi->hdr_parsing_completed;
+}
+
+int lws_header_table_detach(struct lws *wsi, int autoservice)
+{
+ struct lws_context *context = wsi->context;
+ struct allocated_headers *ah = wsi->u.hdr.ah;
+ struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
+ struct lws_pollargs pa;
+ struct lws **pwsi;
+ time_t now;
+
+ if (!ah)
+ return 0;
+
+ lwsl_info("%s: wsi %p: ah %p (tsi=%d, count = %d)\n", __func__,
+ (void *)wsi, (void *)ah, wsi->tsi,
+ pt->ah_count_in_use);
+
+ if (wsi->u.hdr.preamble_rx)
+ lws_free_set_NULL(wsi->u.hdr.preamble_rx);
+
+ /* may not be detached while he still has unprocessed rx */
+ if (!lws_header_table_is_in_detachable_state(wsi)) {
+ lwsl_err("%s: %p: CANNOT DETACH rxpos:%d, rxlen:%d, wsi->hdr_parsing_completed = %d\n", __func__, wsi,
+ ah->rxpos, ah->rxlen, wsi->hdr_parsing_completed);
+ return 0;
+ }
+
+ lws_pt_lock(pt);
+
+ pwsi = &pt->ah_wait_list;
+ if (!ah) { /* remove from wait list if none attached */
+ while (*pwsi) {
+ if (*pwsi == wsi) {
+ lwsl_info("%s: wsi %p, remv wait\n",
+ __func__, wsi);
+ *pwsi = wsi->u.hdr.ah_wait_list;
+ wsi->u.hdr.ah_wait_list = NULL;
+ pt->ah_wait_list_length--;
+ goto bail;
+ }
+ pwsi = &(*pwsi)->u.hdr.ah_wait_list;
+ }
+ /* no ah, not on list... no more business here */
+ goto bail;
+ }
+ /* we did have an ah attached */
+ time(&now);
+ if (ah->assigned && now - ah->assigned > 3) {
+ /*
+ * we're detaching the ah, but it was held an
+ * unreasonably long time
+ */
+ lwsl_notice("%s: wsi %p: ah held %ds, "
+ "ah.rxpos %d, ah.rxlen %d, mode/state %d %d,"
+ "wsi->more_rx_waiting %d\n", __func__, wsi,
+ (int)(now - ah->assigned),
+ ah->rxpos, ah->rxlen, wsi->mode, wsi->state,
+ wsi->more_rx_waiting);
+ }
+
+ ah->assigned = 0;
+
+ /* if we think we're detaching one, there should be one in use */
+ assert(pt->ah_count_in_use > 0);
+ /* and this specific one should have been in use */
+ assert(ah->in_use);