Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Kitware
GitHub Repository: Kitware/CMake
Path: blob/master/Utilities/cmnghttp2/lib/nghttp2_stream.c
3153 views
1
/*
2
* nghttp2 - HTTP/2 C Library
3
*
4
* Copyright (c) 2012 Tatsuhiro Tsujikawa
5
*
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:
13
*
14
* The above copyright notice and this permission notice shall be
15
* included in all copies or substantial portions of the Software.
16
*
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.
24
*/
25
#include "nghttp2_stream.h"
26
27
#include <assert.h>
28
#include <stdio.h>
29
30
#include "nghttp2_session.h"
31
#include "nghttp2_helper.h"
32
#include "nghttp2_debug.h"
33
#include "nghttp2_frame.h"
34
35
/* Maximum distance between any two stream's cycle in the same
36
priority 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
43
fact. */
44
#define NGHTTP2_MAX_CYCLE_DISTANCE \
45
((uint64_t)NGHTTP2_MAX_FRAME_SIZE_MAX * 256 + 255)
46
47
static int stream_less(const void *lhsx, const void *rhsx) {
48
const nghttp2_stream *lhs, *rhs;
49
50
lhs = nghttp2_struct_of(lhsx, nghttp2_stream, pq_entry);
51
rhs = nghttp2_struct_of(rhsx, nghttp2_stream, pq_entry);
52
53
if (lhs->cycle == rhs->cycle) {
54
return lhs->seq < rhs->seq;
55
}
56
57
return rhs->cycle - lhs->cycle <= NGHTTP2_MAX_CYCLE_DISTANCE;
58
}
59
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);
66
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;
72
stream->item = NULL;
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;
79
80
stream->dep_prev = NULL;
81
stream->dep_next = NULL;
82
stream->sib_prev = NULL;
83
stream->sib_next = NULL;
84
85
stream->closed_prev = NULL;
86
stream->closed_next = NULL;
87
88
stream->weight = weight;
89
stream->sum_dep_weight = 0;
90
91
stream->http_flags = NGHTTP2_HTTP_FLAG_NONE;
92
stream->content_length = -1;
93
stream->recv_content_length = 0;
94
stream->status_code = -1;
95
96
stream->queued = 0;
97
stream->descendant_last_cycle = 0;
98
stream->cycle = 0;
99
stream->pending_penalty = 0;
100
stream->descendant_next_seq = 0;
101
stream->seq = 0;
102
stream->last_writelen = 0;
103
104
stream->extpri = stream->http_extpri = NGHTTP2_EXTPRI_DEFAULT_URGENCY;
105
}
106
107
void nghttp2_stream_free(nghttp2_stream *stream) {
108
nghttp2_pq_free(&stream->obq);
109
/* We don't free stream->item. If it is assigned to aob, then
110
active_outbound_item_reset() will delete it. Otherwise,
111
nghttp2_stream_close() or session_del() will delete it. */
112
}
113
114
void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag) {
115
stream->shut_flags = (uint8_t)(stream->shut_flags | flag);
116
}
117
118
/*
119
* Returns nonzero if |stream| is active. This function does not take
120
* into account its descendants.
121
*/
122
static int stream_active(nghttp2_stream *stream) {
123
return stream->item &&
124
(stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0;
125
}
126
127
/*
128
* Returns nonzero if |stream| or one of its descendants is active
129
*/
130
static int stream_subtree_active(nghttp2_stream *stream) {
131
return stream_active(stream) || !nghttp2_pq_empty(&stream->obq);
132
}
133
134
/*
135
* Returns next cycle for |stream|.
136
*/
137
static void stream_next_cycle(nghttp2_stream *stream, uint64_t last_cycle) {
138
uint64_t penalty;
139
140
penalty = (uint64_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT +
141
stream->pending_penalty;
142
143
stream->cycle = last_cycle + penalty / (uint32_t)stream->weight;
144
stream->pending_penalty = (uint32_t)(penalty % (uint32_t)stream->weight);
145
}
146
147
static int stream_obq_push(nghttp2_stream *dep_stream, nghttp2_stream *stream) {
148
int rv;
149
150
for (; dep_stream && !stream->queued;
151
stream = dep_stream, dep_stream = dep_stream->dep_prev) {
152
stream_next_cycle(stream, dep_stream->descendant_last_cycle);
153
stream->seq = dep_stream->descendant_next_seq++;
154
155
DEBUGF("stream: stream=%d obq push cycle=%lu\n", stream->stream_id,
156
stream->cycle);
157
158
DEBUGF("stream: push stream %d to stream %d\n", stream->stream_id,
159
dep_stream->stream_id);
160
161
rv = nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);
162
if (rv != 0) {
163
return rv;
164
}
165
stream->queued = 1;
166
}
167
168
return 0;
169
}
170
171
/*
172
* Removes |stream| from parent's obq. If removal of |stream| makes
173
* parent's obq empty, and parent is not active, then parent is also
174
* removed. This process is repeated recursively.
175
*/
176
static void stream_obq_remove(nghttp2_stream *stream) {
177
nghttp2_stream *dep_stream;
178
179
dep_stream = stream->dep_prev;
180
181
if (!stream->queued) {
182
return;
183
}
184
185
for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) {
186
DEBUGF("stream: remove stream %d from stream %d\n", stream->stream_id,
187
dep_stream->stream_id);
188
189
nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
190
191
assert(stream->queued);
192
193
stream->queued = 0;
194
stream->cycle = 0;
195
stream->pending_penalty = 0;
196
stream->descendant_last_cycle = 0;
197
stream->last_writelen = 0;
198
199
if (stream_subtree_active(dep_stream)) {
200
return;
201
}
202
}
203
}
204
205
/*
206
* Moves |stream| from |src|'s obq to |dest|'s obq. Removal from
207
* |src|'s obq is just done calling nghttp2_pq_remove(), so it does
208
* not recursively remove |src| and ancestors, like
209
* stream_obq_remove().
210
*/
211
static int stream_obq_move(nghttp2_stream *dest, nghttp2_stream *src,
212
nghttp2_stream *stream) {
213
if (!stream->queued) {
214
return 0;
215
}
216
217
DEBUGF("stream: remove stream %d from stream %d (move)\n", stream->stream_id,
218
src->stream_id);
219
220
nghttp2_pq_remove(&src->obq, &stream->pq_entry);
221
stream->queued = 0;
222
223
return stream_obq_push(dest, stream);
224
}
225
226
void nghttp2_stream_reschedule(nghttp2_stream *stream) {
227
nghttp2_stream *dep_stream;
228
229
assert(stream->queued);
230
231
dep_stream = stream->dep_prev;
232
233
for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) {
234
nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
235
236
stream_next_cycle(stream, dep_stream->descendant_last_cycle);
237
stream->seq = dep_stream->descendant_next_seq++;
238
239
nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);
240
241
DEBUGF("stream: stream=%d obq resched cycle=%lu\n", stream->stream_id,
242
stream->cycle);
243
244
dep_stream->last_writelen = stream->last_writelen;
245
}
246
}
247
248
void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight) {
249
nghttp2_stream *dep_stream;
250
uint64_t last_cycle;
251
int32_t old_weight;
252
uint64_t wlen_penalty;
253
254
if (stream->weight == weight) {
255
return;
256
}
257
258
old_weight = stream->weight;
259
stream->weight = weight;
260
261
dep_stream = stream->dep_prev;
262
263
if (!dep_stream) {
264
return;
265
}
266
267
dep_stream->sum_dep_weight += weight - old_weight;
268
269
if (!stream->queued) {
270
return;
271
}
272
273
nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
274
275
wlen_penalty = (uint64_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT;
276
277
/* Compute old stream->pending_penalty we used to calculate
278
stream->cycle */
279
stream->pending_penalty =
280
(uint32_t)((stream->pending_penalty + (uint32_t)old_weight -
281
(wlen_penalty % (uint32_t)old_weight)) %
282
(uint32_t)old_weight);
283
284
last_cycle = stream->cycle -
285
(wlen_penalty + stream->pending_penalty) / (uint32_t)old_weight;
286
287
/* Now we have old stream->pending_penalty and new stream->weight in
288
place */
289
stream_next_cycle(stream, last_cycle);
290
291
if (dep_stream->descendant_last_cycle - stream->cycle <=
292
NGHTTP2_MAX_CYCLE_DISTANCE) {
293
stream->cycle = dep_stream->descendant_last_cycle;
294
}
295
296
/* Continue to use same stream->seq */
297
298
nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);
299
300
DEBUGF("stream: stream=%d obq resched cycle=%lu\n", stream->stream_id,
301
stream->cycle);
302
}
303
304
static nghttp2_stream *stream_last_sib(nghttp2_stream *stream) {
305
for (; stream->sib_next; stream = stream->sib_next)
306
;
307
308
return stream;
309
}
310
311
int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
312
int32_t weight) {
313
weight = stream->weight * weight / stream->sum_dep_weight;
314
315
return nghttp2_max(1, weight);
316
}
317
318
#ifdef STREAM_DEP_DEBUG
319
320
static void ensure_inactive(nghttp2_stream *stream) {
321
nghttp2_stream *si;
322
323
if (stream->queued) {
324
fprintf(stderr, "stream(%p)=%d, stream->queued = 1; want 0\n", stream,
325
stream->stream_id);
326
assert(0);
327
}
328
329
if (stream_active(stream)) {
330
fprintf(stderr, "stream(%p)=%d, stream_active(stream) = 1; want 0\n",
331
stream, stream->stream_id);
332
assert(0);
333
}
334
335
if (!nghttp2_pq_empty(&stream->obq)) {
336
fprintf(stderr, "stream(%p)=%d, nghttp2_pq_size() = %zu; want 0\n", stream,
337
stream->stream_id, nghttp2_pq_size(&stream->obq));
338
assert(0);
339
}
340
341
for (si = stream->dep_next; si; si = si->sib_next) {
342
ensure_inactive(si);
343
}
344
}
345
346
static void check_queued(nghttp2_stream *stream) {
347
nghttp2_stream *si;
348
int queued;
349
350
if (stream->queued) {
351
if (!stream_subtree_active(stream)) {
352
fprintf(stderr,
353
"stream(%p)=%d, stream->queued == 1, but "
354
"stream_active() == %d and nghttp2_pq_size(&stream->obq) = %zu\n",
355
stream, stream->stream_id, stream_active(stream),
356
nghttp2_pq_size(&stream->obq));
357
assert(0);
358
}
359
if (!stream_active(stream)) {
360
queued = 0;
361
for (si = stream->dep_next; si; si = si->sib_next) {
362
if (si->queued) {
363
++queued;
364
}
365
}
366
if (queued == 0) {
367
fprintf(stderr,
368
"stream(%p)=%d, stream->queued == 1, and "
369
"!stream_active(), but no descendants is queued\n",
370
stream, stream->stream_id);
371
assert(0);
372
}
373
}
374
375
for (si = stream->dep_next; si; si = si->sib_next) {
376
check_queued(si);
377
}
378
} else {
379
if (stream_active(stream) || !nghttp2_pq_empty(&stream->obq)) {
380
fprintf(stderr,
381
"stream(%p) = %d, stream->queued == 0, but "
382
"stream_active(stream) == %d and "
383
"nghttp2_pq_size(&stream->obq) = %zu\n",
384
stream, stream->stream_id, stream_active(stream),
385
nghttp2_pq_size(&stream->obq));
386
assert(0);
387
}
388
for (si = stream->dep_next; si; si = si->sib_next) {
389
ensure_inactive(si);
390
}
391
}
392
}
393
394
static void check_sum_dep(nghttp2_stream *stream) {
395
nghttp2_stream *si;
396
int32_t n = 0;
397
for (si = stream->dep_next; si; si = si->sib_next) {
398
n += si->weight;
399
}
400
if (n != stream->sum_dep_weight) {
401
fprintf(stderr, "stream(%p)=%d, sum_dep_weight = %d; want %d\n", stream,
402
stream->stream_id, n, stream->sum_dep_weight);
403
assert(0);
404
}
405
for (si = stream->dep_next; si; si = si->sib_next) {
406
check_sum_dep(si);
407
}
408
}
409
410
static void check_dep_prev(nghttp2_stream *stream) {
411
nghttp2_stream *si;
412
for (si = stream->dep_next; si; si = si->sib_next) {
413
if (si->dep_prev != stream) {
414
fprintf(stderr, "si->dep_prev = %p; want %p\n", si->dep_prev, stream);
415
assert(0);
416
}
417
check_dep_prev(si);
418
}
419
}
420
421
#endif /* STREAM_DEP_DEBUG */
422
423
#ifdef STREAM_DEP_DEBUG
424
static void validate_tree(nghttp2_stream *stream) {
425
nghttp2_stream *si;
426
427
if (!stream) {
428
return;
429
}
430
431
for (; stream->dep_prev; stream = stream->dep_prev)
432
;
433
434
assert(stream->stream_id == 0);
435
assert(!stream->queued);
436
437
fprintf(stderr, "checking...\n");
438
if (nghttp2_pq_empty(&stream->obq)) {
439
fprintf(stderr, "root obq empty\n");
440
for (si = stream->dep_next; si; si = si->sib_next) {
441
ensure_inactive(si);
442
}
443
} else {
444
for (si = stream->dep_next; si; si = si->sib_next) {
445
check_queued(si);
446
}
447
}
448
449
check_sum_dep(stream);
450
check_dep_prev(stream);
451
}
452
#else /* !STREAM_DEP_DEBUG */
453
static void validate_tree(nghttp2_stream *stream) { (void)stream; }
454
#endif /* !STREAM_DEP_DEBUG*/
455
456
static int stream_update_dep_on_attach_item(nghttp2_stream *stream) {
457
int rv;
458
459
rv = stream_obq_push(stream->dep_prev, stream);
460
if (rv != 0) {
461
return rv;
462
}
463
464
validate_tree(stream);
465
return 0;
466
}
467
468
static int stream_update_dep_on_detach_item(nghttp2_stream *stream) {
469
if (nghttp2_pq_empty(&stream->obq)) {
470
stream_obq_remove(stream);
471
}
472
473
validate_tree(stream);
474
475
return 0;
476
}
477
478
int nghttp2_stream_attach_item(nghttp2_stream *stream,
479
nghttp2_outbound_item *item) {
480
int rv;
481
482
assert((stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0);
483
assert(stream->item == NULL);
484
485
DEBUGF("stream: stream=%d attach item=%p\n", stream->stream_id, item);
486
487
stream->item = item;
488
489
if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
490
return 0;
491
}
492
493
rv = stream_update_dep_on_attach_item(stream);
494
if (rv != 0) {
495
/* This may relave stream->queued == 1, but stream->item == NULL.
496
But only consequence of this error is fatal one, and session
497
destruction. In that execution path, these inconsistency does
498
not matter. */
499
stream->item = NULL;
500
return rv;
501
}
502
503
return 0;
504
}
505
506
int nghttp2_stream_detach_item(nghttp2_stream *stream) {
507
DEBUGF("stream: stream=%d detach item=%p\n", stream->stream_id, stream->item);
508
509
stream->item = NULL;
510
stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL);
511
512
if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
513
return 0;
514
}
515
516
return stream_update_dep_on_detach_item(stream);
517
}
518
519
int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) {
520
assert(stream->item);
521
522
DEBUGF("stream: stream=%d defer item=%p cause=%02x\n", stream->stream_id,
523
stream->item, flags);
524
525
stream->flags |= flags;
526
527
if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
528
return 0;
529
}
530
531
return stream_update_dep_on_detach_item(stream);
532
}
533
534
int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags) {
535
assert(stream->item);
536
537
DEBUGF("stream: stream=%d resume item=%p flags=%02x\n", stream->stream_id,
538
stream->item, flags);
539
540
stream->flags = (uint8_t)(stream->flags & ~flags);
541
542
if (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) {
543
return 0;
544
}
545
546
if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
547
return 0;
548
}
549
550
return stream_update_dep_on_attach_item(stream);
551
}
552
553
int nghttp2_stream_check_deferred_item(nghttp2_stream *stream) {
554
return stream->item && (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL);
555
}
556
557
int nghttp2_stream_check_deferred_by_flow_control(nghttp2_stream *stream) {
558
return stream->item &&
559
(stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
560
}
561
562
static int update_initial_window_size(int32_t *window_size_ptr,
563
int32_t new_initial_window_size,
564
int32_t old_initial_window_size) {
565
int64_t new_window_size = (int64_t)(*window_size_ptr) +
566
new_initial_window_size - old_initial_window_size;
567
if (INT32_MIN > new_window_size ||
568
new_window_size > NGHTTP2_MAX_WINDOW_SIZE) {
569
return -1;
570
}
571
*window_size_ptr = (int32_t)new_window_size;
572
return 0;
573
}
574
575
int nghttp2_stream_update_remote_initial_window_size(
576
nghttp2_stream *stream, int32_t new_initial_window_size,
577
int32_t old_initial_window_size) {
578
return update_initial_window_size(&stream->remote_window_size,
579
new_initial_window_size,
580
old_initial_window_size);
581
}
582
583
int nghttp2_stream_update_local_initial_window_size(
584
nghttp2_stream *stream, int32_t new_initial_window_size,
585
int32_t old_initial_window_size) {
586
return update_initial_window_size(&stream->local_window_size,
587
new_initial_window_size,
588
old_initial_window_size);
589
}
590
591
void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream) {
592
stream->state = NGHTTP2_STREAM_OPENED;
593
stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_PUSH);
594
}
595
596
int nghttp2_stream_dep_find_ancestor(nghttp2_stream *stream,
597
nghttp2_stream *target) {
598
for (; stream; stream = stream->dep_prev) {
599
if (stream == target) {
600
return 1;
601
}
602
}
603
return 0;
604
}
605
606
int nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
607
nghttp2_stream *stream) {
608
nghttp2_stream *si;
609
int rv;
610
611
DEBUGF("stream: dep_insert dep_stream(%p)=%d, stream(%p)=%d\n", dep_stream,
612
dep_stream->stream_id, stream, stream->stream_id);
613
614
stream->sum_dep_weight = dep_stream->sum_dep_weight;
615
dep_stream->sum_dep_weight = stream->weight;
616
617
if (dep_stream->dep_next) {
618
for (si = dep_stream->dep_next; si; si = si->sib_next) {
619
si->dep_prev = stream;
620
if (si->queued) {
621
rv = stream_obq_move(stream, dep_stream, si);
622
if (rv != 0) {
623
return rv;
624
}
625
}
626
}
627
628
if (stream_subtree_active(stream)) {
629
rv = stream_obq_push(dep_stream, stream);
630
if (rv != 0) {
631
return rv;
632
}
633
}
634
635
stream->dep_next = dep_stream->dep_next;
636
}
637
638
dep_stream->dep_next = stream;
639
stream->dep_prev = dep_stream;
640
641
validate_tree(stream);
642
643
return 0;
644
}
645
646
static void set_dep_prev(nghttp2_stream *stream, nghttp2_stream *dep) {
647
for (; stream; stream = stream->sib_next) {
648
stream->dep_prev = dep;
649
}
650
}
651
652
static void link_dep(nghttp2_stream *dep_stream, nghttp2_stream *stream) {
653
dep_stream->dep_next = stream;
654
if (stream) {
655
stream->dep_prev = dep_stream;
656
}
657
}
658
659
static void link_sib(nghttp2_stream *a, nghttp2_stream *b) {
660
a->sib_next = b;
661
if (b) {
662
b->sib_prev = a;
663
}
664
}
665
666
static void insert_link_dep(nghttp2_stream *dep_stream,
667
nghttp2_stream *stream) {
668
nghttp2_stream *sib_next;
669
670
assert(stream->sib_prev == NULL);
671
672
sib_next = dep_stream->dep_next;
673
674
link_sib(stream, sib_next);
675
676
link_dep(dep_stream, stream);
677
}
678
679
static void unlink_sib(nghttp2_stream *stream) {
680
nghttp2_stream *prev, *next, *dep_next;
681
682
prev = stream->sib_prev;
683
dep_next = stream->dep_next;
684
685
assert(prev);
686
687
if (dep_next) {
688
/*
689
* prev--stream(--sib_next--...)
690
* |
691
* dep_next
692
*/
693
694
link_sib(prev, dep_next);
695
696
set_dep_prev(dep_next, stream->dep_prev);
697
698
if (stream->sib_next) {
699
link_sib(stream_last_sib(dep_next), stream->sib_next);
700
}
701
} else {
702
/*
703
* prev--stream(--sib_next--...)
704
*/
705
next = stream->sib_next;
706
707
prev->sib_next = next;
708
709
if (next) {
710
next->sib_prev = prev;
711
}
712
}
713
}
714
715
static void unlink_dep(nghttp2_stream *stream) {
716
nghttp2_stream *prev, *next, *dep_next;
717
718
prev = stream->dep_prev;
719
dep_next = stream->dep_next;
720
721
assert(prev);
722
723
if (dep_next) {
724
/*
725
* prev
726
* |
727
* stream(--sib_next--...)
728
* |
729
* dep_next
730
*/
731
link_dep(prev, dep_next);
732
733
set_dep_prev(dep_next, stream->dep_prev);
734
735
if (stream->sib_next) {
736
link_sib(stream_last_sib(dep_next), stream->sib_next);
737
}
738
739
} else if (stream->sib_next) {
740
/*
741
* prev
742
* |
743
* stream--sib_next
744
*/
745
next = stream->sib_next;
746
747
next->sib_prev = NULL;
748
749
link_dep(prev, next);
750
} else {
751
prev->dep_next = NULL;
752
}
753
}
754
755
void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
756
nghttp2_stream *stream) {
757
DEBUGF("stream: dep_add dep_stream(%p)=%d, stream(%p)=%d\n", dep_stream,
758
dep_stream->stream_id, stream, stream->stream_id);
759
760
dep_stream->sum_dep_weight += stream->weight;
761
762
if (dep_stream->dep_next == NULL) {
763
link_dep(dep_stream, stream);
764
} else {
765
insert_link_dep(dep_stream, stream);
766
}
767
768
validate_tree(stream);
769
}
770
771
int nghttp2_stream_dep_remove(nghttp2_stream *stream) {
772
nghttp2_stream *dep_prev, *si;
773
int32_t sum_dep_weight_delta;
774
int rv;
775
776
DEBUGF("stream: dep_remove stream(%p)=%d\n", stream, stream->stream_id);
777
778
/* Distribute weight of |stream| to direct descendants */
779
sum_dep_weight_delta = -stream->weight;
780
781
for (si = stream->dep_next; si; si = si->sib_next) {
782
si->weight = nghttp2_stream_dep_distributed_weight(stream, si->weight);
783
784
sum_dep_weight_delta += si->weight;
785
786
if (si->queued) {
787
rv = stream_obq_move(stream->dep_prev, stream, si);
788
if (rv != 0) {
789
return rv;
790
}
791
}
792
}
793
794
assert(stream->dep_prev);
795
796
dep_prev = stream->dep_prev;
797
798
dep_prev->sum_dep_weight += sum_dep_weight_delta;
799
800
if (stream->queued) {
801
stream_obq_remove(stream);
802
}
803
804
if (stream->sib_prev) {
805
unlink_sib(stream);
806
} else {
807
unlink_dep(stream);
808
}
809
810
stream->sum_dep_weight = 0;
811
812
stream->dep_prev = NULL;
813
stream->dep_next = NULL;
814
stream->sib_prev = NULL;
815
stream->sib_next = NULL;
816
817
validate_tree(dep_prev);
818
819
return 0;
820
}
821
822
int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
823
nghttp2_stream *stream) {
824
nghttp2_stream *last_sib;
825
nghttp2_stream *dep_next;
826
nghttp2_stream *si;
827
int rv;
828
829
DEBUGF("stream: dep_insert_subtree dep_stream(%p)=%d stream(%p)=%d\n",
830
dep_stream, dep_stream->stream_id, stream, stream->stream_id);
831
832
stream->sum_dep_weight += dep_stream->sum_dep_weight;
833
dep_stream->sum_dep_weight = stream->weight;
834
835
if (dep_stream->dep_next) {
836
dep_next = dep_stream->dep_next;
837
838
link_dep(dep_stream, stream);
839
840
if (stream->dep_next) {
841
last_sib = stream_last_sib(stream->dep_next);
842
843
link_sib(last_sib, dep_next);
844
} else {
845
link_dep(stream, dep_next);
846
}
847
848
for (si = dep_next; si; si = si->sib_next) {
849
si->dep_prev = stream;
850
if (si->queued) {
851
rv = stream_obq_move(stream, dep_stream, si);
852
if (rv != 0) {
853
return rv;
854
}
855
}
856
}
857
} else {
858
link_dep(dep_stream, stream);
859
}
860
861
if (stream_subtree_active(stream)) {
862
rv = stream_obq_push(dep_stream, stream);
863
if (rv != 0) {
864
return rv;
865
}
866
}
867
868
validate_tree(dep_stream);
869
870
return 0;
871
}
872
873
int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
874
nghttp2_stream *stream) {
875
int rv;
876
877
DEBUGF("stream: dep_add_subtree dep_stream(%p)=%d stream(%p)=%d\n",
878
dep_stream, dep_stream->stream_id, stream, stream->stream_id);
879
880
dep_stream->sum_dep_weight += stream->weight;
881
882
if (dep_stream->dep_next) {
883
insert_link_dep(dep_stream, stream);
884
} else {
885
link_dep(dep_stream, stream);
886
}
887
888
if (stream_subtree_active(stream)) {
889
rv = stream_obq_push(dep_stream, stream);
890
if (rv != 0) {
891
return rv;
892
}
893
}
894
895
validate_tree(dep_stream);
896
897
return 0;
898
}
899
900
void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) {
901
nghttp2_stream *next, *dep_prev;
902
903
DEBUGF("stream: dep_remove_subtree stream(%p)=%d\n", stream,
904
stream->stream_id);
905
906
assert(stream->dep_prev);
907
908
dep_prev = stream->dep_prev;
909
910
if (stream->sib_prev) {
911
link_sib(stream->sib_prev, stream->sib_next);
912
} else {
913
next = stream->sib_next;
914
915
link_dep(dep_prev, next);
916
917
if (next) {
918
next->sib_prev = NULL;
919
}
920
}
921
922
dep_prev->sum_dep_weight -= stream->weight;
923
924
if (stream->queued) {
925
stream_obq_remove(stream);
926
}
927
928
validate_tree(dep_prev);
929
930
stream->sib_prev = NULL;
931
stream->sib_next = NULL;
932
stream->dep_prev = NULL;
933
}
934
935
int nghttp2_stream_in_dep_tree(nghttp2_stream *stream) {
936
return stream->dep_prev || stream->dep_next || stream->sib_prev ||
937
stream->sib_next;
938
}
939
940
nghttp2_outbound_item *
941
nghttp2_stream_next_outbound_item(nghttp2_stream *stream) {
942
nghttp2_pq_entry *ent;
943
nghttp2_stream *si;
944
945
for (;;) {
946
if (stream_active(stream)) {
947
/* Update ascendant's descendant_last_cycle here, so that we can
948
assure that new stream is scheduled based on it. */
949
for (si = stream; si->dep_prev; si = si->dep_prev) {
950
si->dep_prev->descendant_last_cycle = si->cycle;
951
}
952
return stream->item;
953
}
954
ent = nghttp2_pq_top(&stream->obq);
955
if (!ent) {
956
return NULL;
957
}
958
stream = nghttp2_struct_of(ent, nghttp2_stream, pq_entry);
959
}
960
}
961
962
nghttp2_stream_proto_state nghttp2_stream_get_state(nghttp2_stream *stream) {
963
if (stream->flags & NGHTTP2_STREAM_FLAG_CLOSED) {
964
return NGHTTP2_STREAM_STATE_CLOSED;
965
}
966
967
if (stream->flags & NGHTTP2_STREAM_FLAG_PUSH) {
968
if (stream->shut_flags & NGHTTP2_SHUT_RD) {
969
return NGHTTP2_STREAM_STATE_RESERVED_LOCAL;
970
}
971
972
if (stream->shut_flags & NGHTTP2_SHUT_WR) {
973
return NGHTTP2_STREAM_STATE_RESERVED_REMOTE;
974
}
975
}
976
977
if (stream->shut_flags & NGHTTP2_SHUT_RD) {
978
return NGHTTP2_STREAM_STATE_HALF_CLOSED_REMOTE;
979
}
980
981
if (stream->shut_flags & NGHTTP2_SHUT_WR) {
982
return NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL;
983
}
984
985
if (stream->state == NGHTTP2_STREAM_IDLE) {
986
return NGHTTP2_STREAM_STATE_IDLE;
987
}
988
989
return NGHTTP2_STREAM_STATE_OPEN;
990
}
991
992
nghttp2_stream *nghttp2_stream_get_parent(nghttp2_stream *stream) {
993
return stream->dep_prev;
994
}
995
996
nghttp2_stream *nghttp2_stream_get_next_sibling(nghttp2_stream *stream) {
997
return stream->sib_next;
998
}
999
1000
nghttp2_stream *nghttp2_stream_get_previous_sibling(nghttp2_stream *stream) {
1001
return stream->sib_prev;
1002
}
1003
1004
nghttp2_stream *nghttp2_stream_get_first_child(nghttp2_stream *stream) {
1005
return stream->dep_next;
1006
}
1007
1008
int32_t nghttp2_stream_get_weight(nghttp2_stream *stream) {
1009
return stream->weight;
1010
}
1011
1012
int32_t nghttp2_stream_get_sum_dependency_weight(nghttp2_stream *stream) {
1013
return stream->sum_dep_weight;
1014
}
1015
1016
int32_t nghttp2_stream_get_stream_id(nghttp2_stream *stream) {
1017
return stream->stream_id;
1018
}
1019
1020