diff --git a/src/fruity/device-monitor.vala b/src/fruity/device-monitor.vala index 51acbd6a0..8d16955c2 100644 --- a/src/fruity/device-monitor.vala +++ b/src/fruity/device-monitor.vala @@ -1624,7 +1624,7 @@ namespace Frida.Fruity { public async void close (Cancellable? cancellable) throws IOError { _discovery_service.close (); - tunnel_connection.cancel (); + yield tunnel_connection.cancel (cancellable); if (ncm != null) ncm.close (); @@ -1805,7 +1805,7 @@ namespace Frida.Fruity { public async void close (Cancellable? cancellable) throws IOError { _discovery_service.close (); - tunnel_connection.cancel (); + yield tunnel_connection.cancel (cancellable); } public async IOStream open_tcp_connection (uint16 port, Cancellable? cancellable) throws Error, IOError { diff --git a/src/fruity/xpc.vala b/src/fruity/xpc.vala index d28066701..ec0f7ac4c 100644 --- a/src/fruity/xpc.vala +++ b/src/fruity/xpc.vala @@ -1789,7 +1789,7 @@ namespace Frida.Fruity { get; } - public abstract void cancel (); + public abstract async void cancel (Cancellable? cancellable) throws IOError; protected static Bytes make_handshake_request (size_t mtu) { string body = Json.to_string ( @@ -1888,6 +1888,8 @@ namespace Frida.Fruity { } } + private Promise cancelled = new Promise (); + private TunnelParameters tunnel_params; private VirtualNetworkStack _tunnel_netstack; @@ -1926,12 +1928,6 @@ namespace Frida.Fruity { ); } - public override void dispose () { - cancel (); - - base.dispose (); - } - private async bool init_async (int io_priority, Cancellable? cancellable) throws Error, IOError { var stream = yield netstack.open_tcp_connection (address, cancellable); @@ -1975,9 +1971,15 @@ namespace Frida.Fruity { return true; } - public void cancel () { + public async void cancel (Cancellable? cancellable) throws IOError { io_cancellable.cancel (); + try { + yield cancelled.future.wait_async (cancellable); + } catch (Error e) { + assert_not_reached (); + } + if (_tunnel_netstack != null) _tunnel_netstack.stop (); } @@ -1992,6 +1994,18 @@ namespace Frida.Fruity { } catch (GLib.Error e) { } + var source = new IdleSource (); + source.set_callback (process_incoming_messages.callback); + source.attach (MainContext.get_thread_default ()); + yield; + + try { + yield connection.close_async (); + } catch (IOError e) { + } + + cancelled.resolve (true); + close (); } @@ -2155,6 +2169,7 @@ namespace Frida.Fruity { } private Promise established = new Promise (); + private Promise cancelled = new Promise (); private Stream? control_stream; private TunnelParameters tunnel_params; @@ -2240,7 +2255,7 @@ namespace Frida.Fruity { } public override void dispose () { - cancel (); + perform_teardown (); base.dispose (); } @@ -2340,7 +2355,30 @@ namespace Frida.Fruity { established.resolve (true); } - public void cancel () { + public async void cancel (Cancellable? cancellable) throws IOError { + if (connection == null) + return; + + if (streams.is_empty) { + perform_teardown (); + return; + } + + foreach (int64 id in streams.keys) + connection.shutdown_stream (0, id, 0); + process_pending_writes (); + + try { + yield cancelled.future.wait_async (cancellable); + } catch (Error e) { + assert_not_reached (); + } + } + + private void perform_teardown () { + if (cancelled.future.ready) + return; + if (connection != null) close (); connection = null; @@ -2365,6 +2403,8 @@ namespace Frida.Fruity { if (_tunnel_netstack != null) _tunnel_netstack.stop (); + + cancelled.resolve (true); } private void on_stream_data_available (Stream stream, uint8[] data, out size_t consumed) { @@ -2425,7 +2465,9 @@ namespace Frida.Fruity { unowned uint8[] data = rx_buf[:n]; - connection.read_packet (path, null, data, make_timestamp ()); + var res = connection.read_packet (path, null, data, make_timestamp ()); + if (res == NGTcp2.ErrorCode.DRAINING) + perform_teardown (); } catch (GLib.Error e) { return Source.REMOVE; } finally { @@ -2528,7 +2570,7 @@ namespace Frida.Fruity { private bool on_expiry () { int res = connection.handle_expiry (make_timestamp ()); if (res != 0) { - cancel (); + perform_teardown (); return Source.REMOVE; } @@ -2567,7 +2609,7 @@ namespace Frida.Fruity { uint64.FORMAT_MODIFIER + "u", app_error_code)); } - cancel (); + perform_teardown (); return 0; } diff --git a/vapi/libngtcp2.vapi b/vapi/libngtcp2.vapi index c28c0440e..8fb8a3323 100644 --- a/vapi/libngtcp2.vapi +++ b/vapi/libngtcp2.vapi @@ -19,6 +19,7 @@ namespace NGTcp2 { public int read_packet (Path path, PacketInfo * pi, uint8[] pkt, Timestamp ts); public int open_bidi_stream (out int64 stream_id, void * stream_user_data); + public int shutdown_stream (uint32 flags, int64 stream_id, uint64 app_error_code); public ssize_t write_stream (Path * path, PacketInfo * pi, uint8[] dest, ssize_t * pdatalen, WriteStreamFlags flags, int64 stream_id, uint8[]? data, Timestamp ts);