mojo/discovery: change Stop() to return error

  Change Stop() API to return error if the handle is not valid.
  This is also helpful to wait until stop() operation actually finishes.

Change-Id: I3293b7e8ad6b32085d61513178b72b0719971465
diff --git a/go/src/mojom/vanadium/discovery/discovery.mojom.go b/go/src/mojom/vanadium/discovery/discovery.mojom.go
index 61c835d..71a3fa4 100644
--- a/go/src/mojom/vanadium/discovery/discovery.mojom.go
+++ b/go/src/mojom/vanadium/discovery/discovery.mojom.go
@@ -54,6 +54,10 @@
 		Value: discovery_Advertiser_Stop_Params__(),
 	}
 
+	discoveryDesc__["discovery_Advertiser_Stop_ResponseParams__"] = &mojom_types.UserDefinedTypeStructType{
+		Value: discovery_Advertiser_Stop_ResponseParams__(),
+	}
+
 	discoveryDesc__["discovery_Scanner__"] = &mojom_types.UserDefinedTypeInterfaceType{
 		Value: discovery_Scanner__(),
 	}
@@ -80,6 +84,10 @@
 		Value: discovery_Scanner_Stop_Params__(),
 	}
 
+	discoveryDesc__["discovery_Scanner_Stop_ResponseParams__"] = &mojom_types.UserDefinedTypeStructType{
+		Value: discovery_Scanner_Stop_ResponseParams__(),
+	}
+
 }
 func GetAllMojomTypeDefinitions() map[string]mojom_types.UserDefinedType {
 	return discoveryDesc__
@@ -87,7 +95,7 @@
 
 type Advertiser interface {
 	Advertise(inService Service, inVisibility *[]string) (outHandle uint32, outInstanceId string, outErr *Error, err error)
-	Stop(inH uint32) (err error)
+	Stop(inH uint32) (outErr *Error, err error)
 }
 
 var advertiser_Name = "discovery::Advertiser"
@@ -541,13 +549,101 @@
 	}
 }
 
-func (p *Advertiser_Proxy) Stop(inH uint32) (err error) {
+type advertiser_Stop_ResponseParams struct {
+	outErr *Error
+}
+
+func (s *advertiser_Stop_ResponseParams) Encode(encoder *bindings.Encoder) error {
+	encoder.StartStruct(8, 0)
+	if s.outErr == nil {
+		encoder.WriteNullPointer()
+	} else {
+		if err := encoder.WritePointer(); err != nil {
+			return err
+		}
+		if err := (*s.outErr).Encode(encoder); err != nil {
+			return err
+		}
+	}
+	if err := encoder.Finish(); err != nil {
+		return err
+	}
+	return nil
+}
+
+var advertiser_Stop_ResponseParams_Versions []bindings.DataHeader = []bindings.DataHeader{
+	bindings.DataHeader{16, 0},
+}
+
+func (s *advertiser_Stop_ResponseParams) Decode(decoder *bindings.Decoder) error {
+	header, err := decoder.StartStruct()
+	if err != nil {
+		return err
+	}
+	index := sort.Search(len(advertiser_Stop_ResponseParams_Versions), func(i int) bool {
+		return advertiser_Stop_ResponseParams_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+	})
+	if index < len(advertiser_Stop_ResponseParams_Versions) {
+		if advertiser_Stop_ResponseParams_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+			index--
+		}
+		expectedSize := advertiser_Stop_ResponseParams_Versions[index].Size
+		if expectedSize != header.Size {
+			return &bindings.ValidationError{bindings.UnexpectedStructHeader,
+				fmt.Sprintf("invalid struct header size: should be %d, but was %d", expectedSize, header.Size),
+			}
+		}
+	}
+	if header.ElementsOrVersion >= 0 {
+		pointer0, err := decoder.ReadPointer()
+		if err != nil {
+			return err
+		}
+		if pointer0 == 0 {
+			s.outErr = nil
+		} else {
+			s.outErr = new(Error)
+			if err := (*s.outErr).Decode(decoder); err != nil {
+				return err
+			}
+		}
+	}
+	if err := decoder.Finish(); err != nil {
+		return err
+	}
+	return nil
+}
+
+// String names and labels used by the MojomStruct types.
+var (
+	structName_AdvertiserStopResponseParams             = "AdvertiserStopResponseParams"
+	structFieldName_AdvertiserStopResponseParams_OutErr = "OutErr"
+)
+
+func discovery_Advertiser_Stop_ResponseParams__() mojom_types.MojomStruct {
+	return mojom_types.MojomStruct{
+		DeclData: &mojom_types.DeclarationData{
+			ShortName: &structName_AdvertiserStopResponseParams,
+		}, Fields: []mojom_types.StructField{mojom_types.StructField{
+			DeclData: &mojom_types.DeclarationData{
+				ShortName: &structFieldName_AdvertiserStopResponseParams_OutErr,
+			},
+			Type: &mojom_types.TypeTypeReference{
+				Value: mojom_types.TypeReference{Nullable: true, Identifier: &ID_discovery_Error__,
+					TypeKey: &ID_discovery_Error__},
+			},
+		}},
+	}
+}
+
+func (p *Advertiser_Proxy) Stop(inH uint32) (outErr *Error, err error) {
 	payload := &advertiser_Stop_Params{
 		inH,
 	}
 	header := bindings.MessageHeader{
-		Type:  advertiser_Stop_Name,
-		Flags: bindings.MessageNoFlag,
+		Type:      advertiser_Stop_Name,
+		Flags:     bindings.MessageExpectsResponseFlag,
+		RequestId: p.ids.Count(),
 	}
 	var message *bindings.Message
 	if message, err = bindings.EncodeMessage(header, payload); err != nil {
@@ -555,10 +651,29 @@
 		p.Close_Proxy()
 		return
 	}
-	if err = p.router.Accept(message); err != nil {
+	readResult := <-p.router.AcceptWithResponse(message)
+	if err = readResult.Error; err != nil {
 		p.Close_Proxy()
 		return
 	}
+	if readResult.Message.Header.Flags != bindings.MessageIsResponseFlag {
+		err = &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+			fmt.Sprintf("invalid message header flag: %v", readResult.Message.Header.Flags),
+		}
+		return
+	}
+	if got, want := readResult.Message.Header.Type, advertiser_Stop_Name; got != want {
+		err = &bindings.ValidationError{bindings.MessageHeaderUnknownMethod,
+			fmt.Sprintf("invalid method in response: expected %v, got %v", want, got),
+		}
+		return
+	}
+	var response advertiser_Stop_ResponseParams
+	if err = readResult.Message.DecodePayload(&response); err != nil {
+		p.Close_Proxy()
+		return
+	}
+	outErr = response.outErr
 	return
 }
 
@@ -583,6 +698,8 @@
 	_ = responseParamsMap // To avoid the declared but unused compiler error
 	mstruct_Advertise := discovery_Advertiser_Advertise_ResponseParams__()
 	responseParamsMap[interfaceMethodName_Advertiser_Advertise] = &mstruct_Advertise
+	mstruct_Stop := discovery_Advertiser_Stop_ResponseParams__()
+	responseParamsMap[interfaceMethodName_Advertiser_Stop] = &mstruct_Stop
 	return mojom_types.MojomInterface{
 		DeclData: &mojom_types.DeclarationData{
 			ShortName: &interfaceName_Advertiser,
@@ -655,7 +772,7 @@
 		}
 		return s.connector.WriteMessage(message)
 	case advertiser_Stop_Name:
-		if message.Header.Flags != bindings.MessageNoFlag {
+		if message.Header.Flags != bindings.MessageExpectsResponseFlag {
 			return &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
 				fmt.Sprintf("invalid message header flag: %v", message.Header.Flags),
 			}
@@ -664,10 +781,21 @@
 		if err := message.DecodePayload(&request); err != nil {
 			return err
 		}
-		err = s.impl.Stop(request.inH)
+		var response advertiser_Stop_ResponseParams
+		response.outErr, err = s.impl.Stop(request.inH)
 		if err != nil {
 			return
 		}
+		header := bindings.MessageHeader{
+			Type:      advertiser_Stop_Name,
+			Flags:     bindings.MessageIsResponseFlag,
+			RequestId: message.Header.RequestId,
+		}
+		message, err = bindings.EncodeMessage(header, &response)
+		if err != nil {
+			return err
+		}
+		return s.connector.WriteMessage(message)
 	default:
 		return &bindings.ValidationError{
 			bindings.MessageHeaderUnknownMethod,
@@ -679,7 +807,7 @@
 
 type Scanner interface {
 	Scan(inQuery string, inScanHandler ScanHandler_Pointer) (outHandle uint32, outErr *Error, err error)
-	Stop(inH uint32) (err error)
+	Stop(inH uint32) (outErr *Error, err error)
 }
 
 var scanner_Name = "discovery::Scanner"
@@ -1066,13 +1194,101 @@
 	}
 }
 
-func (p *Scanner_Proxy) Stop(inH uint32) (err error) {
+type scanner_Stop_ResponseParams struct {
+	outErr *Error
+}
+
+func (s *scanner_Stop_ResponseParams) Encode(encoder *bindings.Encoder) error {
+	encoder.StartStruct(8, 0)
+	if s.outErr == nil {
+		encoder.WriteNullPointer()
+	} else {
+		if err := encoder.WritePointer(); err != nil {
+			return err
+		}
+		if err := (*s.outErr).Encode(encoder); err != nil {
+			return err
+		}
+	}
+	if err := encoder.Finish(); err != nil {
+		return err
+	}
+	return nil
+}
+
+var scanner_Stop_ResponseParams_Versions []bindings.DataHeader = []bindings.DataHeader{
+	bindings.DataHeader{16, 0},
+}
+
+func (s *scanner_Stop_ResponseParams) Decode(decoder *bindings.Decoder) error {
+	header, err := decoder.StartStruct()
+	if err != nil {
+		return err
+	}
+	index := sort.Search(len(scanner_Stop_ResponseParams_Versions), func(i int) bool {
+		return scanner_Stop_ResponseParams_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+	})
+	if index < len(scanner_Stop_ResponseParams_Versions) {
+		if scanner_Stop_ResponseParams_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+			index--
+		}
+		expectedSize := scanner_Stop_ResponseParams_Versions[index].Size
+		if expectedSize != header.Size {
+			return &bindings.ValidationError{bindings.UnexpectedStructHeader,
+				fmt.Sprintf("invalid struct header size: should be %d, but was %d", expectedSize, header.Size),
+			}
+		}
+	}
+	if header.ElementsOrVersion >= 0 {
+		pointer0, err := decoder.ReadPointer()
+		if err != nil {
+			return err
+		}
+		if pointer0 == 0 {
+			s.outErr = nil
+		} else {
+			s.outErr = new(Error)
+			if err := (*s.outErr).Decode(decoder); err != nil {
+				return err
+			}
+		}
+	}
+	if err := decoder.Finish(); err != nil {
+		return err
+	}
+	return nil
+}
+
+// String names and labels used by the MojomStruct types.
+var (
+	structName_ScannerStopResponseParams             = "ScannerStopResponseParams"
+	structFieldName_ScannerStopResponseParams_OutErr = "OutErr"
+)
+
+func discovery_Scanner_Stop_ResponseParams__() mojom_types.MojomStruct {
+	return mojom_types.MojomStruct{
+		DeclData: &mojom_types.DeclarationData{
+			ShortName: &structName_ScannerStopResponseParams,
+		}, Fields: []mojom_types.StructField{mojom_types.StructField{
+			DeclData: &mojom_types.DeclarationData{
+				ShortName: &structFieldName_ScannerStopResponseParams_OutErr,
+			},
+			Type: &mojom_types.TypeTypeReference{
+				Value: mojom_types.TypeReference{Nullable: true, Identifier: &ID_discovery_Error__,
+					TypeKey: &ID_discovery_Error__},
+			},
+		}},
+	}
+}
+
+func (p *Scanner_Proxy) Stop(inH uint32) (outErr *Error, err error) {
 	payload := &scanner_Stop_Params{
 		inH,
 	}
 	header := bindings.MessageHeader{
-		Type:  scanner_Stop_Name,
-		Flags: bindings.MessageNoFlag,
+		Type:      scanner_Stop_Name,
+		Flags:     bindings.MessageExpectsResponseFlag,
+		RequestId: p.ids.Count(),
 	}
 	var message *bindings.Message
 	if message, err = bindings.EncodeMessage(header, payload); err != nil {
@@ -1080,10 +1296,29 @@
 		p.Close_Proxy()
 		return
 	}
-	if err = p.router.Accept(message); err != nil {
+	readResult := <-p.router.AcceptWithResponse(message)
+	if err = readResult.Error; err != nil {
 		p.Close_Proxy()
 		return
 	}
+	if readResult.Message.Header.Flags != bindings.MessageIsResponseFlag {
+		err = &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+			fmt.Sprintf("invalid message header flag: %v", readResult.Message.Header.Flags),
+		}
+		return
+	}
+	if got, want := readResult.Message.Header.Type, scanner_Stop_Name; got != want {
+		err = &bindings.ValidationError{bindings.MessageHeaderUnknownMethod,
+			fmt.Sprintf("invalid method in response: expected %v, got %v", want, got),
+		}
+		return
+	}
+	var response scanner_Stop_ResponseParams
+	if err = readResult.Message.DecodePayload(&response); err != nil {
+		p.Close_Proxy()
+		return
+	}
+	outErr = response.outErr
 	return
 }
 
@@ -1108,6 +1343,8 @@
 	_ = responseParamsMap // To avoid the declared but unused compiler error
 	mstruct_Scan := discovery_Scanner_Scan_ResponseParams__()
 	responseParamsMap[interfaceMethodName_Scanner_Scan] = &mstruct_Scan
+	mstruct_Stop := discovery_Scanner_Stop_ResponseParams__()
+	responseParamsMap[interfaceMethodName_Scanner_Stop] = &mstruct_Stop
 	return mojom_types.MojomInterface{
 		DeclData: &mojom_types.DeclarationData{
 			ShortName: &interfaceName_Scanner,
@@ -1180,7 +1417,7 @@
 		}
 		return s.connector.WriteMessage(message)
 	case scanner_Stop_Name:
-		if message.Header.Flags != bindings.MessageNoFlag {
+		if message.Header.Flags != bindings.MessageExpectsResponseFlag {
 			return &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
 				fmt.Sprintf("invalid message header flag: %v", message.Header.Flags),
 			}
@@ -1189,10 +1426,21 @@
 		if err := message.DecodePayload(&request); err != nil {
 			return err
 		}
-		err = s.impl.Stop(request.inH)
+		var response scanner_Stop_ResponseParams
+		response.outErr, err = s.impl.Stop(request.inH)
 		if err != nil {
 			return
 		}
+		header := bindings.MessageHeader{
+			Type:      scanner_Stop_Name,
+			Flags:     bindings.MessageIsResponseFlag,
+			RequestId: message.Header.RequestId,
+		}
+		message, err = bindings.EncodeMessage(header, &response)
+		if err != nil {
+			return err
+		}
+		return s.connector.WriteMessage(message)
 	default:
 		return &bindings.ValidationError{
 			bindings.MessageHeaderUnknownMethod,
diff --git a/go/src/vanadium/discovery/internal/discovery.go b/go/src/vanadium/discovery/internal/discovery.go
index 512e19a..41bd5f5 100644
--- a/go/src/vanadium/discovery/internal/discovery.go
+++ b/go/src/vanadium/discovery/internal/discovery.go
@@ -17,6 +17,12 @@
 	"v.io/v23/verror"
 )
 
+const pkgPath = "mojo/vanadium/discovery/vanadium/discovery"
+
+var (
+	errInvalidHandle = verror.Register(pkgPath+".errInvalidHandle", verror.NoRetry, "{1:}{2:} handle not valid")
+)
+
 type handleT uint32
 
 // DiscoveryService implements the mojom interface mojom/vanadium/discovery.DiscoveryService.  It
@@ -97,15 +103,17 @@
 	return uint32(currId), vService.InstanceId, nil, nil
 }
 
-func (d *DiscoveryService) stopAdvertising(handle uint32) error {
+func (d *DiscoveryService) stopAdvertising(handle uint32) (*mojom.Error, error) {
 	d.mu.Lock()
 	stop := d.activeAdvs[handleT(handle)]
+	if stop == nil {
+		d.mu.Unlock()
+		return v2mError(verror.New(errInvalidHandle, d.ctx)), nil
+	}
 	delete(d.activeAdvs, handleT(handle))
 	d.mu.Unlock()
-	if stop != nil {
-		stop()
-	}
-	return nil
+	stop()
+	return nil, nil
 }
 
 func v2mService(s discovery.Service) mojom.Service {
@@ -154,22 +162,24 @@
 }
 
 // Stop stops the scan.
-func (d *DiscoveryService) Stop(handle uint32) error {
+func (d *DiscoveryService) Stop(handle uint32) (*mojom.Error, error) {
 	if handle%2 == 0 {
 		return d.stopScan(handle)
 	}
 	return d.stopAdvertising(handle)
 }
 
-func (d *DiscoveryService) stopScan(handle uint32) error {
+func (d *DiscoveryService) stopScan(handle uint32) (*mojom.Error, error) {
 	d.mu.Lock()
 	cancel := d.activeScans[handleT(handle)]
+	if cancel == nil {
+		d.mu.Unlock()
+		return v2mError(verror.New(errInvalidHandle, d.ctx)), nil
+	}
 	delete(d.activeScans, handleT(handle))
 	d.mu.Unlock()
-	if cancel != nil {
-		cancel()
-	}
-	return nil
+	cancel()
+	return nil, nil
 }
 
 // Stop Stops all scans and advertisements.
diff --git a/lib/gen/dart-gen/mojom/lib/discovery/discovery.mojom.dart b/lib/gen/dart-gen/mojom/lib/discovery/discovery.mojom.dart
index 6c91ff7..d0f6172 100644
--- a/lib/gen/dart-gen/mojom/lib/discovery/discovery.mojom.dart
+++ b/lib/gen/dart-gen/mojom/lib/discovery/discovery.mojom.dart
@@ -519,6 +519,74 @@
 }
 
 
+class AdvertiserStopResponseParams extends bindings.Struct {
+  static const List<bindings.StructDataHeader> kVersions = const [
+    const bindings.StructDataHeader(16, 0)
+  ];
+  Error err = null;
+
+  AdvertiserStopResponseParams() : super(kVersions.last.size);
+
+  static AdvertiserStopResponseParams deserialize(bindings.Message message) {
+    var decoder = new bindings.Decoder(message);
+    var result = decode(decoder);
+    if (decoder.excessHandles != null) {
+      decoder.excessHandles.forEach((h) => h.close());
+    }
+    return result;
+  }
+
+  static AdvertiserStopResponseParams decode(bindings.Decoder decoder0) {
+    if (decoder0 == null) {
+      return null;
+    }
+    AdvertiserStopResponseParams result = new AdvertiserStopResponseParams();
+
+    var mainDataHeader = decoder0.decodeStructDataHeader();
+    if (mainDataHeader.version <= kVersions.last.version) {
+      // Scan in reverse order to optimize for more recent versions.
+      for (int i = kVersions.length - 1; i >= 0; --i) {
+        if (mainDataHeader.version >= kVersions[i].version) {
+          if (mainDataHeader.size == kVersions[i].size) {
+            // Found a match.
+            break;
+          }
+          throw new bindings.MojoCodecError(
+              'Header size doesn\'t correspond to known version size.');
+        }
+      }
+    } else if (mainDataHeader.size < kVersions.last.size) {
+      throw new bindings.MojoCodecError(
+        'Message newer than the last known version cannot be shorter than '
+        'required by the last known version.');
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      var decoder1 = decoder0.decodePointer(8, true);
+      result.err = Error.decode(decoder1);
+    }
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder) {
+    var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
+    
+    encoder0.encodeStruct(err, 8, true);
+  }
+
+  String toString() {
+    return "AdvertiserStopResponseParams("
+           "err: $err" ")";
+  }
+
+  Map toJson() {
+    Map map = new Map();
+    map["err"] = err;
+    return map;
+  }
+}
+
+
 class ScannerScanParams extends bindings.Struct {
   static const List<bindings.StructDataHeader> kVersions = const [
     const bindings.StructDataHeader(24, 0)
@@ -737,6 +805,74 @@
 }
 
 
+class ScannerStopResponseParams extends bindings.Struct {
+  static const List<bindings.StructDataHeader> kVersions = const [
+    const bindings.StructDataHeader(16, 0)
+  ];
+  Error err = null;
+
+  ScannerStopResponseParams() : super(kVersions.last.size);
+
+  static ScannerStopResponseParams deserialize(bindings.Message message) {
+    var decoder = new bindings.Decoder(message);
+    var result = decode(decoder);
+    if (decoder.excessHandles != null) {
+      decoder.excessHandles.forEach((h) => h.close());
+    }
+    return result;
+  }
+
+  static ScannerStopResponseParams decode(bindings.Decoder decoder0) {
+    if (decoder0 == null) {
+      return null;
+    }
+    ScannerStopResponseParams result = new ScannerStopResponseParams();
+
+    var mainDataHeader = decoder0.decodeStructDataHeader();
+    if (mainDataHeader.version <= kVersions.last.version) {
+      // Scan in reverse order to optimize for more recent versions.
+      for (int i = kVersions.length - 1; i >= 0; --i) {
+        if (mainDataHeader.version >= kVersions[i].version) {
+          if (mainDataHeader.size == kVersions[i].size) {
+            // Found a match.
+            break;
+          }
+          throw new bindings.MojoCodecError(
+              'Header size doesn\'t correspond to known version size.');
+        }
+      }
+    } else if (mainDataHeader.size < kVersions.last.size) {
+      throw new bindings.MojoCodecError(
+        'Message newer than the last known version cannot be shorter than '
+        'required by the last known version.');
+    }
+    if (mainDataHeader.version >= 0) {
+      
+      var decoder1 = decoder0.decodePointer(8, true);
+      result.err = Error.decode(decoder1);
+    }
+    return result;
+  }
+
+  void encode(bindings.Encoder encoder) {
+    var encoder0 = encoder.getStructEncoderAtOffset(kVersions.last);
+    
+    encoder0.encodeStruct(err, 8, true);
+  }
+
+  String toString() {
+    return "ScannerStopResponseParams("
+           "err: $err" ")";
+  }
+
+  Map toJson() {
+    Map map = new Map();
+    map["err"] = err;
+    return map;
+  }
+}
+
+
 class ScanHandlerFoundParams extends bindings.Struct {
   static const List<bindings.StructDataHeader> kVersions = const [
     const bindings.StructDataHeader(16, 0)
@@ -879,7 +1015,7 @@
 
 abstract class Advertiser {
   dynamic advertise(Service service,List<String> visibility,[Function responseFactory = null]);
-  void stop(int h);
+  dynamic stop(int h,[Function responseFactory = null]);
 
 }
 
@@ -923,6 +1059,26 @@
         }
         c.complete(r);
         break;
+      case kAdvertiser_stop_name:
+        var r = AdvertiserStopResponseParams.deserialize(
+            message.payload);
+        if (!message.header.hasRequestId) {
+          proxyError("Expected a message with a valid request Id.");
+          return;
+        }
+        Completer c = completerMap[message.header.requestId];
+        if (c == null) {
+          proxyError(
+              "Message had unknown request Id: ${message.header.requestId}");
+          return;
+        }
+        completerMap.remove(message.header.requestId);
+        if (c.isCompleted) {
+          proxyError("Response completer already completed");
+          return;
+        }
+        c.complete(r);
+        break;
       default:
         proxyError("Unexpected message type: ${message.header.type}");
         close(immediate: true);
@@ -951,16 +1107,15 @@
           -1,
           bindings.MessageHeader.kMessageExpectsResponse);
     }
-    void stop(int h) {
-      if (!_proxyImpl.isBound) {
-        _proxyImpl.proxyError("The Proxy is closed.");
-        return;
-      }
+    dynamic stop(int h,[Function responseFactory = null]) {
       var params = new AdvertiserStopParams();
       params.h = h;
-      _proxyImpl.sendMessage(params, kAdvertiser_stop_name);
+      return _proxyImpl.sendMessageWithRequestId(
+          params,
+          kAdvertiser_stop_name,
+          -1,
+          bindings.MessageHeader.kMessageExpectsResponse);
     }
-  
 }
 
 
@@ -1050,6 +1205,11 @@
     result.err = err;
     return result;
   }
+  AdvertiserStopResponseParams _AdvertiserStopResponseParamsFactory(Error err) {
+    var result = new AdvertiserStopResponseParams();
+    result.err = err;
+    return result;
+  }
 
   dynamic handleMessage(bindings.ServiceMessage message) {
     if (bindings.ControlMessageHandler.isControlMessage(message)) {
@@ -1084,7 +1244,24 @@
       case kAdvertiser_stop_name:
         var params = AdvertiserStopParams.deserialize(
             message.payload);
-        _impl.stop(params.h);
+        var response = _impl.stop(params.h,_AdvertiserStopResponseParamsFactory);
+        if (response is Future) {
+          return response.then((response) {
+            if (response != null) {
+              return buildResponseWithId(
+                  response,
+                  kAdvertiser_stop_name,
+                  message.header.requestId,
+                  bindings.MessageHeader.kMessageIsResponse);
+            }
+          });
+        } else if (response != null) {
+          return buildResponseWithId(
+              response,
+              kAdvertiser_stop_name,
+              message.header.requestId,
+              bindings.MessageHeader.kMessageIsResponse);
+        }
         break;
       default:
         throw new bindings.MojoCodecError("Unexpected message name");
@@ -1115,7 +1292,7 @@
 
 abstract class Scanner {
   dynamic scan(String query,Object scanHandler,[Function responseFactory = null]);
-  void stop(int h);
+  dynamic stop(int h,[Function responseFactory = null]);
 
 }
 
@@ -1159,6 +1336,26 @@
         }
         c.complete(r);
         break;
+      case kScanner_stop_name:
+        var r = ScannerStopResponseParams.deserialize(
+            message.payload);
+        if (!message.header.hasRequestId) {
+          proxyError("Expected a message with a valid request Id.");
+          return;
+        }
+        Completer c = completerMap[message.header.requestId];
+        if (c == null) {
+          proxyError(
+              "Message had unknown request Id: ${message.header.requestId}");
+          return;
+        }
+        completerMap.remove(message.header.requestId);
+        if (c.isCompleted) {
+          proxyError("Response completer already completed");
+          return;
+        }
+        c.complete(r);
+        break;
       default:
         proxyError("Unexpected message type: ${message.header.type}");
         close(immediate: true);
@@ -1187,16 +1384,15 @@
           -1,
           bindings.MessageHeader.kMessageExpectsResponse);
     }
-    void stop(int h) {
-      if (!_proxyImpl.isBound) {
-        _proxyImpl.proxyError("The Proxy is closed.");
-        return;
-      }
+    dynamic stop(int h,[Function responseFactory = null]) {
       var params = new ScannerStopParams();
       params.h = h;
-      _proxyImpl.sendMessage(params, kScanner_stop_name);
+      return _proxyImpl.sendMessageWithRequestId(
+          params,
+          kScanner_stop_name,
+          -1,
+          bindings.MessageHeader.kMessageExpectsResponse);
     }
-  
 }
 
 
@@ -1285,6 +1481,11 @@
     result.err = err;
     return result;
   }
+  ScannerStopResponseParams _ScannerStopResponseParamsFactory(Error err) {
+    var result = new ScannerStopResponseParams();
+    result.err = err;
+    return result;
+  }
 
   dynamic handleMessage(bindings.ServiceMessage message) {
     if (bindings.ControlMessageHandler.isControlMessage(message)) {
@@ -1319,7 +1520,24 @@
       case kScanner_stop_name:
         var params = ScannerStopParams.deserialize(
             message.payload);
-        _impl.stop(params.h);
+        var response = _impl.stop(params.h,_ScannerStopResponseParamsFactory);
+        if (response is Future) {
+          return response.then((response) {
+            if (response != null) {
+              return buildResponseWithId(
+                  response,
+                  kScanner_stop_name,
+                  message.header.requestId,
+                  bindings.MessageHeader.kMessageIsResponse);
+            }
+          });
+        } else if (response != null) {
+          return buildResponseWithId(
+              response,
+              kScanner_stop_name,
+              message.header.requestId,
+              bindings.MessageHeader.kMessageIsResponse);
+        }
         break;
       default:
         throw new bindings.MojoCodecError("Unexpected message name");
diff --git a/mojom/vanadium/discovery.mojom b/mojom/vanadium/discovery.mojom
index f29ddd2..5a5c89a 100644
--- a/mojom/vanadium/discovery.mojom
+++ b/mojom/vanadium/discovery.mojom
@@ -40,7 +40,7 @@
   Advertise(Service service, array<string>? visibility) => (uint32 Handle, string instanceId, Error? Err);
 
   // Stop Stops the advertisement associated with the given handle.
-  Stop(uint32 h);
+  Stop(uint32 h) => (Error? Err);
 };
 
 // Scanner provides methods to scan for Vanadium advertisements.
@@ -61,7 +61,7 @@
   Scan(string query, ScanHandler scanHandler) => (uint32 Handle, Error? Err);
 
   // StopScan stops the scanner associated weith the given handle.
-  Stop(uint32 h);
+  Stop(uint32 h) => (Error? Err);
 };
 
 // ScanHandler is used to pass updates about Services that are found/lost during
diff --git a/pubspec.yaml b/pubspec.yaml
index c7c369c..64fbe93 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -2,11 +2,11 @@
 description: Discovery is a discovery system for developers that makes it easy to advertise apps and scan for them. It works over MDNS and BLE.
 homepage: https://github.com/vanadium/mojo.discovery
 name: v23discovery
-version: 0.0.5
+version: 0.0.6
 dependencies:
   mojo: '>=0.3.0 <0.5.0'
 dev_dependencies:
   dart_style: any
   test: any
 environment:
-  sdk: '>=1.12.0 <2.0.0'
\ No newline at end of file
+  sdk: '>=1.12.0 <2.0.0'