@@ -14,6 +14,7 @@ namespace {
1414using namespace proxygen ::coro;
1515using folly::coro::co_error;
1616using folly::coro::co_nothrow;
17+ constexpr uint64_t kMaxWriteSize = 65'535 ;
1718
1819BufQueue* asBodyEv (HTTPBodyEvent& event) {
1920 return event.eventType == HTTPBodyEvent::BODY ? &event.event .body : nullptr ;
@@ -27,10 +28,12 @@ CoroWtSession::CoroWtSession(
2728 folly::EventBase* evb,
2829 WtDir dir,
2930 WtStreamManager::WtConfig wtConfig,
30- std::unique_ptr<WebTransportHandler> handler) noexcept
31+ std::unique_ptr<WebTransportHandler> handler,
32+ std::unique_ptr<folly::coro::TransportIf> transport) noexcept
3133 : CoroWtSessionBase(dir, wtConfig),
3234 WtSessionBase (evb, sm),
33- wtHandler_(std::move(handler)) {
35+ wtHandler_(std::move(handler)),
36+ transport_(std::move(transport)) {
3437}
3538
3639CoroWtSession::~CoroWtSession () noexcept {
@@ -46,21 +49,26 @@ WtExpected<folly::Unit>::Type CoroWtSession::closeSession(
4649}
4750
4851using WtCapsuleCallback = proxygen::detail::WtCapsuleCallback;
49- folly::coro::Task<void > CoroWtSession::readLoop (Ptr self,
50- HTTPSourceHolder ingress) {
51- WtCapsuleCallback wtCapsuleCallback{sm, *this };
52+ folly::coro::Task<void > CoroWtSession::readLoop (Ptr self) {
53+ WtCapsuleCallback wtCapsuleCallback{sm, *self};
5254 WebTransportCapsuleCodec codec{&wtCapsuleCallback, CodecVersion::H2 };
53-
54- while (!sm.isClosed () && ingress.readable ()) {
55- auto maybeEv = co_await co_awaitTry (ingress.readBodyEvent ());
56- if (maybeEv.hasException () ||
57- maybeEv->eventType != HTTPBodyEvent::BODY ) { // skip non-body events
58- XLOG_IF (DBG4 , maybeEv.hasException ())
59- << " ::readLoop ingress ex=" << maybeEv.exception ().what ();
60- continue ;
55+ folly::IOBufQueue ingressBuf{folly::IOBufQueue::cacheChainLength ()};
56+
57+ while (!sm.isClosed ()) {
58+ auto readRes = co_await co_awaitTry (transport_->read (
59+ ingressBuf,
60+ /* minReadSize=*/ 1460 ,
61+ /* newAllocationSize=*/ 4000 ,
62+ /* timeout=*/ std::chrono::milliseconds (0 ))); // TODO: timeout should be
63+ // changed from 0ms
64+ if (readRes.hasException ()) {
65+ XLOG (DBG4 ) << __func__ << " ; ex=" << readRes.exception ();
66+ break ;
6167 }
62- auto & event = maybeEv.value ();
63- codec.onIngress (event.event .body .move (), event.eom );
68+
69+ const bool eom = (*readRes == 0 );
70+ codec.onIngress (ingressBuf.move (), eom);
71+
6472 // handle any new peer streams
6573 auto peerIds = std::move (wtSmIngressCb.peerStreams );
6674 for (auto id : peerIds) {
@@ -72,96 +80,71 @@ folly::coro::Task<void> CoroWtSession::readLoop(Ptr self,
7280 }
7381 }
7482
75- if (event. eom ) {
83+ if (eom) {
7684 break ;
7785 }
7886 }
7987 XLOG (DBG4 ) << " CoroWtSession::readLoop exiting" ;
80- // http/2 rst, eom or WtStreamManager closed – in either case invoke
81- // ::shutdown to exit write loop
8288 sm.shutdown (WtStreamManager::CloseSession{.err = 0x00 ,
83- .msg = " h2 stream ingress closed" });
89+ .msg = " stream ingress closed" });
8490 readLoopFinished ();
8591}
8692
87- folly::coro::Task<void > CoroWtSession::writeLoop (Ptr self,
88- EgressSourcePtr egress) {
89- const auto timeout = egress->getReadTimeout ();
90- const folly::IOBuf empty;
93+ folly::coro::Task<void > CoroWtSession::writeLoop (Ptr self) {
9194 folly::IOBufQueue egressBuf{folly::IOBufQueue::cacheChainLength ()};
9295 proxygen::detail::WtEventVisitor eventVisitor{.egress = egressBuf};
93- detail::EgressBackPressure streamSourceCallback;
94- egress->setCallback (&streamSourceCallback);
9596 auto & waitForEventBaton = wtSmEgressCb.waitForEvent ;
9697
9798 while (!eventVisitor.sessionClosed ) {
98- // wait for WtSession egress (i.e. underlying http/2 egress buffer space);
99- // this is upperbounded by writeTimeout in HTTPBodyEventQueue
100- XLOG (DBG6 ) << " waiting for http/2 egress fc" ;
101- co_await streamSourceCallback.waitForEgress .wait ();
102-
103- // wait for underlying wt ctrl events or writable streams
99+ // wait for WtStreamManager control events or writable streams
104100 XLOG (DBG6 ) << " waiting for WtStreamManager event" ;
105- auto res = co_await waitForEventBaton.timedWait (evb (), timeout);
106- if (res == TimedBaton::Status::timedout) {
107- sm.shutdown (WtStreamManager::CloseSession{.err = 0x00 ,
108- .msg = " wt write timed out" });
109- } // fallthru to writing close_session below
101+ co_await waitForEventBaton.wait ();
110102 waitForEventBaton.reset ();
111103
112104 XLOG (DBG6 ) << " received WtStreamManager event" ;
113- // always write control frames first (not subject to flow control)
105+ // always write control frames first
114106 auto ctrl = sm.moveEvents ();
115107 for (auto & ev : ctrl) {
116108 std::visit (eventVisitor, ev);
117109 }
118- egress->body (egressBuf.move (), /* padding=*/ 0 , /* eom=*/ false );
119110
120- // write stream data
121111 auto * wh = sm.nextWritable ();
122- while (wh) {
123- auto bytesAvailable = egress->window ().getNonNegativeSize ();
124- XLOG (DBG4 ) << __func__ << " ; id=" << wh->getID () << " ; wh=" << wh
125- << " ; bytesAvailable=" << bytesAvailable;
126- if (bytesAvailable == 0 ) {
127- XLOG (DBG5 ) << __func__ << " egress blocked" ;
128- streamSourceCallback.waitForEgress .reset (); // block on next loop
129- break ;
130- }
112+ while (wh && egressBuf.chainLength () < kMaxWriteSize ) {
131113 auto id = wh->getID ();
132- auto dequeue = sm.dequeue (*wh, /* atMost=*/ bytesAvailable);
114+ const auto atMost = kMaxWriteSize - egressBuf.chainLength ();
115+ auto dequeue = sm.dequeue (*wh, /* atMost=*/ atMost);
133116 writeWTStream (egressBuf,
134117 WTStreamCapsule{.streamId = id,
135118 .streamData = std::move (dequeue.data ),
136119 .fin = dequeue.fin });
137- // ::body overflow checked in next iteration
138- egress->body (egressBuf.move (), /* padding=*/ 0 , /* eom=*/ false );
139120 wh = sm.nextWritable ();
140121 }
122+ if (wh) {
123+ waitForEventBaton.signal (); // re-signal for remaining streams
124+ }
141125
142- if (wh) { // if there's more pending data to be written, signal baton
143- waitForEventBaton.signal ();
126+ if (!egressBuf.empty ()) {
127+ auto writeRes = co_await co_awaitTry (
128+ transport_->write (egressBuf)); // TODO: plumb writeTimeout here
129+ if (writeRes.hasException ()) {
130+ XLOG (DBG4 ) << __func__ << " ; ex=" << writeRes.exception ();
131+ break ;
132+ }
144133 }
145134 }
146135
147136 XLOG (DBG4 ) << " CoroWtSession::writeLoop exiting" ;
148- egress-> eom ();
137+ transport_-> shutdownWrite ();
149138 writeLoopFinished ();
150139 co_return ;
151140}
152141
153- void CoroWtSession::start (CoroWtSession::Ptr self,
154- HTTPSourceHolder&& ingress,
155- EgressSourcePtr&& egress) {
142+ void CoroWtSession::start (CoroWtSession::Ptr self) {
156143 wtHandler_->onWebTransportSession (self);
157144 auto ct = cs_.getToken ();
158145 auto * eventBase = evb ();
159- co_withExecutor (eventBase,
160- co_withCancellation (ct, readLoop (self, std::move (ingress))))
161- .start ();
162- co_withExecutor (eventBase,
163- co_withCancellation (ct, writeLoop (self, std::move (egress))))
164- .start ();
146+ co_withExecutor (eventBase, co_withCancellation (ct, readLoop (self))).start ();
147+ co_withExecutor (eventBase, co_withCancellation (ct, writeLoop (self))).start ();
165148}
166149
167150void CoroWtSession::writeLoopFinished () noexcept {
0 commit comments