nghttp2_stream.c 26 KB

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