Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve fake network write() efficiency #1178

Closed
wants to merge 28 commits into from

Conversation

chschnell
Copy link
Contributor

@chschnell chschnell commented Nov 4, 2024

Several improvements in fake network code that deal with data flowing towards the guest OS (i.e. package encoding and downstream buffering) and TCP state mechanics.

  • new: improved support for TCP connection state mechanics, implemented graceful shutdown, fixed FIN flag in generated TCP packet stream (context)
  • new: member eth_encoder_buf[] in classes FetchNetworkAdapter and WispNetworkAdapter, a buffer allocated once per adapter instance to encode single ethernet frames
  • new: class GrowableRingbuffer, designed to replace array TCPConnection.send_buffer[] with a growable ringbuffer
  • new: added internet checksum to synthesized UDP packets (required by mTCP) in function write_udp()
  • replaced internet checksum calculation with more efficient algorithm from RFC1071 (chapter 4.1)
  • increased TCP chunk size in TCPConnection.pump() from 500 to 1460 bytes (max. TCP payload size)
  • added function to efficiently copy an array into a DataView using TypedArray.set(), replaces a bunch of for-loops
  • added function to efficiently encode a string into a DataView using TextEncoder.encodeInto()
  • refactored all write_...()-functions to use encoder buffer
  • added several named constants for ethernet/ipv4/udp/tcp-related offsets
  • removed several apparently unused "return true" statements

- new: class EthernetPacketEncoder, replaces all dynamically allocated write-buffers with a single, static buffer
- new: class Uint8Stream, designed to replace TCPConnection.send_buffer[] with a dynamically growing ringbuffer
- new: added internet checksum to synthesized UDP packets (required by mTCP) in function write_udp()
- replaced internet checksum calculation with more efficient algorithm from RFC1071 (chapter 4.1)
- increased TCP chunk size in TCPConnection.pump() from 500 to 1460 bytes (max. TCP payload size)
- added function to efficiently copy an array into a DataView using TypedArray.set(), replaces a bunch of for-loops
- added function to efficiently encode a string into a DataView using TextEncoder.encodeInto()
- refactored all write_...()-functions to use EthernetPacketEncoder
- added several named constants for ethernet/ipv4/udp/tcp-related offsets
- removed several apparently unused "return true" statements
TCP FIN flag marks the sender's last package. This patch delays sending FIN in TCPConnection.close() until the send buffer is drained.
Copy link
Owner

@copy copy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Overall, this looks like a reasonable set of changes.

I've left some comments.

src/browser/fake_network.js Show resolved Hide resolved
src/browser/fake_network.js Outdated Show resolved Hide resolved
src/browser/fake_network.js Outdated Show resolved Hide resolved
src/browser/fake_network.js Outdated Show resolved Hide resolved
src/browser/fake_network.js Show resolved Hide resolved
src/browser/fake_network.js Outdated Show resolved Hide resolved
src/browser/fake_network.js Show resolved Hide resolved
- Renamed Uint8Stream to GrowableRingbuffer
- Minimum capacity now guaranteed to be 16, and maximum (if given) to be greater or equal to minumum
- Changed peek(dst_array, length) to peek(dst_array)
- Removed misleading method resize(), moved code into write()
- Now throws an Exception on capacity overflow error instead of console.error()
- Removed debug code that is no longer needed

When we have a capacity overflow the situation is as bad as if the Uint8Array constructor had failed with out-of-memory, which throws a RangeError.
- use actual dynamic TCP port range from RFC6335
- throw an Exception when pool of dynamic ports is exhausted
- removed class EthernetPacketEncoder and its global single instance ethernet_encoder
- moved encoder buffer ownership to adapter (WispNetworkAdapter and FetchNetworkAdapter)
- made view_{setArray,setString,setInetChecksum} global functions
- changed prototype of all write_...(spec, ...) functions to uniform write_...(spec, out)
- removed function make_packet(spec), added new function adapter_receive(adapter, spec)
- replaced all calls of form "A.receive(make_packet(S))" with "adapter_receive(A, S)" (also in WispNetworkAdapter)

Note that before this patch function make_packet() was always called in the form:

    adapter.receive(make_packet(spec));

This patch binds the lifetime and scope of the encoder buffer from class EthernetPacketEncoder to the WispNetworkAdapter/FetchNetworkAdapter instance "adapter".
- removed unnecessary comments around TCP_STATE_...
- renamed TCPConnection.send_stream to send_buffer
- calculate package length in write_udp() and write_tcp() along the same structure as in all other write_...() functions
src/browser/fake_network.js Outdated Show resolved Hide resolved
For the most part, this patch adds graceful TCP connection shutdown behaviour to class TCPConnection in fake_network.js.

Network-intense guest applications like "apt" run noticeably smoother with support for graceful TCP shutdown.

Changes in detail:

- completed SYN-related state mechanics (TCP connection establishment)
- added FIN-related state mechanics (TCP connection shutdown)
- reordered and regrouped TCP packet handling steps in TCPConnection.process()
- reduced minimum IPv4 packet size from 46 to 40 bytes to reduce noise in logs (why is this even checked)
- added explicit detection of TCP Keep-Alive packets to reduce noise in logs
- added dbg_log() calls to trace TCP connection state (could be removed if unwanted, or maybe use smth. like LOG_TCP instead of LOG_FETCH?)
- removed TCPConnection.seq_history as it was not used anywhere

As should be expected, the changes related to TCP connection state only affect class TCPConnection internally and are mostly concentrated in its methods process() and pump().

A few TCP connection states are left unimplemented, reasons:

- CLOSING: simultaneous close from both ends (deemed too unlikely)
- TIME_WAIT: wait seconds to minutes after sending final ACK before entering CLOSED state (pointless in our specific case and would require a Timer)
- LISTEN: are server sockets even supported? Both WISP and FETCH do not support them. Also, TCPConnection.connect() seems not to be called from anywhere (it used to be called from fake_tcp_connect() which was deleted in the previous patcH).

As before, fake_network.js does not use any Timers (i.e. setTimeout()), the code is purely driven by outside callers. That means that there are no checks for lost packets (or resends), the internal network is assumed to be ideal (as was the case before).

Even though I fixed and removed most of the TODOs I originally found in fake_network.js, I've added several new ones that are left to be discussed.

Tested with V86 network providers WispNetworkAdapter and FetchNetworkAdapter, and with V86 network devices ne2k (FreeDOS) and virtio (Debian 12 32-bit).
src/browser/fake_network.js Outdated Show resolved Hide resolved
src/browser/fake_network.js Show resolved Hide resolved
src/browser/fake_network.js Outdated Show resolved Hide resolved
src/browser/fake_network.js Outdated Show resolved Hide resolved
src/browser/fake_network.js Outdated Show resolved Hide resolved
src/browser/fake_network.js Outdated Show resolved Hide resolved
- removed orphaned function siptolong()
- refactored view_setInetChecksum() to calc_inet_checksum()
- renamed view_setString() into view_set_string() and simplified it
- renamed view_setArray() into view_set_array()
- refactored adapter_receive() to make_packet()
- bugfix: send FIN after receiving last ACK instead of tagging it to the last packet we send, fixes a corner case when TCPConnection.close() is called with empty send_buffer but with a yet to be acknowledged package in transit. Send a FIN packet in TCPConnection.close() only if both the send_buffer is empty and there is no package in transit, else delay that until we receive the last ACK.
@chschnell
Copy link
Contributor Author

I have a small idea for fetch-based networking that I would first like to check with you before committing.

Currently, the full HTTP response (header and body) from fetch() is cached before being forwarded to the originating HTTP client.

My proposal is to only wait for the HTTP response headers from fetch(), and then to forward the response body asynchronously chunk by chunk to the originating HTTP client using ReadableStream and HTTP Chunked transfer encoding.

To test this, I changed on_data_http() in fetch_network.js based on a ReadableStream usage pattern from MDN, it's pretty straight-forward and it works well with my tests (all HTTP applications support chunked Transfer-Encoding to my knowledge). This would also remove the need for FetchNetworkAdapter.fetch(), I merged its relevant code into on_data_http().

The upside is that this much, much increases both the responsiveness as well as the effective speed of fetch-based networking, all the more with increasing size of the HTTP response.

The downside is that the originating HTTP client never gets to see the Content-Length of the response it is receiving, thus it cannot show any meaningful progress statistics anymore other than about what it has received so far. Any Content-Length must be ignored if any Transfer-Encoding is used, and the Content-Length from the fetch response header can be incorrect (for example, for compressed response bodies). The only way around this seems to be the prefetching like it currently is. I might be wrong, but to my knowledge it's categorically either prefetching or the loss of Content-Length (for any request from the originating HTTP client). I wasn't aware of that until I had finished implementing it.

I would of course wait with this until #1182 is merged, and include any changes from there.

I'm really undecided which side outweighs the other here. What do you think, thumbs up or down?

@copy
Copy link
Owner

copy commented Nov 11, 2024

I'm really undecided which side outweighs the other here. What do you think, thumbs up or down?

Generally thumbs up, but I'm unsure about the downsides. I wonder if HTTP Chunked transfer encoding is necessary at all. Can't the data be streamed in separate ethernet packets?

and the Content-Length from the fetch response header can be incorrect (for example, for compressed response bodies).

I believe for compressed bodies (via Content-Encoding), Content-Length indicates the length of the compressed body. As far as I know, compression via Transfer-Encoding isn't really used or widely implemented.

@chschnell
Copy link
Contributor Author

chschnell commented Nov 12, 2024

EDIT: The gist of the matter is that I cannot determine whether Content-Length from the fetch() response headers is correct, so I cannot use it at all and I have no Content-Length to pass to the originating HTTP client. The only option I see at this point is to use chunked encoding.


If I could rely on Content-Length in the received fetch() response headers then I could just pass the unmodified chunks on to the originating client, passing the very same Content-Length to it.

I build and send the response headers to the originating client when I receive the first response body chunk, but I don't have a Content-Length to set in these response headers (well I do, but it is wrong when compression is used).

In fetch(), my browser negotiates gzip compression with my Apache server and transparently decompresses the response before passing me the decompressed chunks (and passes me the compressed size in Content-Length, which is useless). I never get to know how long the response is going to be myself.

I tried to suppress compression but Accept-Encoding is amongst the forbidden header names in fetch, so I can't set that header in the fetch request.

I wonder, is there any other method besides Chunked transfer encoding that I could use when I don't know the length of the response?

@copy
Copy link
Owner

copy commented Nov 12, 2024

In fetch(), my browser negotiates gzip compression with my Apache server and transparently decompresses the response before passing me the decompressed chunks (and passes me the compressed size in Content-Length, which is useless). I never get to know how long the response is going to be myself.

I see the problem now. fetch passes you already decompressed chunks, but Content-Length indicates the compressed size on the wire.

I wonder, is there any other method besides Chunked transfer encoding that I could use when I don't know the length of the response?

It seems to be legal to send an http reponse with neither Content-Length nor Transfer-Encoding: chunked, in which case the server closes the TCP connection after writing all data.

@chschnell
Copy link
Contributor Author

I wonder, is there any other method besides Chunked transfer encoding that I could use when I don't know the length of the response?

It seems to be legal to send an http reponse with neither Content-Length nor Transfer-Encoding: chunked, in which case the server closes the TCP connection after writing all data.

I actually do all this to learn and also try out new things, so thank you very much for this information!

It should fit in well since I'm already closing the HTTP connection to the originating client once the transaction is complete (current fetch-based networking can't do that because of the FIN packet that is sent too early).

@chschnell
Copy link
Contributor Author

chschnell commented Nov 12, 2024

It works without both Content-Length and chunked encoding! :)

Of course, the originating client still doesn't get to learn the Content-Length of the response body, so it cannot show any meaningfull download progress information besides the total bytes received so far.

@chschnell chschnell marked this pull request as ready for review November 16, 2024 16:59
@chschnell chschnell marked this pull request as draft November 17, 2024 15:44
See https://en.wikipedia.org/wiki/File:Tcp_state_diagram_fixed_new.svg for a full TCP state diagram, all states (except TIME_WAIT) and state transitions below ESTABLISHED are now properly implemented in class TCPConnection.

- fixed misconceptions regarding TCP close states and transitions
- fixed incorrect behaviour when guest closes a TCP connection
- added state CLOSING to state machine
- added support to pass passive close up to WispNetworkAdapter
- commented out all calls to dbg_log() that are part of this PR

This improves interoperability by further completing the TCP state machine model in fake_network.js.
@copy
Copy link
Owner

copy commented Nov 18, 2024

Looks good to merge to me (one more small comment above). @chschnell Any objections? (asking because it's still marked as a draft)

@chschnell
Copy link
Contributor Author

I've never heard of half close, okay I see, wisp doesn't support that. Does full closing still work? I thought that commit removed full closing and that's why I was concerned

close 0x02 closes the TCP stream entirely, no more receiving or transmitting can be done

Only WispServerCpp implements CLOSE/0x02 like that, neither epoxy-tls nor wisp-js do, in my observation. There was no CLOSE/0x02 in V86's WISP client before I added it a couple of days ago.

So in the case of WispServerCpp that commit did remove full closing, but in the case of the other two WISP servers it didn't change anything. I did that because none of them implemented half-close. Now it all comes down to a timeout by the server, or a leaked connection in case that never happens.

Maybe I should put the CLOSE/0x02 better back in, even though it will break certain applications and has no effect with some WISP servers.

@ProgrammerIn-wonderland
Copy link
Contributor

ProgrammerIn-wonderland commented Nov 21, 2024

Are you saying the other wisp servers don't support closing or don't support half closing? Sorry I think I'm misunderstanding

To my understanding every current wisp server does support full closing of streams from either direction (client and server can both report closed streams I believe)

Also close is 0x04, the reason is 0x02. Just wanted to clarify because I stated it incorrectly above in my own message

@r58Playz
Copy link

I've never heard of half close, okay I see, wisp doesn't support that. Does full closing still work? I thought that commit removed full closing and that's why I was concerned

close 0x02 closes the TCP stream entirely, no more receiving or transmitting can be done

Only WispServerCpp implements CLOSE/0x02 like that, neither epoxy-tls nor wisp-js do, in my observation. There was no CLOSE/0x02 in V86's WISP client before I added it a couple of days ago.

So in the case of WispServerCpp that commit did remove full closing, but in the case of the other two WISP servers it didn't change anything. I did that because none of them implemented half-close. Now it all comes down to a timeout by the server, or a leaked connection in case that never happens.

Maybe I should put the CLOSE/0x02 better back in, even though it will break certain applications and has no effect with some WISP servers.

@chschnell

The protocol does not specify any special behavior on the server side for specific close reasons. I don't know why WispServerCpp behaves differently here, but wisp-js and epoxy-server are following protocol and closing fully.
Wisp V1 reference Wisp V2 reference

Any CLOSE packets sent from either the server or the client must immediately close the associated stream and TCP socket. The close reason in the payload doesn't affect this behavior, but may provide extra information which is useful for debugging.

On epoxy, you can use RUST_LOG=trace to see that it does close streams (stream uuid f9f5dcdb-5edc-40d2-9ba7-b7686b6cfc19 disconnected for client id "127.0.0.1:46658"):

[2024-11-21T20:32:37Z TRACE epoxy_server] routed "127.0.0.1:46658": Wisp
[2024-11-21T20:32:37Z DEBUG epoxy_server::handle::wisp] new wisp client id "127.0.0.1:46658" connected with extensions [1], downgraded false
[2024-11-21T20:32:37Z TRACE epoxy_server::handle::wisp] sent ping to wisp client id "127.0.0.1:46658"
[2024-11-21T20:32:37Z TRACE epoxy_server::handle::wisp] sent ping to wisp client id "127.0.0.1:46658"
[2024-11-21T20:32:37Z DEBUG epoxy_server::handle::wisp] new stream created for client id "127.0.0.1:46658": (stream uuid f9f5dcdb-5edc-40d2-9ba7-b7686b6cfc19) ConnectPacket { stream_type: Tcp, destination_port: 8000, destination_hostname: "localhost" } ConnectPacket { stream_type: Tcp, destination_port: 8000, destination_hostname: "127.0.0.1" }
[2024-11-21T20:32:37Z DEBUG epoxy_server::handle::wisp] stream uuid f9f5dcdb-5edc-40d2-9ba7-b7686b6cfc19 disconnected for client id "127.0.0.1:46658"
[2024-11-21T20:33:07Z TRACE epoxy_server::handle::wisp] sent ping to wisp client id "127.0.0.1:46658"
[2024-11-21T20:33:37Z TRACE epoxy_server::handle::wisp] sent ping to wisp client id "127.0.0.1:46658"
[2024-11-21T20:33:59Z DEBUG epoxy_server::handle::wisp] wisp client id "127.0.0.1:46658" multiplexor result Ok(())
[2024-11-21T20:33:59Z DEBUG epoxy_server::handle::wisp] shutting down wisp client id "127.0.0.1:46658"
[2024-11-21T20:33:59Z TRACE epoxy_server::handle::wisp] waiting for tasks to close for wisp client id "127.0.0.1:46658"
[2024-11-21T20:33:59Z DEBUG epoxy_server::handle::wisp] wisp client id "127.0.0.1:46658" disconnected

@ProgrammerIn-wonderland
Copy link
Contributor

ProgrammerIn-wonderland commented Nov 21, 2024

Also wisp server Cpp sends a 0x04 Close packet back after the client sends one. It is the only server to do this, and it actually isn't in the spec. The client is supposed to assume the stream is closed immediately after sending the close packet.

Just wanted to note that on this GitHub thread

@r58Playz
Copy link

r58Playz commented Nov 21, 2024

Another note: WispServerCpp doesn't actually close any sockets that it forwards, violating spec, so the remote server never sees the close from the wisp client.
Edit: This can also result in sending packets to sockets that were closed according to the client, emulating half-closed behavior without actually closing anything.

- both methods must be overloaded by the network adapter, just like TCPConnection.on_data()
- on_shutdown() informs the network adapter that the client has closed its half of the connection (FIN)
- on_close() informs the network adapter that the client has fully closed the connection (RST)
- added call to on_shutdown() when we receive a TCP packet with active FIN flag from guest
- added call to on_close() when we receive a TCP packet with active RST flag from guest
- added calls to on_close() when we have to tear down the connection in fake_network.js
- added implementation of on_shutdown() and on_close() in wisp_network.js

The default implementation of these methods is to do nothing.

These methods do not apply to fetch-based networking, fetch() only supports HTTP and it doesn't matter if the client closes its end of the connection after it has sent its HTTP request. Hence FetchNetworkAdapter does not override these methods.

Note that WISP currently only supports close(), as a workaround shutdown() is implemented like close() which might be incorrect (missing support for half-closed TCP connections).
@ProgrammerIn-wonderland
Copy link
Contributor

I think it's worth looking into making a protocol extension for half closing, @ading2210 @r58Playz

@chschnell
Copy link
Contributor Author

@ProgrammerIn-wonderland

Are you saying the other wisp servers don't support closing or don't support half closing? Sorry I think I'm misunderstanding

Sorry about the confusion. I meant to say the other WISP servers don't support closing, but it turned out I was wrong about that.

Also close is 0x04, the reason is 0x02. Just wanted to clarify because I stated it incorrectly above in my own message

Understood. By 0x02 I always meant reason 0x02 (Voluntary stream closure).

@r58Playz

On epoxy, you can use RUST_LOG=trace to see that it does close streams (stream uuid f9f5dcdb-5edc-40d2-9ba7-b7686b6cfc19 disconnected for client id "127.0.0.1:46658")

Thanks, I enabled tracing and indeed, I see the same message. Sorry about my confusion, I was wrong when I said it wasn't supported by epoxy-tls/wisp-js, they indeed do.

@chschnell
Copy link
Contributor Author

My latest commit is a slight change in strategy with this close issue.

I now distingush between on_shutdown() (FIN) and on_close() (RST), this is the right way to model it in fake_network.js.

I implemented both on_shutdown() and on_close() for WISP using a CLOSE frame with reason 0x02. This does not implement half-closed TCP connections (currently not supported), but this also doesn't leak idle TCP connections.

It would be trivial to change on_shutdown() in case WISP support changes in the future.

@ProgrammerIn-wonderland
Copy link
Contributor

Thanks! This does make retrofitting it migh easier if the server advertises support for TCP half closing.

…apter.send()

- in both functions, all the scattered "if" statements are mutually exclusive
- changed control flow to mutual exclusive cases
- removed boolean return values in handle_fake_networking(), they were never checked by the caller
- added missing callback WispNetworkAdapter.on_tcp_connection(packet, tuple),
  moved all relevant code from WispNetworkAdapter.send(data) to new method,
  replaced with call to handle_fake_tcp() (now identical to FetchNetworkAdapter)
- removed redundant first argument of adapter.on_tcp_connection(adapter, ...)
- added TCP_STATE_SYN_RECEIVED -> TCP_STATE_ESTABLISHED state transition back in (just to be sure)

The larger goal is to replace all code in WispNetworkAdapter.send(data) with a call to handle_fake_networking(), just like in FetchNetworkAdapter. The only difference left is two alternate fake DNS implementations.
@chschnell
Copy link
Contributor Author

Currently there are two different fake DNS methods in V86:

  1. in fake_network.js: offline, static implementation that returns 192.168.87.1 for any given DNS name
  2. in wisp_network.js: uses fetch() and DoH (DNS over HTTPS), DoH server defaults to cloudflare-dns.com unless specified in config.doh_server

Fetch-based networking uses the first method, wisp-based the second, and I'm not sure why.

Faking DNS with DoH works just fine for both fetch- and wisp-based networking, and it returns real results.

So I would like to move the DoH-code from wisp_network.js into handle_fake_dns() (fake_network.js) and make it the default fake DNS method.

Question: Is the first method without DoH still needed or can it be removed? I think it is not needed, only fetch-based networking uses it, and with fetch() this DNS method doesn't really matter (the browser performs the DNS lookup for the URL passed to fetch()).

In case I should keep the first method I would suggest to add a new option config.dns_method next to config.doh_server with possible values static and doh (default doh), unless someone has a better idea.

@SuperMaxusa
Copy link
Contributor

Question: Is the first method without DoH still needed or can it be removed? I think it is not needed, only fetch-based networking uses it, and with fetch() this DNS method doesn't really matter (the browser performs the DNS lookup for the URL passed to fetch()).

For fetch-based networking, there is not much need for it: #1061 (comment), and fetch with IP address works buggy, especially if HTTPS-only mode is enabled in browser.

@ProgrammerIn-wonderland
Copy link
Contributor

Fetch networking uses the Host: header so the IP address given is irrelevant, to save time it just returns a dummy IP.

Since wisp actually connects to the IP it has to do the real resolution

@ProgrammerIn-wonderland
Copy link
Contributor

Sorry just saw your command supermaxusa, my Internet is glitching

@ProgrammerIn-wonderland
Copy link
Contributor

I don't think it makes much sense to add Doh to fetch personally since it's not really necessary based on how it operates (unless you're running a SUPER OLD pre Host header http client). But I do think the Doh server should be configurable

- added member "dns_method" to both FetchNetworkAdapter (value "static") and WispNetworkAdapter (value "doh")
- moved the DoH-code from WispNetworkAdapter.send() into new function handle_fake_dns_doh() in fake_network.js
- renamed function handle_fake_dns() into handle_fake_dns_static()
- recreated function handle_fake_dns() that now calls either of the two depending on the value of adapter.dns_method
@chschnell
Copy link
Contributor Author

@SuperMaxusa @ProgrammerIn-wonderland

Thanks a lot for your input!

We all agree that DoH doesn't make much sense with fetch-based networking, my point was that it also doesn't hurt because it matters so little. But it's fine, I'll leave it at that.

In my latest commit I moved the DoH-code from WispNetworkAdapter.send() into new function handle_fake_dns_doh() in fake_network.js, and only WispNetworkAdapter uses DoH, just as before. So it's only a refactoring, the code behaves unchanged. Everything is in place in case someone wants to add a config option for this, I don't see the point.

The benefit of all this is that all of the code in WispNetworkAdapter.send() that was duplicated from fake_network.js is now gone which somewhat simplifies reasoning about the fake networking control flow (it made me scratch my head quite a little).

@copy
Copy link
Owner

copy commented Nov 25, 2024

Thanks! This looks good to merge to me now. Let me know if there's another change you'd like to get in. I will try to rebase (to get rid of the merge commits).

@chschnell
Copy link
Contributor Author

Thanks! This looks good to merge to me now. Let me know if there's another change you'd like to get in. I will try to rebase (to get rid of the merge commits).

Yes, let's merge it.

I see two things left to do, but I want to split them off into a new PR in a couple of weeks.

  1. replace the bus with direct function calls
  2. further improve buffering, for example to encode ethernet packets at the latest possible stage, or to use GrowableRingbuffer in other places

I will do other things in the next week or two, but I think then I'll take another go at this, if you don't mind.

@basicer
Copy link
Contributor

basicer commented Nov 26, 2024

Great work! A huge improvement over my hacked up proof of concept.

@chschnell
Copy link
Contributor Author

Great work! A huge improvement over my hacked up proof of concept.

My pleasure! And it was just a bit rough around the edges, the core was rock-solid.

@copy
Copy link
Owner

copy commented Nov 26, 2024

Merged manually, thanks all!

@copy copy closed this Nov 26, 2024
@chschnell chschnell deleted the fake-network-refactor branch November 26, 2024 17:06
@chschnell
Copy link
Contributor Author

@copy I am very sorry but I just noticed that I broke the cors_proxy function in FetchNetworkAdapter. Only a single line needs to be fixed in fetch_network.js, is a quick PR ok?

@copy
Copy link
Owner

copy commented Nov 26, 2024

@chschnell Sure

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants