2 * nghttp2 - HTTP/2 C Library
4 * Copyright (c) 2012 Tatsuhiro Tsujikawa
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 #include "nghttp2_stream.h"
30 #include "nghttp2_session.h"
31 #include "nghttp2_helper.h"
32 #include "nghttp2_debug.h"
33 #include "nghttp2_frame.h"
35 /* Maximum distance between any two stream's cycle in the same
36 prirority queue. Imagine stream A's cycle is A, and stream B's
37 cycle is B, and A < B. The cycle is unsigned 32 bit integer, it
38 may get overflow. Because of how we calculate the next cycle
39 value, if B - A is less than or equals to
40 NGHTTP2_MAX_CYCLE_DISTANCE, A and B are in the same scale, in other
41 words, B is really greater than or equal to A. Otherwise, A is a
42 result of overflow, and it is actually A > B if we consider that
44 #define NGHTTP2_MAX_CYCLE_DISTANCE \
45 ((uint64_t)NGHTTP2_MAX_FRAME_SIZE_MAX * 256 + 255)
47 static int stream_less(const void *lhsx, const void *rhsx) {
48 const nghttp2_stream *lhs, *rhs;
50 lhs = nghttp2_struct_of(lhsx, nghttp2_stream, pq_entry);
51 rhs = nghttp2_struct_of(rhsx, nghttp2_stream, pq_entry);
53 if (lhs->cycle == rhs->cycle) {
54 return lhs->seq < rhs->seq;
57 return rhs->cycle - lhs->cycle <= NGHTTP2_MAX_CYCLE_DISTANCE;
60 void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
61 uint8_t flags, nghttp2_stream_state initial_state,
62 int32_t weight, int32_t remote_initial_window_size,
63 int32_t local_initial_window_size,
64 void *stream_user_data, nghttp2_mem *mem) {
65 nghttp2_pq_init(&stream->obq, stream_less, mem);
67 stream->stream_id = stream_id;
68 stream->flags = flags;
69 stream->state = initial_state;
70 stream->shut_flags = NGHTTP2_SHUT_NONE;
71 stream->stream_user_data = stream_user_data;
73 stream->remote_window_size = remote_initial_window_size;
74 stream->local_window_size = local_initial_window_size;
75 stream->recv_window_size = 0;
76 stream->consumed_size = 0;
77 stream->recv_reduction = 0;
78 stream->window_update_queued = 0;
80 stream->dep_prev = NULL;
81 stream->dep_next = NULL;
82 stream->sib_prev = NULL;
83 stream->sib_next = NULL;
85 stream->closed_prev = NULL;
86 stream->closed_next = NULL;
88 stream->weight = weight;
89 stream->sum_dep_weight = 0;
91 stream->http_flags = NGHTTP2_HTTP_FLAG_NONE;
92 stream->content_length = -1;
93 stream->recv_content_length = 0;
94 stream->status_code = -1;
97 stream->descendant_last_cycle = 0;
99 stream->pending_penalty = 0;
100 stream->descendant_next_seq = 0;
102 stream->last_writelen = 0;
105 void nghttp2_stream_free(nghttp2_stream *stream) {
106 nghttp2_pq_free(&stream->obq);
107 /* We don't free stream->item. If it is assigned to aob, then
108 active_outbound_item_reset() will delete it. Otherwise,
109 nghttp2_stream_close() or session_del() will delete it. */
112 void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag) {
113 stream->shut_flags = (uint8_t)(stream->shut_flags | flag);
117 * Returns nonzero if |stream| is active. This function does not take
118 * into account its descendants.
120 static int stream_active(nghttp2_stream *stream) {
121 return stream->item &&
122 (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0;
126 * Returns nonzero if |stream| or one of its descendants is active
128 static int stream_subtree_active(nghttp2_stream *stream) {
129 return stream_active(stream) || !nghttp2_pq_empty(&stream->obq);
133 * Returns next cycle for |stream|.
135 static void stream_next_cycle(nghttp2_stream *stream, uint64_t last_cycle) {
138 penalty = (uint64_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT +
139 stream->pending_penalty;
141 stream->cycle = last_cycle + penalty / (uint32_t)stream->weight;
142 stream->pending_penalty = (uint32_t)(penalty % (uint32_t)stream->weight);
145 static int stream_obq_push(nghttp2_stream *dep_stream, nghttp2_stream *stream) {
148 for (; dep_stream && !stream->queued;
149 stream = dep_stream, dep_stream = dep_stream->dep_prev) {
150 stream_next_cycle(stream, dep_stream->descendant_last_cycle);
151 stream->seq = dep_stream->descendant_next_seq++;
153 DEBUGF("stream: stream=%d obq push cycle=%lu\n", stream->stream_id,
156 DEBUGF("stream: push stream %d to stream %d\n", stream->stream_id,
157 dep_stream->stream_id);
159 rv = nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);
170 * Removes |stream| from parent's obq. If removal of |stream| makes
171 * parent's obq empty, and parent is not active, then parent is also
172 * removed. This process is repeated recursively.
174 static void stream_obq_remove(nghttp2_stream *stream) {
175 nghttp2_stream *dep_stream;
177 dep_stream = stream->dep_prev;
179 if (!stream->queued) {
183 for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) {
184 DEBUGF("stream: remove stream %d from stream %d\n", stream->stream_id,
185 dep_stream->stream_id);
187 nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
189 assert(stream->queued);
193 stream->pending_penalty = 0;
194 stream->descendant_last_cycle = 0;
195 stream->last_writelen = 0;
197 if (stream_subtree_active(dep_stream)) {
204 * Moves |stream| from |src|'s obq to |dest|'s obq. Removal from
205 * |src|'s obq is just done calling nghttp2_pq_remove(), so it does
206 * not recursively remove |src| and ancestors, like
207 * stream_obq_remove().
209 static int stream_obq_move(nghttp2_stream *dest, nghttp2_stream *src,
210 nghttp2_stream *stream) {
211 if (!stream->queued) {
215 DEBUGF("stream: remove stream %d from stream %d (move)\n", stream->stream_id,
218 nghttp2_pq_remove(&src->obq, &stream->pq_entry);
221 return stream_obq_push(dest, stream);
224 void nghttp2_stream_reschedule(nghttp2_stream *stream) {
225 nghttp2_stream *dep_stream;
227 assert(stream->queued);
229 dep_stream = stream->dep_prev;
231 for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) {
232 nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
234 stream_next_cycle(stream, dep_stream->descendant_last_cycle);
235 stream->seq = dep_stream->descendant_next_seq++;
237 nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);
239 DEBUGF("stream: stream=%d obq resched cycle=%lu\n", stream->stream_id,
242 dep_stream->last_writelen = stream->last_writelen;
246 void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight) {
247 nghttp2_stream *dep_stream;
250 uint64_t wlen_penalty;
252 if (stream->weight == weight) {
256 old_weight = stream->weight;
257 stream->weight = weight;
259 dep_stream = stream->dep_prev;
265 dep_stream->sum_dep_weight += weight - old_weight;
267 if (!stream->queued) {
271 nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
273 wlen_penalty = (uint64_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT;
275 /* Compute old stream->pending_penalty we used to calculate
277 stream->pending_penalty =
278 (uint32_t)((stream->pending_penalty + (uint32_t)old_weight -
279 (wlen_penalty % (uint32_t)old_weight)) %
280 (uint32_t)old_weight);
282 last_cycle = stream->cycle -
283 (wlen_penalty + stream->pending_penalty) / (uint32_t)old_weight;
285 /* Now we have old stream->pending_penalty and new stream->weight in
287 stream_next_cycle(stream, last_cycle);
289 if (dep_stream->descendant_last_cycle - stream->cycle <=
290 NGHTTP2_MAX_CYCLE_DISTANCE) {
291 stream->cycle = dep_stream->descendant_last_cycle;
294 /* Continue to use same stream->seq */
296 nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);
298 DEBUGF("stream: stream=%d obq resched cycle=%lu\n", stream->stream_id,
302 static nghttp2_stream *stream_last_sib(nghttp2_stream *stream) {
303 for (; stream->sib_next; stream = stream->sib_next)
309 int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
311 weight = stream->weight * weight / stream->sum_dep_weight;
313 return nghttp2_max(1, weight);
316 #ifdef STREAM_DEP_DEBUG
318 static void ensure_inactive(nghttp2_stream *stream) {
321 if (stream->queued) {
322 fprintf(stderr, "stream(%p)=%d, stream->queued = 1; want 0\n", stream,
327 if (stream_active(stream)) {
328 fprintf(stderr, "stream(%p)=%d, stream_active(stream) = 1; want 0\n",
329 stream, stream->stream_id);
333 if (!nghttp2_pq_empty(&stream->obq)) {
334 fprintf(stderr, "stream(%p)=%d, nghttp2_pq_size() = %zu; want 0\n", stream,
335 stream->stream_id, nghttp2_pq_size(&stream->obq));
339 for (si = stream->dep_next; si; si = si->sib_next) {
344 static void check_queued(nghttp2_stream *stream) {
348 if (stream->queued) {
349 if (!stream_subtree_active(stream)) {
351 "stream(%p)=%d, stream->queued == 1, but "
352 "stream_active() == %d and nghttp2_pq_size(&stream->obq) = %zu\n",
353 stream, stream->stream_id, stream_active(stream),
354 nghttp2_pq_size(&stream->obq));
357 if (!stream_active(stream)) {
359 for (si = stream->dep_next; si; si = si->sib_next) {
366 "stream(%p)=%d, stream->queued == 1, and "
367 "!stream_active(), but no descendants is queued\n",
368 stream, stream->stream_id);
373 for (si = stream->dep_next; si; si = si->sib_next) {
377 if (stream_active(stream) || !nghttp2_pq_empty(&stream->obq)) {
379 "stream(%p) = %d, stream->queued == 0, but "
380 "stream_active(stream) == %d and "
381 "nghttp2_pq_size(&stream->obq) = %zu\n",
382 stream, stream->stream_id, stream_active(stream),
383 nghttp2_pq_size(&stream->obq));
386 for (si = stream->dep_next; si; si = si->sib_next) {
392 static void check_sum_dep(nghttp2_stream *stream) {
395 for (si = stream->dep_next; si; si = si->sib_next) {
398 if (n != stream->sum_dep_weight) {
399 fprintf(stderr, "stream(%p)=%d, sum_dep_weight = %d; want %d\n", stream,
400 stream->stream_id, n, stream->sum_dep_weight);
403 for (si = stream->dep_next; si; si = si->sib_next) {
408 static void check_dep_prev(nghttp2_stream *stream) {
410 for (si = stream->dep_next; si; si = si->sib_next) {
411 if (si->dep_prev != stream) {
412 fprintf(stderr, "si->dep_prev = %p; want %p\n", si->dep_prev, stream);
419 #endif /* STREAM_DEP_DEBUG */
421 #ifdef STREAM_DEP_DEBUG
422 static void validate_tree(nghttp2_stream *stream) {
429 for (; stream->dep_prev; stream = stream->dep_prev)
432 assert(stream->stream_id == 0);
433 assert(!stream->queued);
435 fprintf(stderr, "checking...\n");
436 if (nghttp2_pq_empty(&stream->obq)) {
437 fprintf(stderr, "root obq empty\n");
438 for (si = stream->dep_next; si; si = si->sib_next) {
442 for (si = stream->dep_next; si; si = si->sib_next) {
447 check_sum_dep(stream);
448 check_dep_prev(stream);
450 #else /* !STREAM_DEP_DEBUG */
451 static void validate_tree(nghttp2_stream *stream) { (void)stream; }
452 #endif /* !STREAM_DEP_DEBUG*/
454 static int stream_update_dep_on_attach_item(nghttp2_stream *stream) {
457 rv = stream_obq_push(stream->dep_prev, stream);
462 validate_tree(stream);
466 static int stream_update_dep_on_detach_item(nghttp2_stream *stream) {
467 if (nghttp2_pq_empty(&stream->obq)) {
468 stream_obq_remove(stream);
471 validate_tree(stream);
476 int nghttp2_stream_attach_item(nghttp2_stream *stream,
477 nghttp2_outbound_item *item) {
480 assert((stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0);
481 assert(stream->item == NULL);
483 DEBUGF("stream: stream=%d attach item=%p\n", stream->stream_id, item);
487 rv = stream_update_dep_on_attach_item(stream);
489 /* This may relave stream->queued == 1, but stream->item == NULL.
490 But only consequence of this error is fatal one, and session
491 destruction. In that execution path, these inconsistency does
500 int nghttp2_stream_detach_item(nghttp2_stream *stream) {
501 DEBUGF("stream: stream=%d detach item=%p\n", stream->stream_id, stream->item);
504 stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL);
506 return stream_update_dep_on_detach_item(stream);
509 int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) {
510 assert(stream->item);
512 DEBUGF("stream: stream=%d defer item=%p cause=%02x\n", stream->stream_id,
513 stream->item, flags);
515 stream->flags |= flags;
517 return stream_update_dep_on_detach_item(stream);
520 int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags) {
521 assert(stream->item);
523 DEBUGF("stream: stream=%d resume item=%p flags=%02x\n", stream->stream_id,
524 stream->item, flags);
526 stream->flags = (uint8_t)(stream->flags & ~flags);
528 if (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) {
532 return stream_update_dep_on_attach_item(stream);
535 int nghttp2_stream_check_deferred_item(nghttp2_stream *stream) {
536 return stream->item && (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL);
539 int nghttp2_stream_check_deferred_by_flow_control(nghttp2_stream *stream) {
540 return stream->item &&
541 (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
544 static int update_initial_window_size(int32_t *window_size_ptr,
545 int32_t new_initial_window_size,
546 int32_t old_initial_window_size) {
547 int64_t new_window_size = (int64_t)(*window_size_ptr) +
548 new_initial_window_size - old_initial_window_size;
549 if (INT32_MIN > new_window_size ||
550 new_window_size > NGHTTP2_MAX_WINDOW_SIZE) {
553 *window_size_ptr = (int32_t)new_window_size;
557 int nghttp2_stream_update_remote_initial_window_size(
558 nghttp2_stream *stream, int32_t new_initial_window_size,
559 int32_t old_initial_window_size) {
560 return update_initial_window_size(&stream->remote_window_size,
561 new_initial_window_size,
562 old_initial_window_size);
565 int nghttp2_stream_update_local_initial_window_size(
566 nghttp2_stream *stream, int32_t new_initial_window_size,
567 int32_t old_initial_window_size) {
568 return update_initial_window_size(&stream->local_window_size,
569 new_initial_window_size,
570 old_initial_window_size);
573 void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream) {
574 stream->state = NGHTTP2_STREAM_OPENED;
575 stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_PUSH);
578 int nghttp2_stream_dep_find_ancestor(nghttp2_stream *stream,
579 nghttp2_stream *target) {
580 for (; stream; stream = stream->dep_prev) {
581 if (stream == target) {
588 int nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
589 nghttp2_stream *stream) {
593 DEBUGF("stream: dep_insert dep_stream(%p)=%d, stream(%p)=%d\n", dep_stream,
594 dep_stream->stream_id, stream, stream->stream_id);
596 stream->sum_dep_weight = dep_stream->sum_dep_weight;
597 dep_stream->sum_dep_weight = stream->weight;
599 if (dep_stream->dep_next) {
600 for (si = dep_stream->dep_next; si; si = si->sib_next) {
601 si->dep_prev = stream;
603 rv = stream_obq_move(stream, dep_stream, si);
610 if (stream_subtree_active(stream)) {
611 rv = stream_obq_push(dep_stream, stream);
617 stream->dep_next = dep_stream->dep_next;
620 dep_stream->dep_next = stream;
621 stream->dep_prev = dep_stream;
623 validate_tree(stream);
628 static void set_dep_prev(nghttp2_stream *stream, nghttp2_stream *dep) {
629 for (; stream; stream = stream->sib_next) {
630 stream->dep_prev = dep;
634 static void link_dep(nghttp2_stream *dep_stream, nghttp2_stream *stream) {
635 dep_stream->dep_next = stream;
637 stream->dep_prev = dep_stream;
641 static void link_sib(nghttp2_stream *a, nghttp2_stream *b) {
648 static void insert_link_dep(nghttp2_stream *dep_stream,
649 nghttp2_stream *stream) {
650 nghttp2_stream *sib_next;
652 assert(stream->sib_prev == NULL);
654 sib_next = dep_stream->dep_next;
656 link_sib(stream, sib_next);
658 link_dep(dep_stream, stream);
661 static void unlink_sib(nghttp2_stream *stream) {
662 nghttp2_stream *prev, *next, *dep_next;
664 prev = stream->sib_prev;
665 dep_next = stream->dep_next;
671 * prev--stream(--sib_next--...)
676 link_sib(prev, dep_next);
678 set_dep_prev(dep_next, stream->dep_prev);
680 if (stream->sib_next) {
681 link_sib(stream_last_sib(dep_next), stream->sib_next);
685 * prev--stream(--sib_next--...)
687 next = stream->sib_next;
689 prev->sib_next = next;
692 next->sib_prev = prev;
697 static void unlink_dep(nghttp2_stream *stream) {
698 nghttp2_stream *prev, *next, *dep_next;
700 prev = stream->dep_prev;
701 dep_next = stream->dep_next;
709 * stream(--sib_next--...)
713 link_dep(prev, dep_next);
715 set_dep_prev(dep_next, stream->dep_prev);
717 if (stream->sib_next) {
718 link_sib(stream_last_sib(dep_next), stream->sib_next);
721 } else if (stream->sib_next) {
727 next = stream->sib_next;
729 next->sib_prev = NULL;
731 link_dep(prev, next);
733 prev->dep_next = NULL;
737 void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
738 nghttp2_stream *stream) {
739 DEBUGF("stream: dep_add dep_stream(%p)=%d, stream(%p)=%d\n", dep_stream,
740 dep_stream->stream_id, stream, stream->stream_id);
742 dep_stream->sum_dep_weight += stream->weight;
744 if (dep_stream->dep_next == NULL) {
745 link_dep(dep_stream, stream);
747 insert_link_dep(dep_stream, stream);
750 validate_tree(stream);
753 int nghttp2_stream_dep_remove(nghttp2_stream *stream) {
754 nghttp2_stream *dep_prev, *si;
755 int32_t sum_dep_weight_delta;
758 DEBUGF("stream: dep_remove stream(%p)=%d\n", stream, stream->stream_id);
760 /* Distribute weight of |stream| to direct descendants */
761 sum_dep_weight_delta = -stream->weight;
763 for (si = stream->dep_next; si; si = si->sib_next) {
764 si->weight = nghttp2_stream_dep_distributed_weight(stream, si->weight);
766 sum_dep_weight_delta += si->weight;
769 rv = stream_obq_move(stream->dep_prev, stream, si);
776 assert(stream->dep_prev);
778 dep_prev = stream->dep_prev;
780 dep_prev->sum_dep_weight += sum_dep_weight_delta;
782 if (stream->queued) {
783 stream_obq_remove(stream);
786 if (stream->sib_prev) {
792 stream->sum_dep_weight = 0;
794 stream->dep_prev = NULL;
795 stream->dep_next = NULL;
796 stream->sib_prev = NULL;
797 stream->sib_next = NULL;
799 validate_tree(dep_prev);
804 int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
805 nghttp2_stream *stream) {
806 nghttp2_stream *last_sib;
807 nghttp2_stream *dep_next;
811 DEBUGF("stream: dep_insert_subtree dep_stream(%p)=%d stream(%p)=%d\n",
812 dep_stream, dep_stream->stream_id, stream, stream->stream_id);
814 stream->sum_dep_weight += dep_stream->sum_dep_weight;
815 dep_stream->sum_dep_weight = stream->weight;
817 if (dep_stream->dep_next) {
818 dep_next = dep_stream->dep_next;
820 link_dep(dep_stream, stream);
822 if (stream->dep_next) {
823 last_sib = stream_last_sib(stream->dep_next);
825 link_sib(last_sib, dep_next);
827 link_dep(stream, dep_next);
830 for (si = dep_next; si; si = si->sib_next) {
831 si->dep_prev = stream;
833 rv = stream_obq_move(stream, dep_stream, si);
840 link_dep(dep_stream, stream);
843 if (stream_subtree_active(stream)) {
844 rv = stream_obq_push(dep_stream, stream);
850 validate_tree(dep_stream);
855 int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
856 nghttp2_stream *stream) {
859 DEBUGF("stream: dep_add_subtree dep_stream(%p)=%d stream(%p)=%d\n",
860 dep_stream, dep_stream->stream_id, stream, stream->stream_id);
862 dep_stream->sum_dep_weight += stream->weight;
864 if (dep_stream->dep_next) {
865 insert_link_dep(dep_stream, stream);
867 link_dep(dep_stream, stream);
870 if (stream_subtree_active(stream)) {
871 rv = stream_obq_push(dep_stream, stream);
877 validate_tree(dep_stream);
882 void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) {
883 nghttp2_stream *next, *dep_prev;
885 DEBUGF("stream: dep_remove_subtree stream(%p)=%d\n", stream,
888 assert(stream->dep_prev);
890 dep_prev = stream->dep_prev;
892 if (stream->sib_prev) {
893 link_sib(stream->sib_prev, stream->sib_next);
895 next = stream->sib_next;
897 link_dep(dep_prev, next);
900 next->sib_prev = NULL;
904 dep_prev->sum_dep_weight -= stream->weight;
906 if (stream->queued) {
907 stream_obq_remove(stream);
910 validate_tree(dep_prev);
912 stream->sib_prev = NULL;
913 stream->sib_next = NULL;
914 stream->dep_prev = NULL;
917 int nghttp2_stream_in_dep_tree(nghttp2_stream *stream) {
918 return stream->dep_prev || stream->dep_next || stream->sib_prev ||
922 nghttp2_outbound_item *
923 nghttp2_stream_next_outbound_item(nghttp2_stream *stream) {
924 nghttp2_pq_entry *ent;
928 if (stream_active(stream)) {
929 /* Update ascendant's descendant_last_cycle here, so that we can
930 assure that new stream is scheduled based on it. */
931 for (si = stream; si->dep_prev; si = si->dep_prev) {
932 si->dep_prev->descendant_last_cycle = si->cycle;
936 ent = nghttp2_pq_top(&stream->obq);
940 stream = nghttp2_struct_of(ent, nghttp2_stream, pq_entry);
944 nghttp2_stream_proto_state nghttp2_stream_get_state(nghttp2_stream *stream) {
945 if (stream->flags & NGHTTP2_STREAM_FLAG_CLOSED) {
946 return NGHTTP2_STREAM_STATE_CLOSED;
949 if (stream->flags & NGHTTP2_STREAM_FLAG_PUSH) {
950 if (stream->shut_flags & NGHTTP2_SHUT_RD) {
951 return NGHTTP2_STREAM_STATE_RESERVED_LOCAL;
954 if (stream->shut_flags & NGHTTP2_SHUT_WR) {
955 return NGHTTP2_STREAM_STATE_RESERVED_REMOTE;
959 if (stream->shut_flags & NGHTTP2_SHUT_RD) {
960 return NGHTTP2_STREAM_STATE_HALF_CLOSED_REMOTE;
963 if (stream->shut_flags & NGHTTP2_SHUT_WR) {
964 return NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL;
967 if (stream->state == NGHTTP2_STREAM_IDLE) {
968 return NGHTTP2_STREAM_STATE_IDLE;
971 return NGHTTP2_STREAM_STATE_OPEN;
974 nghttp2_stream *nghttp2_stream_get_parent(nghttp2_stream *stream) {
975 return stream->dep_prev;
978 nghttp2_stream *nghttp2_stream_get_next_sibling(nghttp2_stream *stream) {
979 return stream->sib_next;
982 nghttp2_stream *nghttp2_stream_get_previous_sibling(nghttp2_stream *stream) {
983 return stream->sib_prev;
986 nghttp2_stream *nghttp2_stream_get_first_child(nghttp2_stream *stream) {
987 return stream->dep_next;
990 int32_t nghttp2_stream_get_weight(nghttp2_stream *stream) {
991 return stream->weight;
994 int32_t nghttp2_stream_get_sum_dependency_weight(nghttp2_stream *stream) {
995 return stream->sum_dep_weight;
998 int32_t nghttp2_stream_get_stream_id(nghttp2_stream *stream) {
999 return stream->stream_id;