nghttp2_stream.c 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000
  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. #include <assert.h>
  27. #include <stdio.h>
  28. #include "nghttp2_session.h"
  29. #include "nghttp2_helper.h"
  30. #include "nghttp2_debug.h"
  31. #include "nghttp2_frame.h"
  32. /* Maximum distance between any two stream's cycle in the same
  33. priority queue. Imagine stream A's cycle is A, and stream B's
  34. cycle is B, and A < B. The cycle is unsigned 32 bit integer, it
  35. may get overflow. Because of how we calculate the next cycle
  36. value, if B - A is less than or equals to
  37. NGHTTP2_MAX_CYCLE_DISTANCE, A and B are in the same scale, in other
  38. words, B is really greater than or equal to A. Otherwise, A is a
  39. result of overflow, and it is actually A > B if we consider that
  40. fact. */
  41. #define NGHTTP2_MAX_CYCLE_DISTANCE \
  42. ((uint64_t)NGHTTP2_MAX_FRAME_SIZE_MAX * 256 + 255)
  43. static int stream_less(const void *lhsx, const void *rhsx) {
  44. const nghttp2_stream *lhs, *rhs;
  45. lhs = nghttp2_struct_of(lhsx, nghttp2_stream, pq_entry);
  46. rhs = nghttp2_struct_of(rhsx, nghttp2_stream, pq_entry);
  47. if (lhs->cycle == rhs->cycle) {
  48. return lhs->seq < rhs->seq;
  49. }
  50. return rhs->cycle - lhs->cycle <= NGHTTP2_MAX_CYCLE_DISTANCE;
  51. }
  52. void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
  53. uint8_t flags, nghttp2_stream_state initial_state,
  54. int32_t weight, int32_t remote_initial_window_size,
  55. int32_t local_initial_window_size,
  56. void *stream_user_data, nghttp2_mem *mem) {
  57. nghttp2_pq_init(&stream->obq, stream_less, mem);
  58. stream->stream_id = stream_id;
  59. stream->flags = flags;
  60. stream->state = initial_state;
  61. stream->shut_flags = NGHTTP2_SHUT_NONE;
  62. stream->stream_user_data = stream_user_data;
  63. stream->item = NULL;
  64. stream->remote_window_size = remote_initial_window_size;
  65. stream->local_window_size = local_initial_window_size;
  66. stream->recv_window_size = 0;
  67. stream->consumed_size = 0;
  68. stream->recv_reduction = 0;
  69. stream->window_update_queued = 0;
  70. stream->dep_prev = NULL;
  71. stream->dep_next = NULL;
  72. stream->sib_prev = NULL;
  73. stream->sib_next = NULL;
  74. stream->closed_prev = NULL;
  75. stream->closed_next = NULL;
  76. stream->weight = weight;
  77. stream->sum_dep_weight = 0;
  78. stream->http_flags = NGHTTP2_HTTP_FLAG_NONE;
  79. stream->content_length = -1;
  80. stream->recv_content_length = 0;
  81. stream->status_code = -1;
  82. stream->queued = 0;
  83. stream->descendant_last_cycle = 0;
  84. stream->cycle = 0;
  85. stream->pending_penalty = 0;
  86. stream->descendant_next_seq = 0;
  87. stream->seq = 0;
  88. stream->last_writelen = 0;
  89. }
  90. void nghttp2_stream_free(nghttp2_stream *stream) {
  91. nghttp2_pq_free(&stream->obq);
  92. /* We don't free stream->item. If it is assigned to aob, then
  93. active_outbound_item_reset() will delete it. Otherwise,
  94. nghttp2_stream_close() or session_del() will delete it. */
  95. }
  96. void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag) {
  97. stream->shut_flags = (uint8_t)(stream->shut_flags | flag);
  98. }
  99. /*
  100. * Returns nonzero if |stream| is active. This function does not take
  101. * into account its descendants.
  102. */
  103. static int stream_active(nghttp2_stream *stream) {
  104. return stream->item &&
  105. (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0;
  106. }
  107. /*
  108. * Returns nonzero if |stream| or one of its descendants is active
  109. */
  110. static int stream_subtree_active(nghttp2_stream *stream) {
  111. return stream_active(stream) || !nghttp2_pq_empty(&stream->obq);
  112. }
  113. /*
  114. * Returns next cycle for |stream|.
  115. */
  116. static void stream_next_cycle(nghttp2_stream *stream, uint64_t last_cycle) {
  117. uint64_t penalty;
  118. penalty = (uint64_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT +
  119. stream->pending_penalty;
  120. stream->cycle = last_cycle + penalty / (uint32_t)stream->weight;
  121. stream->pending_penalty = (uint32_t)(penalty % (uint32_t)stream->weight);
  122. }
  123. static int stream_obq_push(nghttp2_stream *dep_stream, nghttp2_stream *stream) {
  124. int rv;
  125. for (; dep_stream && !stream->queued;
  126. stream = dep_stream, dep_stream = dep_stream->dep_prev) {
  127. stream_next_cycle(stream, dep_stream->descendant_last_cycle);
  128. stream->seq = dep_stream->descendant_next_seq++;
  129. DEBUGF("stream: stream=%d obq push cycle=%lu\n", stream->stream_id,
  130. stream->cycle);
  131. DEBUGF("stream: push stream %d to stream %d\n", stream->stream_id,
  132. dep_stream->stream_id);
  133. rv = nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);
  134. if (rv != 0) {
  135. return rv;
  136. }
  137. stream->queued = 1;
  138. }
  139. return 0;
  140. }
  141. /*
  142. * Removes |stream| from parent's obq. If removal of |stream| makes
  143. * parent's obq empty, and parent is not active, then parent is also
  144. * removed. This process is repeated recursively.
  145. */
  146. static void stream_obq_remove(nghttp2_stream *stream) {
  147. nghttp2_stream *dep_stream;
  148. dep_stream = stream->dep_prev;
  149. if (!stream->queued) {
  150. return;
  151. }
  152. for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) {
  153. DEBUGF("stream: remove stream %d from stream %d\n", stream->stream_id,
  154. dep_stream->stream_id);
  155. nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
  156. assert(stream->queued);
  157. stream->queued = 0;
  158. stream->cycle = 0;
  159. stream->pending_penalty = 0;
  160. stream->descendant_last_cycle = 0;
  161. stream->last_writelen = 0;
  162. if (stream_subtree_active(dep_stream)) {
  163. return;
  164. }
  165. }
  166. }
  167. /*
  168. * Moves |stream| from |src|'s obq to |dest|'s obq. Removal from
  169. * |src|'s obq is just done calling nghttp2_pq_remove(), so it does
  170. * not recursively remove |src| and ancestors, like
  171. * stream_obq_remove().
  172. */
  173. static int stream_obq_move(nghttp2_stream *dest, nghttp2_stream *src,
  174. nghttp2_stream *stream) {
  175. if (!stream->queued) {
  176. return 0;
  177. }
  178. DEBUGF("stream: remove stream %d from stream %d (move)\n", stream->stream_id,
  179. src->stream_id);
  180. nghttp2_pq_remove(&src->obq, &stream->pq_entry);
  181. stream->queued = 0;
  182. return stream_obq_push(dest, stream);
  183. }
  184. void nghttp2_stream_reschedule(nghttp2_stream *stream) {
  185. nghttp2_stream *dep_stream;
  186. assert(stream->queued);
  187. dep_stream = stream->dep_prev;
  188. for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) {
  189. nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
  190. stream_next_cycle(stream, dep_stream->descendant_last_cycle);
  191. stream->seq = dep_stream->descendant_next_seq++;
  192. nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);
  193. DEBUGF("stream: stream=%d obq resched cycle=%lu\n", stream->stream_id,
  194. stream->cycle);
  195. dep_stream->last_writelen = stream->last_writelen;
  196. }
  197. }
  198. void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight) {
  199. nghttp2_stream *dep_stream;
  200. uint64_t last_cycle;
  201. int32_t old_weight;
  202. uint64_t wlen_penalty;
  203. if (stream->weight == weight) {
  204. return;
  205. }
  206. old_weight = stream->weight;
  207. stream->weight = weight;
  208. dep_stream = stream->dep_prev;
  209. if (!dep_stream) {
  210. return;
  211. }
  212. dep_stream->sum_dep_weight += weight - old_weight;
  213. if (!stream->queued) {
  214. return;
  215. }
  216. nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
  217. wlen_penalty = (uint64_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT;
  218. /* Compute old stream->pending_penalty we used to calculate
  219. stream->cycle */
  220. stream->pending_penalty =
  221. (uint32_t)((stream->pending_penalty + (uint32_t)old_weight -
  222. (wlen_penalty % (uint32_t)old_weight)) %
  223. (uint32_t)old_weight);
  224. last_cycle = stream->cycle -
  225. (wlen_penalty + stream->pending_penalty) / (uint32_t)old_weight;
  226. /* Now we have old stream->pending_penalty and new stream->weight in
  227. place */
  228. stream_next_cycle(stream, last_cycle);
  229. if (dep_stream->descendant_last_cycle - stream->cycle <=
  230. NGHTTP2_MAX_CYCLE_DISTANCE) {
  231. stream->cycle = dep_stream->descendant_last_cycle;
  232. }
  233. /* Continue to use same stream->seq */
  234. nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);
  235. DEBUGF("stream: stream=%d obq resched cycle=%lu\n", stream->stream_id,
  236. stream->cycle);
  237. }
  238. static nghttp2_stream *stream_last_sib(nghttp2_stream *stream) {
  239. for (; stream->sib_next; stream = stream->sib_next)
  240. ;
  241. return stream;
  242. }
  243. int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
  244. int32_t weight) {
  245. weight = stream->weight * weight / stream->sum_dep_weight;
  246. return nghttp2_max(1, weight);
  247. }
  248. #ifdef STREAM_DEP_DEBUG
  249. static void ensure_inactive(nghttp2_stream *stream) {
  250. nghttp2_stream *si;
  251. if (stream->queued) {
  252. fprintf(stderr, "stream(%p)=%d, stream->queued = 1; want 0\n", stream,
  253. stream->stream_id);
  254. assert(0);
  255. }
  256. if (stream_active(stream)) {
  257. fprintf(stderr, "stream(%p)=%d, stream_active(stream) = 1; want 0\n",
  258. stream, stream->stream_id);
  259. assert(0);
  260. }
  261. if (!nghttp2_pq_empty(&stream->obq)) {
  262. fprintf(stderr, "stream(%p)=%d, nghttp2_pq_size() = %zu; want 0\n", stream,
  263. stream->stream_id, nghttp2_pq_size(&stream->obq));
  264. assert(0);
  265. }
  266. for (si = stream->dep_next; si; si = si->sib_next) {
  267. ensure_inactive(si);
  268. }
  269. }
  270. static void check_queued(nghttp2_stream *stream) {
  271. nghttp2_stream *si;
  272. int queued;
  273. if (stream->queued) {
  274. if (!stream_subtree_active(stream)) {
  275. fprintf(stderr,
  276. "stream(%p)=%d, stream->queued == 1, but "
  277. "stream_active() == %d and nghttp2_pq_size(&stream->obq) = %zu\n",
  278. stream, stream->stream_id, stream_active(stream),
  279. nghttp2_pq_size(&stream->obq));
  280. assert(0);
  281. }
  282. if (!stream_active(stream)) {
  283. queued = 0;
  284. for (si = stream->dep_next; si; si = si->sib_next) {
  285. if (si->queued) {
  286. ++queued;
  287. }
  288. }
  289. if (queued == 0) {
  290. fprintf(stderr,
  291. "stream(%p)=%d, stream->queued == 1, and "
  292. "!stream_active(), but no descendants is queued\n",
  293. stream, stream->stream_id);
  294. assert(0);
  295. }
  296. }
  297. for (si = stream->dep_next; si; si = si->sib_next) {
  298. check_queued(si);
  299. }
  300. } else {
  301. if (stream_active(stream) || !nghttp2_pq_empty(&stream->obq)) {
  302. fprintf(stderr,
  303. "stream(%p) = %d, stream->queued == 0, but "
  304. "stream_active(stream) == %d and "
  305. "nghttp2_pq_size(&stream->obq) = %zu\n",
  306. stream, stream->stream_id, stream_active(stream),
  307. nghttp2_pq_size(&stream->obq));
  308. assert(0);
  309. }
  310. for (si = stream->dep_next; si; si = si->sib_next) {
  311. ensure_inactive(si);
  312. }
  313. }
  314. }
  315. static void check_sum_dep(nghttp2_stream *stream) {
  316. nghttp2_stream *si;
  317. int32_t n = 0;
  318. for (si = stream->dep_next; si; si = si->sib_next) {
  319. n += si->weight;
  320. }
  321. if (n != stream->sum_dep_weight) {
  322. fprintf(stderr, "stream(%p)=%d, sum_dep_weight = %d; want %d\n", stream,
  323. stream->stream_id, n, stream->sum_dep_weight);
  324. assert(0);
  325. }
  326. for (si = stream->dep_next; si; si = si->sib_next) {
  327. check_sum_dep(si);
  328. }
  329. }
  330. static void check_dep_prev(nghttp2_stream *stream) {
  331. nghttp2_stream *si;
  332. for (si = stream->dep_next; si; si = si->sib_next) {
  333. if (si->dep_prev != stream) {
  334. fprintf(stderr, "si->dep_prev = %p; want %p\n", si->dep_prev, stream);
  335. assert(0);
  336. }
  337. check_dep_prev(si);
  338. }
  339. }
  340. #endif /* STREAM_DEP_DEBUG */
  341. #ifdef STREAM_DEP_DEBUG
  342. static void validate_tree(nghttp2_stream *stream) {
  343. nghttp2_stream *si;
  344. if (!stream) {
  345. return;
  346. }
  347. for (; stream->dep_prev; stream = stream->dep_prev)
  348. ;
  349. assert(stream->stream_id == 0);
  350. assert(!stream->queued);
  351. fprintf(stderr, "checking...\n");
  352. if (nghttp2_pq_empty(&stream->obq)) {
  353. fprintf(stderr, "root obq empty\n");
  354. for (si = stream->dep_next; si; si = si->sib_next) {
  355. ensure_inactive(si);
  356. }
  357. } else {
  358. for (si = stream->dep_next; si; si = si->sib_next) {
  359. check_queued(si);
  360. }
  361. }
  362. check_sum_dep(stream);
  363. check_dep_prev(stream);
  364. }
  365. #else /* !STREAM_DEP_DEBUG */
  366. static void validate_tree(nghttp2_stream *stream) { (void)stream; }
  367. #endif /* !STREAM_DEP_DEBUG*/
  368. static int stream_update_dep_on_attach_item(nghttp2_stream *stream) {
  369. int rv;
  370. rv = stream_obq_push(stream->dep_prev, stream);
  371. if (rv != 0) {
  372. return rv;
  373. }
  374. validate_tree(stream);
  375. return 0;
  376. }
  377. static int stream_update_dep_on_detach_item(nghttp2_stream *stream) {
  378. if (nghttp2_pq_empty(&stream->obq)) {
  379. stream_obq_remove(stream);
  380. }
  381. validate_tree(stream);
  382. return 0;
  383. }
  384. int nghttp2_stream_attach_item(nghttp2_stream *stream,
  385. nghttp2_outbound_item *item) {
  386. int rv;
  387. assert((stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0);
  388. assert(stream->item == NULL);
  389. DEBUGF("stream: stream=%d attach item=%p\n", stream->stream_id, item);
  390. stream->item = item;
  391. rv = stream_update_dep_on_attach_item(stream);
  392. if (rv != 0) {
  393. /* This may relave stream->queued == 1, but stream->item == NULL.
  394. But only consequence of this error is fatal one, and session
  395. destruction. In that execution path, these inconsistency does
  396. not matter. */
  397. stream->item = NULL;
  398. return rv;
  399. }
  400. return 0;
  401. }
  402. int nghttp2_stream_detach_item(nghttp2_stream *stream) {
  403. DEBUGF("stream: stream=%d detach item=%p\n", stream->stream_id, stream->item);
  404. stream->item = NULL;
  405. stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL);
  406. return stream_update_dep_on_detach_item(stream);
  407. }
  408. int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) {
  409. assert(stream->item);
  410. DEBUGF("stream: stream=%d defer item=%p cause=%02x\n", stream->stream_id,
  411. stream->item, flags);
  412. stream->flags |= flags;
  413. return stream_update_dep_on_detach_item(stream);
  414. }
  415. int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags) {
  416. assert(stream->item);
  417. DEBUGF("stream: stream=%d resume item=%p flags=%02x\n", stream->stream_id,
  418. stream->item, flags);
  419. stream->flags = (uint8_t)(stream->flags & ~flags);
  420. if (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) {
  421. return 0;
  422. }
  423. return stream_update_dep_on_attach_item(stream);
  424. }
  425. int nghttp2_stream_check_deferred_item(nghttp2_stream *stream) {
  426. return stream->item && (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL);
  427. }
  428. int nghttp2_stream_check_deferred_by_flow_control(nghttp2_stream *stream) {
  429. return stream->item &&
  430. (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
  431. }
  432. static int update_initial_window_size(int32_t *window_size_ptr,
  433. int32_t new_initial_window_size,
  434. int32_t old_initial_window_size) {
  435. int64_t new_window_size = (int64_t)(*window_size_ptr) +
  436. new_initial_window_size - old_initial_window_size;
  437. if (INT32_MIN > new_window_size ||
  438. new_window_size > NGHTTP2_MAX_WINDOW_SIZE) {
  439. return -1;
  440. }
  441. *window_size_ptr = (int32_t)new_window_size;
  442. return 0;
  443. }
  444. int nghttp2_stream_update_remote_initial_window_size(
  445. nghttp2_stream *stream, int32_t new_initial_window_size,
  446. int32_t old_initial_window_size) {
  447. return update_initial_window_size(&stream->remote_window_size,
  448. new_initial_window_size,
  449. old_initial_window_size);
  450. }
  451. int nghttp2_stream_update_local_initial_window_size(
  452. nghttp2_stream *stream, int32_t new_initial_window_size,
  453. int32_t old_initial_window_size) {
  454. return update_initial_window_size(&stream->local_window_size,
  455. new_initial_window_size,
  456. old_initial_window_size);
  457. }
  458. void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream) {
  459. stream->state = NGHTTP2_STREAM_OPENED;
  460. stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_PUSH);
  461. }
  462. int nghttp2_stream_dep_find_ancestor(nghttp2_stream *stream,
  463. nghttp2_stream *target) {
  464. for (; stream; stream = stream->dep_prev) {
  465. if (stream == target) {
  466. return 1;
  467. }
  468. }
  469. return 0;
  470. }
  471. int nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
  472. nghttp2_stream *stream) {
  473. nghttp2_stream *si;
  474. int rv;
  475. DEBUGF("stream: dep_insert dep_stream(%p)=%d, stream(%p)=%d\n", dep_stream,
  476. dep_stream->stream_id, stream, stream->stream_id);
  477. stream->sum_dep_weight = dep_stream->sum_dep_weight;
  478. dep_stream->sum_dep_weight = stream->weight;
  479. if (dep_stream->dep_next) {
  480. for (si = dep_stream->dep_next; si; si = si->sib_next) {
  481. si->dep_prev = stream;
  482. if (si->queued) {
  483. rv = stream_obq_move(stream, dep_stream, si);
  484. if (rv != 0) {
  485. return rv;
  486. }
  487. }
  488. }
  489. if (stream_subtree_active(stream)) {
  490. rv = stream_obq_push(dep_stream, stream);
  491. if (rv != 0) {
  492. return rv;
  493. }
  494. }
  495. stream->dep_next = dep_stream->dep_next;
  496. }
  497. dep_stream->dep_next = stream;
  498. stream->dep_prev = dep_stream;
  499. validate_tree(stream);
  500. return 0;
  501. }
  502. static void set_dep_prev(nghttp2_stream *stream, nghttp2_stream *dep) {
  503. for (; stream; stream = stream->sib_next) {
  504. stream->dep_prev = dep;
  505. }
  506. }
  507. static void link_dep(nghttp2_stream *dep_stream, nghttp2_stream *stream) {
  508. dep_stream->dep_next = stream;
  509. if (stream) {
  510. stream->dep_prev = dep_stream;
  511. }
  512. }
  513. static void link_sib(nghttp2_stream *a, nghttp2_stream *b) {
  514. a->sib_next = b;
  515. if (b) {
  516. b->sib_prev = a;
  517. }
  518. }
  519. static void insert_link_dep(nghttp2_stream *dep_stream,
  520. nghttp2_stream *stream) {
  521. nghttp2_stream *sib_next;
  522. assert(stream->sib_prev == NULL);
  523. sib_next = dep_stream->dep_next;
  524. link_sib(stream, sib_next);
  525. link_dep(dep_stream, stream);
  526. }
  527. static void unlink_sib(nghttp2_stream *stream) {
  528. nghttp2_stream *prev, *next, *dep_next;
  529. prev = stream->sib_prev;
  530. dep_next = stream->dep_next;
  531. assert(prev);
  532. if (dep_next) {
  533. /*
  534. * prev--stream(--sib_next--...)
  535. * |
  536. * dep_next
  537. */
  538. link_sib(prev, dep_next);
  539. set_dep_prev(dep_next, stream->dep_prev);
  540. if (stream->sib_next) {
  541. link_sib(stream_last_sib(dep_next), stream->sib_next);
  542. }
  543. } else {
  544. /*
  545. * prev--stream(--sib_next--...)
  546. */
  547. next = stream->sib_next;
  548. prev->sib_next = next;
  549. if (next) {
  550. next->sib_prev = prev;
  551. }
  552. }
  553. }
  554. static void unlink_dep(nghttp2_stream *stream) {
  555. nghttp2_stream *prev, *next, *dep_next;
  556. prev = stream->dep_prev;
  557. dep_next = stream->dep_next;
  558. assert(prev);
  559. if (dep_next) {
  560. /*
  561. * prev
  562. * |
  563. * stream(--sib_next--...)
  564. * |
  565. * dep_next
  566. */
  567. link_dep(prev, dep_next);
  568. set_dep_prev(dep_next, stream->dep_prev);
  569. if (stream->sib_next) {
  570. link_sib(stream_last_sib(dep_next), stream->sib_next);
  571. }
  572. } else if (stream->sib_next) {
  573. /*
  574. * prev
  575. * |
  576. * stream--sib_next
  577. */
  578. next = stream->sib_next;
  579. next->sib_prev = NULL;
  580. link_dep(prev, next);
  581. } else {
  582. prev->dep_next = NULL;
  583. }
  584. }
  585. void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
  586. nghttp2_stream *stream) {
  587. DEBUGF("stream: dep_add dep_stream(%p)=%d, stream(%p)=%d\n", dep_stream,
  588. dep_stream->stream_id, stream, stream->stream_id);
  589. dep_stream->sum_dep_weight += stream->weight;
  590. if (dep_stream->dep_next == NULL) {
  591. link_dep(dep_stream, stream);
  592. } else {
  593. insert_link_dep(dep_stream, stream);
  594. }
  595. validate_tree(stream);
  596. }
  597. int nghttp2_stream_dep_remove(nghttp2_stream *stream) {
  598. nghttp2_stream *dep_prev, *si;
  599. int32_t sum_dep_weight_delta;
  600. int rv;
  601. DEBUGF("stream: dep_remove stream(%p)=%d\n", stream, stream->stream_id);
  602. /* Distribute weight of |stream| to direct descendants */
  603. sum_dep_weight_delta = -stream->weight;
  604. for (si = stream->dep_next; si; si = si->sib_next) {
  605. si->weight = nghttp2_stream_dep_distributed_weight(stream, si->weight);
  606. sum_dep_weight_delta += si->weight;
  607. if (si->queued) {
  608. rv = stream_obq_move(stream->dep_prev, stream, si);
  609. if (rv != 0) {
  610. return rv;
  611. }
  612. }
  613. }
  614. assert(stream->dep_prev);
  615. dep_prev = stream->dep_prev;
  616. dep_prev->sum_dep_weight += sum_dep_weight_delta;
  617. if (stream->queued) {
  618. stream_obq_remove(stream);
  619. }
  620. if (stream->sib_prev) {
  621. unlink_sib(stream);
  622. } else {
  623. unlink_dep(stream);
  624. }
  625. stream->sum_dep_weight = 0;
  626. stream->dep_prev = NULL;
  627. stream->dep_next = NULL;
  628. stream->sib_prev = NULL;
  629. stream->sib_next = NULL;
  630. validate_tree(dep_prev);
  631. return 0;
  632. }
  633. int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
  634. nghttp2_stream *stream) {
  635. nghttp2_stream *last_sib;
  636. nghttp2_stream *dep_next;
  637. nghttp2_stream *si;
  638. int rv;
  639. DEBUGF("stream: dep_insert_subtree dep_stream(%p)=%d stream(%p)=%d\n",
  640. dep_stream, dep_stream->stream_id, stream, stream->stream_id);
  641. stream->sum_dep_weight += dep_stream->sum_dep_weight;
  642. dep_stream->sum_dep_weight = stream->weight;
  643. if (dep_stream->dep_next) {
  644. dep_next = dep_stream->dep_next;
  645. link_dep(dep_stream, stream);
  646. if (stream->dep_next) {
  647. last_sib = stream_last_sib(stream->dep_next);
  648. link_sib(last_sib, dep_next);
  649. } else {
  650. link_dep(stream, dep_next);
  651. }
  652. for (si = dep_next; si; si = si->sib_next) {
  653. si->dep_prev = stream;
  654. if (si->queued) {
  655. rv = stream_obq_move(stream, dep_stream, si);
  656. if (rv != 0) {
  657. return rv;
  658. }
  659. }
  660. }
  661. } else {
  662. link_dep(dep_stream, stream);
  663. }
  664. if (stream_subtree_active(stream)) {
  665. rv = stream_obq_push(dep_stream, stream);
  666. if (rv != 0) {
  667. return rv;
  668. }
  669. }
  670. validate_tree(dep_stream);
  671. return 0;
  672. }
  673. int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
  674. nghttp2_stream *stream) {
  675. int rv;
  676. DEBUGF("stream: dep_add_subtree dep_stream(%p)=%d stream(%p)=%d\n",
  677. dep_stream, dep_stream->stream_id, stream, stream->stream_id);
  678. dep_stream->sum_dep_weight += stream->weight;
  679. if (dep_stream->dep_next) {
  680. insert_link_dep(dep_stream, stream);
  681. } else {
  682. link_dep(dep_stream, stream);
  683. }
  684. if (stream_subtree_active(stream)) {
  685. rv = stream_obq_push(dep_stream, stream);
  686. if (rv != 0) {
  687. return rv;
  688. }
  689. }
  690. validate_tree(dep_stream);
  691. return 0;
  692. }
  693. void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) {
  694. nghttp2_stream *next, *dep_prev;
  695. DEBUGF("stream: dep_remove_subtree stream(%p)=%d\n", stream,
  696. stream->stream_id);
  697. assert(stream->dep_prev);
  698. dep_prev = stream->dep_prev;
  699. if (stream->sib_prev) {
  700. link_sib(stream->sib_prev, stream->sib_next);
  701. } else {
  702. next = stream->sib_next;
  703. link_dep(dep_prev, next);
  704. if (next) {
  705. next->sib_prev = NULL;
  706. }
  707. }
  708. dep_prev->sum_dep_weight -= stream->weight;
  709. if (stream->queued) {
  710. stream_obq_remove(stream);
  711. }
  712. validate_tree(dep_prev);
  713. stream->sib_prev = NULL;
  714. stream->sib_next = NULL;
  715. stream->dep_prev = NULL;
  716. }
  717. int nghttp2_stream_in_dep_tree(nghttp2_stream *stream) {
  718. return stream->dep_prev || stream->dep_next || stream->sib_prev ||
  719. stream->sib_next;
  720. }
  721. nghttp2_outbound_item *
  722. nghttp2_stream_next_outbound_item(nghttp2_stream *stream) {
  723. nghttp2_pq_entry *ent;
  724. nghttp2_stream *si;
  725. for (;;) {
  726. if (stream_active(stream)) {
  727. /* Update ascendant's descendant_last_cycle here, so that we can
  728. assure that new stream is scheduled based on it. */
  729. for (si = stream; si->dep_prev; si = si->dep_prev) {
  730. si->dep_prev->descendant_last_cycle = si->cycle;
  731. }
  732. return stream->item;
  733. }
  734. ent = nghttp2_pq_top(&stream->obq);
  735. if (!ent) {
  736. return NULL;
  737. }
  738. stream = nghttp2_struct_of(ent, nghttp2_stream, pq_entry);
  739. }
  740. }
  741. nghttp2_stream_proto_state nghttp2_stream_get_state(nghttp2_stream *stream) {
  742. if (stream->flags & NGHTTP2_STREAM_FLAG_CLOSED) {
  743. return NGHTTP2_STREAM_STATE_CLOSED;
  744. }
  745. if (stream->flags & NGHTTP2_STREAM_FLAG_PUSH) {
  746. if (stream->shut_flags & NGHTTP2_SHUT_RD) {
  747. return NGHTTP2_STREAM_STATE_RESERVED_LOCAL;
  748. }
  749. if (stream->shut_flags & NGHTTP2_SHUT_WR) {
  750. return NGHTTP2_STREAM_STATE_RESERVED_REMOTE;
  751. }
  752. }
  753. if (stream->shut_flags & NGHTTP2_SHUT_RD) {
  754. return NGHTTP2_STREAM_STATE_HALF_CLOSED_REMOTE;
  755. }
  756. if (stream->shut_flags & NGHTTP2_SHUT_WR) {
  757. return NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL;
  758. }
  759. if (stream->state == NGHTTP2_STREAM_IDLE) {
  760. return NGHTTP2_STREAM_STATE_IDLE;
  761. }
  762. return NGHTTP2_STREAM_STATE_OPEN;
  763. }
  764. nghttp2_stream *nghttp2_stream_get_parent(nghttp2_stream *stream) {
  765. return stream->dep_prev;
  766. }
  767. nghttp2_stream *nghttp2_stream_get_next_sibling(nghttp2_stream *stream) {
  768. return stream->sib_next;
  769. }
  770. nghttp2_stream *nghttp2_stream_get_previous_sibling(nghttp2_stream *stream) {
  771. return stream->sib_prev;
  772. }
  773. nghttp2_stream *nghttp2_stream_get_first_child(nghttp2_stream *stream) {
  774. return stream->dep_next;
  775. }
  776. int32_t nghttp2_stream_get_weight(nghttp2_stream *stream) {
  777. return stream->weight;
  778. }
  779. int32_t nghttp2_stream_get_sum_dependency_weight(nghttp2_stream *stream) {
  780. return stream->sum_dep_weight;
  781. }
  782. int32_t nghttp2_stream_get_stream_id(nghttp2_stream *stream) {
  783. return stream->stream_id;
  784. }