mojo/discovery: Implement a mojo service for discovery.

This implementation currently doesn't set ACLs since that API is in
flux.  It also will turn on both ble and mdns and only works for linux
amd64 machines.

Change-Id: I3b93c7b9dac3b38a1840d01f5fca1977c56cd51b
diff --git a/.gitignore b/.gitignore
index c2296ef..d1b26e4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
 /.jiri
 #TODO(nlacasse): Get rid of .v23 below once v23->jiri transition is complete.
-/.v23
\ No newline at end of file
+/.v23
+gen
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..c54ae5c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,50 @@
+include ../shared/mojo.mk
+V23_GO_FILES := $(shell find $(JIRI_ROOT) -name "*.go")
+
+
+ifdef ANDROID
+	DISCOVERY_BUILD_DIR := $(PWD)/gen/mojo/android
+else
+	DISCOVERY_BUILD_DIR := $(PWD)/gen/mojo/linux_amd64
+endif
+
+MOJO_SHELL_FLAGS := $(MOJO_SHELL_FLAGS) \
+	--config-alias DISCOVERY_DIR=$(PWD) \
+	--config-alias DISCOVERY_BUILD_DIR=$(DISCOVERY_BUILD_DIR)
+
+define CGO_TEST
+	GOPATH="$(GOPATH)" \
+	CGO_CFLAGS="-I$(MOJO_DIR)/src $(CGO_CFLAGS)" \
+	CGO_CXXFLAGS="-I$(MOJO_DIR)/src $(CGO_CXXFLAGS)" \
+	CGO_LDFLAGS="-L$(dir $(MOJO_SHARED_LIB)) -lsystem_thunk $(CGO_LDFLAGS)" \
+	$(GOROOT)/bin/go test -v $1
+
+endef
+all: $(DISCOVERY_BUILD_DIR)/discovery.mojo
+
+
+go/src/mojom/vanadium/discovery/discovery.mojom.go: mojom/vanadium/discovery.mojom | mojo-env-check
+	$(call MOJOM_GEN,$<,.,go)
+	gofmt -w $@
+
+
+$(DISCOVERY_BUILD_DIR)/discovery.mojo: $(V23_GO_FILES) $(MOJO_SHARED_LIB) go/src/mojom/vanadium/discovery/discovery.mojom.go | mojo-env-check
+	$(call MOGO_BUILD,vanadium/discovery,$@)
+
+$(DISCOVERY_BUILD_DIR)/advertiser.mojo: $(V23_GO_FILES) $(MOJO_SHARED_LIB) go/src/mojom/vanadium/discovery/discovery.mojom.go | mojo-env-check
+	$(call MOGO_BUILD,examples/advertiser,$@)
+
+$(DISCOVERY_BUILD_DIR)/scanner.mojo: $(V23_GO_FILES) $(MOJO_SHARED_LIB) go/src/mojom/vanadium/discovery/discovery.mojom.go | mojo-env-check
+	$(call MOGO_BUILD,examples/scanner,$@)
+
+discovery_test: $(V23_GO_FILES) $(MOJO_SHARED_LIB) go/src/mojom/vanadium/discovery/discovery.mojom.go | mojo-env-check
+	echo $(GOPATH)
+	$(call CGO_TEST,vanadium/discovery/internal)
+
+run-advertiser: $(DISCOVERY_BUILD_DIR)/advertiser.mojo $(DISCOVERY_BUILD_DIR)/discovery.mojo
+	sudo $(MOJO_DIR)/src/mojo/devtools/common/mojo_run --config-file $(PWD)/mojoconfig $(MOJO_SHELL_FLAGS) $(MOJO_ANDROID_FLAGS) https://mojo.v.io/advertiser.mojo \
+	--args-for="https://mojo.v.io/discovery.mojo host1 ble mdns"
+
+run-scanner: $(DISCOVERY_BUILD_DIR)/scanner.mojo $(DISCOVERY_BUILD_DIR)/discovery.mojo
+	sudo $(MOJO_DIR)/src/mojo/devtools/common/mojo_run --config-file $(PWD)/mojoconfig $(MOJO_SHELL_FLAGS) $(MOJO_ANDROID_FLAGS) https://mojo.v.io/scanner.mojo \
+	--args-for="https://mojo.v.io/discovery.mojo host2 ble mdns"
\ No newline at end of file
diff --git a/go/src/examples/advertiser/advertiser.go b/go/src/examples/advertiser/advertiser.go
new file mode 100644
index 0000000..f428fae
--- /dev/null
+++ b/go/src/examples/advertiser/advertiser.go
@@ -0,0 +1,58 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"log"
+
+	"mojo/public/go/application"
+	"mojo/public/go/bindings"
+	"mojo/public/go/system"
+
+	"mojom/vanadium/discovery"
+)
+
+//#include "mojo/public/c/system/types.h"
+import "C"
+
+type advDelegate struct {
+	id    uint32
+	proxy *discovery.Advertiser_Proxy
+}
+
+func (a *advDelegate) Initialize(ctx application.Context) {
+	req, ptr := discovery.CreateMessagePipeForAdvertiser()
+	ctx.ConnectToApplication("https://mojo.v.io/discovery.mojo").ConnectToService(&req)
+	a.proxy = discovery.NewAdvertiserProxy(ptr, bindings.GetAsyncWaiter())
+	s := discovery.Service{
+		InterfaceName: "v.io/discovery.T",
+		Addrs:         []string{"localhost:1000", "localhost:2000"},
+		Attrs:         map[string]string{"foo": "bar"},
+	}
+	id, e1, e2 := a.proxy.Advertise(s, nil)
+	if e1 != nil || e2 != nil {
+		log.Println("Error occurred", e1, e2)
+		return
+	}
+
+	a.id = id
+}
+
+func (*advDelegate) AcceptConnection(connection *application.Connection) {
+	connection.Close()
+}
+
+func (s *advDelegate) Quit() {
+	s.proxy.Stop(s.id)
+}
+
+//export MojoMain
+func MojoMain(handle C.MojoHandle) C.MojoResult {
+	application.Run(&advDelegate{}, system.MojoHandle(handle))
+	return C.MOJO_RESULT_OK
+}
+
+func main() {
+}
diff --git a/go/src/examples/scanner/scanner.go b/go/src/examples/scanner/scanner.go
new file mode 100644
index 0000000..1fded60
--- /dev/null
+++ b/go/src/examples/scanner/scanner.go
@@ -0,0 +1,80 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"log"
+
+	"mojo/public/go/application"
+	"mojo/public/go/bindings"
+	"mojo/public/go/system"
+
+	"mojom/vanadium/discovery"
+)
+
+//#include "mojo/public/c/system/types.h"
+import "C"
+
+type handler struct{}
+
+func (*handler) Found(s discovery.Service) error {
+	log.Println("Found a new service", s)
+	return nil
+}
+
+func (*handler) Lost(s []uint8) error {
+	log.Println("Lost a new service", s)
+	return nil
+}
+
+type scannerDelegate struct {
+	id    uint32
+	proxy *discovery.Scanner_Proxy
+	stub  *bindings.Stub
+}
+
+func (s *scannerDelegate) Initialize(ctx application.Context) {
+	req, ptr := discovery.CreateMessagePipeForScanner()
+	ctx.ConnectToApplication("https://mojo.v.io/discovery.mojo").ConnectToService(&req)
+	s.proxy = discovery.NewScannerProxy(ptr, bindings.GetAsyncWaiter())
+	scanReq, scanPtr := discovery.CreateMessagePipeForScanHandler()
+	s.stub = discovery.NewScanHandlerStub(scanReq, &handler{}, bindings.GetAsyncWaiter())
+	id, e1, e2 := s.proxy.Scan("v.io/discovery.T", scanPtr)
+	if e1 != nil || e2 != nil {
+		log.Println("Error occurred", e1, e2)
+		return
+	}
+
+	s.id = id
+	go func() {
+		for {
+			if err := s.stub.ServeRequest(); err != nil {
+				connectionError, ok := err.(*bindings.ConnectionError)
+				if !ok || !connectionError.Closed() {
+					log.Println(err)
+				}
+				break
+			}
+		}
+	}()
+}
+
+func (*scannerDelegate) AcceptConnection(connection *application.Connection) {
+	connection.Close()
+}
+
+func (s *scannerDelegate) Quit() {
+	s.proxy.Stop(s.id)
+	s.stub.Close()
+}
+
+//export MojoMain
+func MojoMain(handle C.MojoHandle) C.MojoResult {
+	application.Run(&scannerDelegate{}, system.MojoHandle(handle))
+	return C.MOJO_RESULT_OK
+}
+
+func main() {
+}
diff --git a/go/src/mojom/vanadium/discovery/discovery.mojom.go b/go/src/mojom/vanadium/discovery/discovery.mojom.go
new file mode 100644
index 0000000..c2147c0
--- /dev/null
+++ b/go/src/mojom/vanadium/discovery/discovery.mojom.go
@@ -0,0 +1,1507 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by:
+//     mojo/public/tools/bindings/mojom_bindings_generator.py
+// For:
+//     mojom/vanadium/discovery.mojom
+//
+
+package discovery
+
+import (
+	"fmt"
+	"mojo/public/go/bindings"
+	"mojo/public/go/system"
+	"sort"
+)
+
+type Advertiser interface {
+	Advertise(inS Service, inVisibility []string) (outHandle uint32, outErr *Error, err error)
+	Stop(inH uint32) (err error)
+}
+
+var advertiser_Name = "discovery::Advertiser"
+
+type Advertiser_Request bindings.InterfaceRequest
+
+func (r *Advertiser_Request) Name() string {
+	return advertiser_Name
+}
+
+type Advertiser_Pointer bindings.InterfacePointer
+
+func (p *Advertiser_Pointer) Name() string {
+	return advertiser_Name
+}
+
+type Advertiser_ServiceFactory struct {
+	Delegate Advertiser_Factory
+}
+
+type Advertiser_Factory interface {
+	Create(request Advertiser_Request)
+}
+
+func (f *Advertiser_ServiceFactory) Name() string {
+	return advertiser_Name
+}
+
+func (f *Advertiser_ServiceFactory) Create(messagePipe system.MessagePipeHandle) {
+	request := Advertiser_Request{bindings.NewMessagePipeHandleOwner(messagePipe)}
+	f.Delegate.Create(request)
+}
+
+// CreateMessagePipeForAdvertiser creates a message pipe for use with the
+// Advertiser interface with a Advertiser_Request on one end and a Advertiser_Pointer on the other.
+func CreateMessagePipeForAdvertiser() (Advertiser_Request, Advertiser_Pointer) {
+	r, p := bindings.CreateMessagePipeForMojoInterface()
+	return Advertiser_Request(r), Advertiser_Pointer(p)
+}
+
+const advertiser_Advertise_Name uint32 = 0
+const advertiser_Stop_Name uint32 = 1
+
+type Advertiser_Proxy struct {
+	router *bindings.Router
+	ids    bindings.Counter
+}
+
+func NewAdvertiserProxy(p Advertiser_Pointer, waiter bindings.AsyncWaiter) *Advertiser_Proxy {
+	return &Advertiser_Proxy{
+		bindings.NewRouter(p.PassMessagePipe(), waiter),
+		bindings.NewCounter(),
+	}
+}
+
+func (p *Advertiser_Proxy) Close_Proxy() {
+	p.router.Close()
+}
+
+type advertiser_Advertise_Params struct {
+	inS          Service
+	inVisibility []string
+}
+
+func (s *advertiser_Advertise_Params) Encode(encoder *bindings.Encoder) error {
+	encoder.StartStruct(16, 0)
+	if err := encoder.WritePointer(); err != nil {
+		return err
+	}
+	if err := s.inS.Encode(encoder); err != nil {
+		return err
+	}
+	if err := encoder.WritePointer(); err != nil {
+		return err
+	}
+	encoder.StartArray(uint32(len(s.inVisibility)), 64)
+	for _, elem0 := range s.inVisibility {
+		if err := encoder.WritePointer(); err != nil {
+			return err
+		}
+		if err := encoder.WriteString(elem0); err != nil {
+			return err
+		}
+	}
+	if err := encoder.Finish(); err != nil {
+		return err
+	}
+	if err := encoder.Finish(); err != nil {
+		return err
+	}
+	return nil
+}
+
+var advertiser_Advertise_Params_Versions []bindings.DataHeader = []bindings.DataHeader{
+	bindings.DataHeader{24, 0},
+}
+
+func (s *advertiser_Advertise_Params) Decode(decoder *bindings.Decoder) error {
+	header, err := decoder.StartStruct()
+	if err != nil {
+		return err
+	}
+	index := sort.Search(len(advertiser_Advertise_Params_Versions), func(i int) bool {
+		return advertiser_Advertise_Params_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+	})
+	if index < len(advertiser_Advertise_Params_Versions) {
+		if advertiser_Advertise_Params_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+			index--
+		}
+		expectedSize := advertiser_Advertise_Params_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 {
+			return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+		} else {
+			if err := s.inS.Decode(decoder); err != nil {
+				return err
+			}
+		}
+	}
+	if header.ElementsOrVersion >= 0 {
+		pointer0, err := decoder.ReadPointer()
+		if err != nil {
+			return err
+		}
+		if pointer0 == 0 {
+			return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+		} else {
+			len0, err := decoder.StartArray(64)
+			if err != nil {
+				return err
+			}
+			s.inVisibility = make([]string, len0)
+			for i0 := uint32(0); i0 < len0; i0++ {
+				pointer1, err := decoder.ReadPointer()
+				if err != nil {
+					return err
+				}
+				if pointer1 == 0 {
+					return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+				} else {
+					value1, err := decoder.ReadString()
+					if err != nil {
+						return err
+					}
+					s.inVisibility[i0] = value1
+				}
+			}
+			if err := decoder.Finish(); err != nil {
+				return err
+			}
+		}
+	}
+	if err := decoder.Finish(); err != nil {
+		return err
+	}
+	return nil
+}
+
+type advertiser_Advertise_ResponseParams struct {
+	outHandle uint32
+	outErr    *Error
+}
+
+func (s *advertiser_Advertise_ResponseParams) Encode(encoder *bindings.Encoder) error {
+	encoder.StartStruct(16, 0)
+	if err := encoder.WriteUint32(s.outHandle); err != nil {
+		return err
+	}
+	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_Advertise_ResponseParams_Versions []bindings.DataHeader = []bindings.DataHeader{
+	bindings.DataHeader{24, 0},
+}
+
+func (s *advertiser_Advertise_ResponseParams) Decode(decoder *bindings.Decoder) error {
+	header, err := decoder.StartStruct()
+	if err != nil {
+		return err
+	}
+	index := sort.Search(len(advertiser_Advertise_ResponseParams_Versions), func(i int) bool {
+		return advertiser_Advertise_ResponseParams_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+	})
+	if index < len(advertiser_Advertise_ResponseParams_Versions) {
+		if advertiser_Advertise_ResponseParams_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+			index--
+		}
+		expectedSize := advertiser_Advertise_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 {
+		value0, err := decoder.ReadUint32()
+		if err != nil {
+			return err
+		}
+		s.outHandle = value0
+	}
+	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
+}
+
+func (p *Advertiser_Proxy) Advertise(inS Service, inVisibility []string) (outHandle uint32, outErr *Error, err error) {
+	payload := &advertiser_Advertise_Params{
+		inS,
+		inVisibility,
+	}
+	header := bindings.MessageHeader{
+		Type:      advertiser_Advertise_Name,
+		Flags:     bindings.MessageExpectsResponseFlag,
+		RequestId: p.ids.Count(),
+	}
+	var message *bindings.Message
+	if message, err = bindings.EncodeMessage(header, payload); err != nil {
+		err = fmt.Errorf("can't encode request: %v", err.Error())
+		p.Close_Proxy()
+		return
+	}
+	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_Advertise_Name; got != want {
+		err = &bindings.ValidationError{bindings.MessageHeaderUnknownMethod,
+			fmt.Sprintf("invalid method in response: expected %v, got %v", want, got),
+		}
+		return
+	}
+	var response advertiser_Advertise_ResponseParams
+	if err = readResult.Message.DecodePayload(&response); err != nil {
+		p.Close_Proxy()
+		return
+	}
+	outHandle = response.outHandle
+	outErr = response.outErr
+	return
+}
+
+type advertiser_Stop_Params struct {
+	inH uint32
+}
+
+func (s *advertiser_Stop_Params) Encode(encoder *bindings.Encoder) error {
+	encoder.StartStruct(8, 0)
+	if err := encoder.WriteUint32(s.inH); err != nil {
+		return err
+	}
+	if err := encoder.Finish(); err != nil {
+		return err
+	}
+	return nil
+}
+
+var advertiser_Stop_Params_Versions []bindings.DataHeader = []bindings.DataHeader{
+	bindings.DataHeader{16, 0},
+}
+
+func (s *advertiser_Stop_Params) Decode(decoder *bindings.Decoder) error {
+	header, err := decoder.StartStruct()
+	if err != nil {
+		return err
+	}
+	index := sort.Search(len(advertiser_Stop_Params_Versions), func(i int) bool {
+		return advertiser_Stop_Params_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+	})
+	if index < len(advertiser_Stop_Params_Versions) {
+		if advertiser_Stop_Params_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+			index--
+		}
+		expectedSize := advertiser_Stop_Params_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 {
+		value0, err := decoder.ReadUint32()
+		if err != nil {
+			return err
+		}
+		s.inH = value0
+	}
+	if err := decoder.Finish(); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (p *Advertiser_Proxy) Stop(inH uint32) (err error) {
+	payload := &advertiser_Stop_Params{
+		inH,
+	}
+	header := bindings.MessageHeader{
+		Type:  advertiser_Stop_Name,
+		Flags: bindings.MessageNoFlag,
+	}
+	var message *bindings.Message
+	if message, err = bindings.EncodeMessage(header, payload); err != nil {
+		err = fmt.Errorf("can't encode request: %v", err.Error())
+		p.Close_Proxy()
+		return
+	}
+	if err = p.router.Accept(message); err != nil {
+		p.Close_Proxy()
+		return
+	}
+	return
+}
+
+type advertiser_Stub struct {
+	connector *bindings.Connector
+	impl      Advertiser
+}
+
+func NewAdvertiserStub(r Advertiser_Request, impl Advertiser, waiter bindings.AsyncWaiter) *bindings.Stub {
+	connector := bindings.NewConnector(r.PassMessagePipe(), waiter)
+	return bindings.NewStub(connector, &advertiser_Stub{connector, impl})
+}
+
+func (s *advertiser_Stub) Accept(message *bindings.Message) (err error) {
+	switch message.Header.Type {
+	case advertiser_Advertise_Name:
+		if message.Header.Flags != bindings.MessageExpectsResponseFlag {
+			return &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+				fmt.Sprintf("invalid message header flag: %v", message.Header.Flags),
+			}
+		}
+		var request advertiser_Advertise_Params
+		if err := message.DecodePayload(&request); err != nil {
+			return err
+		}
+		var response advertiser_Advertise_ResponseParams
+		response.outHandle, response.outErr, err = s.impl.Advertise(request.inS, request.inVisibility)
+		if err != nil {
+			return
+		}
+		header := bindings.MessageHeader{
+			Type:      advertiser_Advertise_Name,
+			Flags:     bindings.MessageIsResponseFlag,
+			RequestId: message.Header.RequestId,
+		}
+		message, err = bindings.EncodeMessage(header, &response)
+		if err != nil {
+			return err
+		}
+		return s.connector.WriteMessage(message)
+	case advertiser_Stop_Name:
+		if message.Header.Flags != bindings.MessageNoFlag {
+			return &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+				fmt.Sprintf("invalid message header flag: %v", message.Header.Flags),
+			}
+		}
+		var request advertiser_Stop_Params
+		if err := message.DecodePayload(&request); err != nil {
+			return err
+		}
+		err = s.impl.Stop(request.inH)
+		if err != nil {
+			return
+		}
+	default:
+		return &bindings.ValidationError{
+			bindings.MessageHeaderUnknownMethod,
+			fmt.Sprintf("unknown method %v", message.Header.Type),
+		}
+	}
+	return
+}
+
+type Scanner interface {
+	Scan(inQuery string, inScanHandler ScanHandler_Pointer) (outHandle uint32, outErr *Error, err error)
+	Stop(inH uint32) (err error)
+}
+
+var scanner_Name = "discovery::Scanner"
+
+type Scanner_Request bindings.InterfaceRequest
+
+func (r *Scanner_Request) Name() string {
+	return scanner_Name
+}
+
+type Scanner_Pointer bindings.InterfacePointer
+
+func (p *Scanner_Pointer) Name() string {
+	return scanner_Name
+}
+
+type Scanner_ServiceFactory struct {
+	Delegate Scanner_Factory
+}
+
+type Scanner_Factory interface {
+	Create(request Scanner_Request)
+}
+
+func (f *Scanner_ServiceFactory) Name() string {
+	return scanner_Name
+}
+
+func (f *Scanner_ServiceFactory) Create(messagePipe system.MessagePipeHandle) {
+	request := Scanner_Request{bindings.NewMessagePipeHandleOwner(messagePipe)}
+	f.Delegate.Create(request)
+}
+
+// CreateMessagePipeForScanner creates a message pipe for use with the
+// Scanner interface with a Scanner_Request on one end and a Scanner_Pointer on the other.
+func CreateMessagePipeForScanner() (Scanner_Request, Scanner_Pointer) {
+	r, p := bindings.CreateMessagePipeForMojoInterface()
+	return Scanner_Request(r), Scanner_Pointer(p)
+}
+
+const scanner_Scan_Name uint32 = 0
+const scanner_Stop_Name uint32 = 1
+
+type Scanner_Proxy struct {
+	router *bindings.Router
+	ids    bindings.Counter
+}
+
+func NewScannerProxy(p Scanner_Pointer, waiter bindings.AsyncWaiter) *Scanner_Proxy {
+	return &Scanner_Proxy{
+		bindings.NewRouter(p.PassMessagePipe(), waiter),
+		bindings.NewCounter(),
+	}
+}
+
+func (p *Scanner_Proxy) Close_Proxy() {
+	p.router.Close()
+}
+
+type scanner_Scan_Params struct {
+	inQuery       string
+	inScanHandler ScanHandler_Pointer
+}
+
+func (s *scanner_Scan_Params) Encode(encoder *bindings.Encoder) error {
+	encoder.StartStruct(16, 0)
+	if err := encoder.WritePointer(); err != nil {
+		return err
+	}
+	if err := encoder.WriteString(s.inQuery); err != nil {
+		return err
+	}
+	if err := encoder.WriteInterface(s.inScanHandler.PassMessagePipe()); err != nil {
+		return err
+	}
+	if err := encoder.Finish(); err != nil {
+		return err
+	}
+	return nil
+}
+
+var scanner_Scan_Params_Versions []bindings.DataHeader = []bindings.DataHeader{
+	bindings.DataHeader{24, 0},
+}
+
+func (s *scanner_Scan_Params) Decode(decoder *bindings.Decoder) error {
+	header, err := decoder.StartStruct()
+	if err != nil {
+		return err
+	}
+	index := sort.Search(len(scanner_Scan_Params_Versions), func(i int) bool {
+		return scanner_Scan_Params_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+	})
+	if index < len(scanner_Scan_Params_Versions) {
+		if scanner_Scan_Params_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+			index--
+		}
+		expectedSize := scanner_Scan_Params_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 {
+			return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+		} else {
+			value0, err := decoder.ReadString()
+			if err != nil {
+				return err
+			}
+			s.inQuery = value0
+		}
+	}
+	if header.ElementsOrVersion >= 0 {
+		handle0, err := decoder.ReadInterface()
+		if err != nil {
+			return err
+		}
+		if handle0.IsValid() {
+			handleOwner := bindings.NewMessagePipeHandleOwner(handle0)
+			s.inScanHandler = ScanHandler_Pointer{handleOwner}
+		} else {
+			return &bindings.ValidationError{bindings.UnexpectedInvalidHandle, "unexpected invalid handle"}
+		}
+	}
+	if err := decoder.Finish(); err != nil {
+		return err
+	}
+	return nil
+}
+
+type scanner_Scan_ResponseParams struct {
+	outHandle uint32
+	outErr    *Error
+}
+
+func (s *scanner_Scan_ResponseParams) Encode(encoder *bindings.Encoder) error {
+	encoder.StartStruct(16, 0)
+	if err := encoder.WriteUint32(s.outHandle); err != nil {
+		return err
+	}
+	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_Scan_ResponseParams_Versions []bindings.DataHeader = []bindings.DataHeader{
+	bindings.DataHeader{24, 0},
+}
+
+func (s *scanner_Scan_ResponseParams) Decode(decoder *bindings.Decoder) error {
+	header, err := decoder.StartStruct()
+	if err != nil {
+		return err
+	}
+	index := sort.Search(len(scanner_Scan_ResponseParams_Versions), func(i int) bool {
+		return scanner_Scan_ResponseParams_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+	})
+	if index < len(scanner_Scan_ResponseParams_Versions) {
+		if scanner_Scan_ResponseParams_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+			index--
+		}
+		expectedSize := scanner_Scan_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 {
+		value0, err := decoder.ReadUint32()
+		if err != nil {
+			return err
+		}
+		s.outHandle = value0
+	}
+	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
+}
+
+func (p *Scanner_Proxy) Scan(inQuery string, inScanHandler ScanHandler_Pointer) (outHandle uint32, outErr *Error, err error) {
+	payload := &scanner_Scan_Params{
+		inQuery,
+		inScanHandler,
+	}
+	header := bindings.MessageHeader{
+		Type:      scanner_Scan_Name,
+		Flags:     bindings.MessageExpectsResponseFlag,
+		RequestId: p.ids.Count(),
+	}
+	var message *bindings.Message
+	if message, err = bindings.EncodeMessage(header, payload); err != nil {
+		err = fmt.Errorf("can't encode request: %v", err.Error())
+		p.Close_Proxy()
+		return
+	}
+	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_Scan_Name; got != want {
+		err = &bindings.ValidationError{bindings.MessageHeaderUnknownMethod,
+			fmt.Sprintf("invalid method in response: expected %v, got %v", want, got),
+		}
+		return
+	}
+	var response scanner_Scan_ResponseParams
+	if err = readResult.Message.DecodePayload(&response); err != nil {
+		p.Close_Proxy()
+		return
+	}
+	outHandle = response.outHandle
+	outErr = response.outErr
+	return
+}
+
+type scanner_Stop_Params struct {
+	inH uint32
+}
+
+func (s *scanner_Stop_Params) Encode(encoder *bindings.Encoder) error {
+	encoder.StartStruct(8, 0)
+	if err := encoder.WriteUint32(s.inH); err != nil {
+		return err
+	}
+	if err := encoder.Finish(); err != nil {
+		return err
+	}
+	return nil
+}
+
+var scanner_Stop_Params_Versions []bindings.DataHeader = []bindings.DataHeader{
+	bindings.DataHeader{16, 0},
+}
+
+func (s *scanner_Stop_Params) Decode(decoder *bindings.Decoder) error {
+	header, err := decoder.StartStruct()
+	if err != nil {
+		return err
+	}
+	index := sort.Search(len(scanner_Stop_Params_Versions), func(i int) bool {
+		return scanner_Stop_Params_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+	})
+	if index < len(scanner_Stop_Params_Versions) {
+		if scanner_Stop_Params_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+			index--
+		}
+		expectedSize := scanner_Stop_Params_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 {
+		value0, err := decoder.ReadUint32()
+		if err != nil {
+			return err
+		}
+		s.inH = value0
+	}
+	if err := decoder.Finish(); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (p *Scanner_Proxy) Stop(inH uint32) (err error) {
+	payload := &scanner_Stop_Params{
+		inH,
+	}
+	header := bindings.MessageHeader{
+		Type:  scanner_Stop_Name,
+		Flags: bindings.MessageNoFlag,
+	}
+	var message *bindings.Message
+	if message, err = bindings.EncodeMessage(header, payload); err != nil {
+		err = fmt.Errorf("can't encode request: %v", err.Error())
+		p.Close_Proxy()
+		return
+	}
+	if err = p.router.Accept(message); err != nil {
+		p.Close_Proxy()
+		return
+	}
+	return
+}
+
+type scanner_Stub struct {
+	connector *bindings.Connector
+	impl      Scanner
+}
+
+func NewScannerStub(r Scanner_Request, impl Scanner, waiter bindings.AsyncWaiter) *bindings.Stub {
+	connector := bindings.NewConnector(r.PassMessagePipe(), waiter)
+	return bindings.NewStub(connector, &scanner_Stub{connector, impl})
+}
+
+func (s *scanner_Stub) Accept(message *bindings.Message) (err error) {
+	switch message.Header.Type {
+	case scanner_Scan_Name:
+		if message.Header.Flags != bindings.MessageExpectsResponseFlag {
+			return &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+				fmt.Sprintf("invalid message header flag: %v", message.Header.Flags),
+			}
+		}
+		var request scanner_Scan_Params
+		if err := message.DecodePayload(&request); err != nil {
+			return err
+		}
+		var response scanner_Scan_ResponseParams
+		response.outHandle, response.outErr, err = s.impl.Scan(request.inQuery, request.inScanHandler)
+		if err != nil {
+			return
+		}
+		header := bindings.MessageHeader{
+			Type:      scanner_Scan_Name,
+			Flags:     bindings.MessageIsResponseFlag,
+			RequestId: message.Header.RequestId,
+		}
+		message, err = bindings.EncodeMessage(header, &response)
+		if err != nil {
+			return err
+		}
+		return s.connector.WriteMessage(message)
+	case scanner_Stop_Name:
+		if message.Header.Flags != bindings.MessageNoFlag {
+			return &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+				fmt.Sprintf("invalid message header flag: %v", message.Header.Flags),
+			}
+		}
+		var request scanner_Stop_Params
+		if err := message.DecodePayload(&request); err != nil {
+			return err
+		}
+		err = s.impl.Stop(request.inH)
+		if err != nil {
+			return
+		}
+	default:
+		return &bindings.ValidationError{
+			bindings.MessageHeaderUnknownMethod,
+			fmt.Sprintf("unknown method %v", message.Header.Type),
+		}
+	}
+	return
+}
+
+type ScanHandler interface {
+	Found(inS Service) (err error)
+	Lost(inInstanceId []uint8) (err error)
+}
+
+var scanHandler_Name = "discovery::ScanHandler"
+
+type ScanHandler_Request bindings.InterfaceRequest
+
+func (r *ScanHandler_Request) Name() string {
+	return scanHandler_Name
+}
+
+type ScanHandler_Pointer bindings.InterfacePointer
+
+func (p *ScanHandler_Pointer) Name() string {
+	return scanHandler_Name
+}
+
+type ScanHandler_ServiceFactory struct {
+	Delegate ScanHandler_Factory
+}
+
+type ScanHandler_Factory interface {
+	Create(request ScanHandler_Request)
+}
+
+func (f *ScanHandler_ServiceFactory) Name() string {
+	return scanHandler_Name
+}
+
+func (f *ScanHandler_ServiceFactory) Create(messagePipe system.MessagePipeHandle) {
+	request := ScanHandler_Request{bindings.NewMessagePipeHandleOwner(messagePipe)}
+	f.Delegate.Create(request)
+}
+
+// CreateMessagePipeForScanHandler creates a message pipe for use with the
+// ScanHandler interface with a ScanHandler_Request on one end and a ScanHandler_Pointer on the other.
+func CreateMessagePipeForScanHandler() (ScanHandler_Request, ScanHandler_Pointer) {
+	r, p := bindings.CreateMessagePipeForMojoInterface()
+	return ScanHandler_Request(r), ScanHandler_Pointer(p)
+}
+
+const scanHandler_Found_Name uint32 = 0
+const scanHandler_Lost_Name uint32 = 1
+
+type ScanHandler_Proxy struct {
+	router *bindings.Router
+	ids    bindings.Counter
+}
+
+func NewScanHandlerProxy(p ScanHandler_Pointer, waiter bindings.AsyncWaiter) *ScanHandler_Proxy {
+	return &ScanHandler_Proxy{
+		bindings.NewRouter(p.PassMessagePipe(), waiter),
+		bindings.NewCounter(),
+	}
+}
+
+func (p *ScanHandler_Proxy) Close_Proxy() {
+	p.router.Close()
+}
+
+type scanHandler_Found_Params struct {
+	inS Service
+}
+
+func (s *scanHandler_Found_Params) Encode(encoder *bindings.Encoder) error {
+	encoder.StartStruct(8, 0)
+	if err := encoder.WritePointer(); err != nil {
+		return err
+	}
+	if err := s.inS.Encode(encoder); err != nil {
+		return err
+	}
+	if err := encoder.Finish(); err != nil {
+		return err
+	}
+	return nil
+}
+
+var scanHandler_Found_Params_Versions []bindings.DataHeader = []bindings.DataHeader{
+	bindings.DataHeader{16, 0},
+}
+
+func (s *scanHandler_Found_Params) Decode(decoder *bindings.Decoder) error {
+	header, err := decoder.StartStruct()
+	if err != nil {
+		return err
+	}
+	index := sort.Search(len(scanHandler_Found_Params_Versions), func(i int) bool {
+		return scanHandler_Found_Params_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+	})
+	if index < len(scanHandler_Found_Params_Versions) {
+		if scanHandler_Found_Params_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+			index--
+		}
+		expectedSize := scanHandler_Found_Params_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 {
+			return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+		} else {
+			if err := s.inS.Decode(decoder); err != nil {
+				return err
+			}
+		}
+	}
+	if err := decoder.Finish(); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (p *ScanHandler_Proxy) Found(inS Service) (err error) {
+	payload := &scanHandler_Found_Params{
+		inS,
+	}
+	header := bindings.MessageHeader{
+		Type:  scanHandler_Found_Name,
+		Flags: bindings.MessageNoFlag,
+	}
+	var message *bindings.Message
+	if message, err = bindings.EncodeMessage(header, payload); err != nil {
+		err = fmt.Errorf("can't encode request: %v", err.Error())
+		p.Close_Proxy()
+		return
+	}
+	if err = p.router.Accept(message); err != nil {
+		p.Close_Proxy()
+		return
+	}
+	return
+}
+
+type scanHandler_Lost_Params struct {
+	inInstanceId []uint8
+}
+
+func (s *scanHandler_Lost_Params) Encode(encoder *bindings.Encoder) error {
+	encoder.StartStruct(8, 0)
+	if err := encoder.WritePointer(); err != nil {
+		return err
+	}
+	encoder.StartArray(uint32(len(s.inInstanceId)), 8)
+	for _, elem0 := range s.inInstanceId {
+		if err := encoder.WriteUint8(elem0); err != nil {
+			return err
+		}
+	}
+	if err := encoder.Finish(); err != nil {
+		return err
+	}
+	if err := encoder.Finish(); err != nil {
+		return err
+	}
+	return nil
+}
+
+var scanHandler_Lost_Params_Versions []bindings.DataHeader = []bindings.DataHeader{
+	bindings.DataHeader{16, 0},
+}
+
+func (s *scanHandler_Lost_Params) Decode(decoder *bindings.Decoder) error {
+	header, err := decoder.StartStruct()
+	if err != nil {
+		return err
+	}
+	index := sort.Search(len(scanHandler_Lost_Params_Versions), func(i int) bool {
+		return scanHandler_Lost_Params_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+	})
+	if index < len(scanHandler_Lost_Params_Versions) {
+		if scanHandler_Lost_Params_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+			index--
+		}
+		expectedSize := scanHandler_Lost_Params_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 {
+			return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+		} else {
+			len0, err := decoder.StartArray(8)
+			if err != nil {
+				return err
+			}
+			s.inInstanceId = make([]uint8, len0)
+			for i0 := uint32(0); i0 < len0; i0++ {
+				value1, err := decoder.ReadUint8()
+				if err != nil {
+					return err
+				}
+				s.inInstanceId[i0] = value1
+			}
+			if err := decoder.Finish(); err != nil {
+				return err
+			}
+		}
+	}
+	if err := decoder.Finish(); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (p *ScanHandler_Proxy) Lost(inInstanceId []uint8) (err error) {
+	payload := &scanHandler_Lost_Params{
+		inInstanceId,
+	}
+	header := bindings.MessageHeader{
+		Type:  scanHandler_Lost_Name,
+		Flags: bindings.MessageNoFlag,
+	}
+	var message *bindings.Message
+	if message, err = bindings.EncodeMessage(header, payload); err != nil {
+		err = fmt.Errorf("can't encode request: %v", err.Error())
+		p.Close_Proxy()
+		return
+	}
+	if err = p.router.Accept(message); err != nil {
+		p.Close_Proxy()
+		return
+	}
+	return
+}
+
+type scanHandler_Stub struct {
+	connector *bindings.Connector
+	impl      ScanHandler
+}
+
+func NewScanHandlerStub(r ScanHandler_Request, impl ScanHandler, waiter bindings.AsyncWaiter) *bindings.Stub {
+	connector := bindings.NewConnector(r.PassMessagePipe(), waiter)
+	return bindings.NewStub(connector, &scanHandler_Stub{connector, impl})
+}
+
+func (s *scanHandler_Stub) Accept(message *bindings.Message) (err error) {
+	switch message.Header.Type {
+	case scanHandler_Found_Name:
+		if message.Header.Flags != bindings.MessageNoFlag {
+			return &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+				fmt.Sprintf("invalid message header flag: %v", message.Header.Flags),
+			}
+		}
+		var request scanHandler_Found_Params
+		if err := message.DecodePayload(&request); err != nil {
+			return err
+		}
+		err = s.impl.Found(request.inS)
+		if err != nil {
+			return
+		}
+	case scanHandler_Lost_Name:
+		if message.Header.Flags != bindings.MessageNoFlag {
+			return &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+				fmt.Sprintf("invalid message header flag: %v", message.Header.Flags),
+			}
+		}
+		var request scanHandler_Lost_Params
+		if err := message.DecodePayload(&request); err != nil {
+			return err
+		}
+		err = s.impl.Lost(request.inInstanceId)
+		if err != nil {
+			return
+		}
+	default:
+		return &bindings.ValidationError{
+			bindings.MessageHeaderUnknownMethod,
+			fmt.Sprintf("unknown method %v", message.Header.Type),
+		}
+	}
+	return
+}
+
+type Service struct {
+	InstanceUuid  []uint8
+	InterfaceName string
+	Attrs         map[string]string
+	Addrs         []string
+}
+
+func (s *Service) Encode(encoder *bindings.Encoder) error {
+	encoder.StartStruct(32, 0)
+	if err := encoder.WritePointer(); err != nil {
+		return err
+	}
+	encoder.StartArray(uint32(len(s.InstanceUuid)), 8)
+	for _, elem0 := range s.InstanceUuid {
+		if err := encoder.WriteUint8(elem0); err != nil {
+			return err
+		}
+	}
+	if err := encoder.Finish(); err != nil {
+		return err
+	}
+	if err := encoder.WritePointer(); err != nil {
+		return err
+	}
+	if err := encoder.WriteString(s.InterfaceName); err != nil {
+		return err
+	}
+	if err := encoder.WritePointer(); err != nil {
+		return err
+	}
+	encoder.StartMap()
+	{
+		var keys0 []string
+		var values0 []string
+		for key0, value0 := range s.Attrs {
+			keys0 = append(keys0, key0)
+			values0 = append(values0, value0)
+		}
+		if err := encoder.WritePointer(); err != nil {
+			return err
+		}
+		encoder.StartArray(uint32(len(keys0)), 64)
+		for _, elem1 := range keys0 {
+			if err := encoder.WritePointer(); err != nil {
+				return err
+			}
+			if err := encoder.WriteString(elem1); err != nil {
+				return err
+			}
+		}
+		if err := encoder.Finish(); err != nil {
+			return err
+		}
+		if err := encoder.WritePointer(); err != nil {
+			return err
+		}
+		encoder.StartArray(uint32(len(values0)), 64)
+		for _, elem1 := range values0 {
+			if err := encoder.WritePointer(); err != nil {
+				return err
+			}
+			if err := encoder.WriteString(elem1); err != nil {
+				return err
+			}
+		}
+		if err := encoder.Finish(); err != nil {
+			return err
+		}
+	}
+	if err := encoder.Finish(); err != nil {
+		return err
+	}
+	if err := encoder.WritePointer(); err != nil {
+		return err
+	}
+	encoder.StartArray(uint32(len(s.Addrs)), 64)
+	for _, elem0 := range s.Addrs {
+		if err := encoder.WritePointer(); err != nil {
+			return err
+		}
+		if err := encoder.WriteString(elem0); err != nil {
+			return err
+		}
+	}
+	if err := encoder.Finish(); err != nil {
+		return err
+	}
+	if err := encoder.Finish(); err != nil {
+		return err
+	}
+	return nil
+}
+
+var service_Versions []bindings.DataHeader = []bindings.DataHeader{
+	bindings.DataHeader{40, 0},
+}
+
+func (s *Service) Decode(decoder *bindings.Decoder) error {
+	header, err := decoder.StartStruct()
+	if err != nil {
+		return err
+	}
+	index := sort.Search(len(service_Versions), func(i int) bool {
+		return service_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+	})
+	if index < len(service_Versions) {
+		if service_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+			index--
+		}
+		expectedSize := service_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 {
+			return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+		} else {
+			len0, err := decoder.StartArray(8)
+			if err != nil {
+				return err
+			}
+			s.InstanceUuid = make([]uint8, len0)
+			for i0 := uint32(0); i0 < len0; i0++ {
+				value1, err := decoder.ReadUint8()
+				if err != nil {
+					return err
+				}
+				s.InstanceUuid[i0] = value1
+			}
+			if err := decoder.Finish(); err != nil {
+				return err
+			}
+		}
+	}
+	if header.ElementsOrVersion >= 0 {
+		pointer0, err := decoder.ReadPointer()
+		if err != nil {
+			return err
+		}
+		if pointer0 == 0 {
+			return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+		} else {
+			value0, err := decoder.ReadString()
+			if err != nil {
+				return err
+			}
+			s.InterfaceName = value0
+		}
+	}
+	if header.ElementsOrVersion >= 0 {
+		pointer0, err := decoder.ReadPointer()
+		if err != nil {
+			return err
+		}
+		if pointer0 == 0 {
+			return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+		} else {
+			if err := decoder.StartMap(); err != nil {
+				return err
+			}
+			var keys0 []string
+			{
+				pointer1, err := decoder.ReadPointer()
+				if err != nil {
+					return err
+				}
+				if pointer1 == 0 {
+					return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+				} else {
+					len1, err := decoder.StartArray(64)
+					if err != nil {
+						return err
+					}
+					keys0 = make([]string, len1)
+					for i1 := uint32(0); i1 < len1; i1++ {
+						pointer2, err := decoder.ReadPointer()
+						if err != nil {
+							return err
+						}
+						if pointer2 == 0 {
+							return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+						} else {
+							value2, err := decoder.ReadString()
+							if err != nil {
+								return err
+							}
+							keys0[i1] = value2
+						}
+					}
+					if err := decoder.Finish(); err != nil {
+						return err
+					}
+				}
+			}
+			var values0 []string
+			{
+				pointer1, err := decoder.ReadPointer()
+				if err != nil {
+					return err
+				}
+				if pointer1 == 0 {
+					return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+				} else {
+					len1, err := decoder.StartArray(64)
+					if err != nil {
+						return err
+					}
+					values0 = make([]string, len1)
+					for i1 := uint32(0); i1 < len1; i1++ {
+						pointer2, err := decoder.ReadPointer()
+						if err != nil {
+							return err
+						}
+						if pointer2 == 0 {
+							return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+						} else {
+							value2, err := decoder.ReadString()
+							if err != nil {
+								return err
+							}
+							values0[i1] = value2
+						}
+					}
+					if err := decoder.Finish(); err != nil {
+						return err
+					}
+				}
+			}
+			if len(keys0) != len(values0) {
+				return &bindings.ValidationError{bindings.DifferentSizedArraysInMap,
+					fmt.Sprintf("Number of keys %d is different from number of values %d", len(keys0), len(values0)),
+				}
+			}
+			if err := decoder.Finish(); err != nil {
+				return err
+			}
+			len0 := len(keys0)
+			map0 := make(map[string]string)
+			for i0 := 0; i0 < len0; i0++ {
+				map0[keys0[i0]] = values0[i0]
+			}
+			s.Attrs = map0
+		}
+	}
+	if header.ElementsOrVersion >= 0 {
+		pointer0, err := decoder.ReadPointer()
+		if err != nil {
+			return err
+		}
+		if pointer0 == 0 {
+			return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+		} else {
+			len0, err := decoder.StartArray(64)
+			if err != nil {
+				return err
+			}
+			s.Addrs = make([]string, len0)
+			for i0 := uint32(0); i0 < len0; i0++ {
+				pointer1, err := decoder.ReadPointer()
+				if err != nil {
+					return err
+				}
+				if pointer1 == 0 {
+					return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+				} else {
+					value1, err := decoder.ReadString()
+					if err != nil {
+						return err
+					}
+					s.Addrs[i0] = value1
+				}
+			}
+			if err := decoder.Finish(); err != nil {
+				return err
+			}
+		}
+	}
+	if err := decoder.Finish(); err != nil {
+		return err
+	}
+	return nil
+}
+
+type Error struct {
+	Id     string
+	Action int32
+	Msg    string
+}
+
+func (s *Error) Encode(encoder *bindings.Encoder) error {
+	encoder.StartStruct(24, 0)
+	if err := encoder.WritePointer(); err != nil {
+		return err
+	}
+	if err := encoder.WriteString(s.Id); err != nil {
+		return err
+	}
+	if err := encoder.WriteInt32(s.Action); err != nil {
+		return err
+	}
+	if err := encoder.WritePointer(); err != nil {
+		return err
+	}
+	if err := encoder.WriteString(s.Msg); err != nil {
+		return err
+	}
+	if err := encoder.Finish(); err != nil {
+		return err
+	}
+	return nil
+}
+
+var error_Versions []bindings.DataHeader = []bindings.DataHeader{
+	bindings.DataHeader{32, 0},
+}
+
+func (s *Error) Decode(decoder *bindings.Decoder) error {
+	header, err := decoder.StartStruct()
+	if err != nil {
+		return err
+	}
+	index := sort.Search(len(error_Versions), func(i int) bool {
+		return error_Versions[i].ElementsOrVersion >= header.ElementsOrVersion
+	})
+	if index < len(error_Versions) {
+		if error_Versions[index].ElementsOrVersion > header.ElementsOrVersion {
+			index--
+		}
+		expectedSize := error_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 {
+			return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+		} else {
+			value0, err := decoder.ReadString()
+			if err != nil {
+				return err
+			}
+			s.Id = value0
+		}
+	}
+	if header.ElementsOrVersion >= 0 {
+		value0, err := decoder.ReadInt32()
+		if err != nil {
+			return err
+		}
+		s.Action = value0
+	}
+	if header.ElementsOrVersion >= 0 {
+		pointer0, err := decoder.ReadPointer()
+		if err != nil {
+			return err
+		}
+		if pointer0 == 0 {
+			return &bindings.ValidationError{bindings.UnexpectedNullPointer, "unexpected null pointer"}
+		} else {
+			value0, err := decoder.ReadString()
+			if err != nil {
+				return err
+			}
+			s.Msg = value0
+		}
+	}
+	if err := decoder.Finish(); err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/go/src/vanadium/discovery/discovery.go b/go/src/vanadium/discovery/discovery.go
new file mode 100644
index 0000000..62d27d8
--- /dev/null
+++ b/go/src/vanadium/discovery/discovery.go
@@ -0,0 +1,116 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"v.io/v23"
+	discovery_factory "v.io/x/ref/lib/discovery/factory"
+
+	_ "v.io/x/ref/runtime/factories/generic"
+
+	mojom "mojom/vanadium/discovery"
+	"vanadium/discovery/internal"
+
+	"mojo/public/go/application"
+	"mojo/public/go/bindings"
+	"mojo/public/go/system"
+	"sync"
+	"v.io/v23/context"
+)
+
+//#include "mojo/public/c/system/types.h"
+import "C"
+
+type discoveryDelegate struct {
+	// mu protects stubs.  All calls to methods on the delegate by
+	// mojo will be done in the same goroutine.  We need mu so
+	// we can clean up stubs that fail because of pipe errors because
+	// each stub serves all its requests in its own goroutine.
+	mu    sync.Mutex
+	stubs map[*bindings.Stub]struct{}
+
+	ctx      *context.T
+	impl     *internal.DiscoveryService
+	shutdown v23.Shutdown
+}
+
+func (d *discoveryDelegate) Initialize(c application.Context) {
+	// TODO(bjornick): Calling init multiple times in the same process
+	// will be bad.  For now, this is ok because this is the only
+	// vanadium service that will be used in the demos and each go library
+	// will be in its own process.
+	ctx, shutdown := v23.Init()
+
+	inst, err := discovery_factory.New(c.Args()[2:]...)
+	if err != nil {
+		ctx.Fatalf("failed to initalize discovery: %v", err)
+	}
+
+	d.impl = internal.NewDiscoveryService(ctx, inst)
+	d.shutdown = shutdown
+}
+
+func (d *discoveryDelegate) addAndServeStub(stub *bindings.Stub) {
+	d.mu.Lock()
+	d.stubs[stub] = struct{}{}
+	d.mu.Unlock()
+	go func() {
+		for {
+			if err := stub.ServeRequest(); err != nil {
+				connectionErr, ok := err.(*bindings.ConnectionError)
+				if !ok || !connectionErr.Closed() {
+					d.ctx.Error(err)
+				}
+				break
+			}
+		}
+		d.mu.Lock()
+		delete(d.stubs, stub)
+		d.mu.Unlock()
+	}()
+}
+
+type advertiseFactory struct {
+	d *discoveryDelegate
+}
+
+func (a *advertiseFactory) Create(request mojom.Advertiser_Request) {
+	stub := mojom.NewAdvertiserStub(request, a.d.impl, bindings.GetAsyncWaiter())
+	a.d.addAndServeStub(stub)
+}
+
+type scannerFactory struct {
+	d *discoveryDelegate
+}
+
+func (s *scannerFactory) Create(request mojom.Scanner_Request) {
+	stub := mojom.NewScannerStub(request, s.d.impl, bindings.GetAsyncWaiter())
+	s.d.addAndServeStub(stub)
+}
+
+func (d *discoveryDelegate) AcceptConnection(connection *application.Connection) {
+	advFactory := &advertiseFactory{d: d}
+	scanFactory := &scannerFactory{d: d}
+	connection.ProvideServices(&mojom.Advertiser_ServiceFactory{advFactory}, &mojom.Scanner_ServiceFactory{scanFactory})
+}
+
+func (d *discoveryDelegate) Quit() {
+	d.impl.StopAll()
+	d.shutdown()
+	d.mu.Lock()
+	for stub := range d.stubs {
+		stub.Close()
+	}
+	d.mu.Unlock()
+}
+
+//export MojoMain
+func MojoMain(handle C.MojoHandle) C.MojoResult {
+	application.Run(&discoveryDelegate{stubs: map[*bindings.Stub]struct{}{}}, system.MojoHandle(handle))
+	return C.MOJO_RESULT_OK
+}
+
+func main() {
+}
diff --git a/go/src/vanadium/discovery/internal/discovery.go b/go/src/vanadium/discovery/internal/discovery.go
new file mode 100644
index 0000000..59da5fa
--- /dev/null
+++ b/go/src/vanadium/discovery/internal/discovery.go
@@ -0,0 +1,169 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package internal
+
+import (
+	"sync"
+
+	"v.io/v23/context"
+	"v.io/v23/discovery"
+	"v.io/v23/verror"
+
+	"mojo/public/go/bindings"
+	mojom "mojom/vanadium/discovery"
+	"v.io/v23/security"
+)
+
+type id uint32
+
+// DiscoveryService implements the mojom interface mojom/vanadium/discovery.DiscoveryService.  It
+// is basically a thin wrapper around the Vanadium Discovery API.
+type DiscoveryService struct {
+	ctx *context.T
+	s   discovery.T
+
+	// mu protects pending* and next*
+	mu sync.Mutex
+
+	// The id to assign the next advertisement.
+	nextAdv id
+	// A map of advertisement ids to the cancellation function.
+	activeAdvs map[id]func()
+	// The id to assign to the next scan.
+	nextScan id
+	// A map of scan id to the cancellataion func()
+	activeScans map[id]func()
+}
+
+func v2mError(err error) *mojom.Error {
+	return &mojom.Error{
+		Id:     string(verror.ErrorID(err)),
+		Action: int32(verror.Action(err)),
+		Msg:    err.Error(),
+	}
+}
+
+// NewDiscoveryService returns a new DiscoveryService bound to the context and the Vanadium
+// Discovery implementation passed in.
+func NewDiscoveryService(ctx *context.T, vDiscovery discovery.T) *DiscoveryService {
+	return &DiscoveryService{
+		ctx:         ctx,
+		s:           vDiscovery,
+		nextAdv:     1,
+		activeAdvs:  map[id]func(){},
+		activeScans: map[id]func(){},
+	}
+}
+
+// Advertise advertises the mojom service passed only to the giveen blessing patterns. Returns the
+// handle to this Advertise call.
+func (d *DiscoveryService) Advertise(s mojom.Service, patterns []string) (uint32, *mojom.Error, error) {
+	vService := discovery.Service{
+		InstanceUuid:  s.InstanceUuid,
+		InterfaceName: s.InterfaceName,
+		Attrs:         discovery.Attributes(s.Attrs),
+		Addrs:         s.Addrs,
+	}
+
+	ctx, cancel := context.WithCancel(d.ctx)
+
+	perms := make([]security.BlessingPattern, len(patterns))
+	for i, pattern := range patterns {
+		perms[i] = security.BlessingPattern(pattern)
+	}
+	err := d.s.Advertise(ctx, vService, perms)
+	if err != nil {
+		cancel()
+		return 0, v2mError(err), nil
+	}
+	d.mu.Lock()
+	currId := d.nextAdv
+	d.activeAdvs[currId] = cancel
+	d.nextAdv += 2
+	d.mu.Unlock()
+	return uint32(currId), nil, nil
+}
+
+func (d *DiscoveryService) stopAdvertising(handle uint32) error {
+	d.mu.Lock()
+	cancel := d.activeAdvs[id(handle)]
+	delete(d.activeAdvs, id(handle))
+	d.mu.Unlock()
+	if cancel != nil {
+		cancel()
+	}
+	return nil
+}
+
+func v2mService(s discovery.Service) mojom.Service {
+	return mojom.Service{
+		InstanceUuid:  s.InstanceUuid,
+		InterfaceName: s.InterfaceName,
+		Attrs:         s.Attrs,
+		Addrs:         s.Addrs,
+	}
+}
+
+// Scan scans for all services that match the query string passed in and calls scanHandler with updates.
+// Returns the handle to this Scan.
+func (d *DiscoveryService) Scan(query string, scanHandler mojom.ScanHandler_Pointer) (uint32, *mojom.Error, error) {
+	ctx, cancel := context.WithCancel(d.ctx)
+	scanCh, err := d.s.Scan(ctx, query)
+	if err != nil {
+		cancel()
+		return 0, v2mError(err), nil
+	}
+	d.mu.Lock()
+	currId := d.nextScan
+	d.activeScans[currId] = cancel
+	d.nextScan += 2
+	d.mu.Unlock()
+
+	go func() {
+		proxy := mojom.NewScanHandlerProxy(scanHandler, bindings.GetAsyncWaiter())
+		for v := range scanCh {
+			switch value := v.(type) {
+			case discovery.UpdateFound:
+				proxy.Found(v2mService(value.Value.Service))
+			case discovery.UpdateLost:
+				proxy.Lost(value.Value.InstanceUuid)
+			}
+		}
+	}()
+	return uint32(currId), nil, nil
+}
+
+// Stop stops the scan.
+func (d *DiscoveryService) Stop(handle uint32) error {
+	if handle % 2 == 0 {
+		return d.stopScan(handle)
+	}
+	return d.stopAdvertising(handle)
+}
+
+func (d *DiscoveryService) stopScan(handle uint32) error {
+	d.mu.Lock()
+	cancel := d.activeScans[id(handle)]
+	delete(d.activeScans, id(handle))
+	d.mu.Unlock()
+	if cancel != nil {
+		cancel()
+	}
+	return nil
+}
+
+// Stop Stops all scans and advertisements.
+func (d *DiscoveryService) StopAll() {
+	d.mu.Lock()
+	for _, cancel := range d.activeScans {
+		cancel()
+	}
+
+	for _, cancel := range d.activeAdvs {
+		cancel()
+	}
+	d.s.Close()
+	d.mu.Unlock()
+}
diff --git a/go/src/vanadium/discovery/internal/discovery_test.go b/go/src/vanadium/discovery/internal/discovery_test.go
new file mode 100644
index 0000000..585eb48
--- /dev/null
+++ b/go/src/vanadium/discovery/internal/discovery_test.go
@@ -0,0 +1,133 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package internal
+
+import (
+	"reflect"
+	"testing"
+
+	"v.io/v23/context"
+	"v.io/v23/discovery"
+	idiscovery "v.io/x/ref/lib/discovery"
+	vtest "v.io/x/ref/test"
+
+	_ "v.io/x/ref/runtime/factories/generic"
+
+	mojom "mojom/vanadium/discovery"
+	"sync"
+	"third_party/go/tool/android_arm/src/fmt"
+	"v.io/v23/security"
+)
+
+type mockAdv struct {
+	s discovery.Service
+}
+
+type discoveryMock struct {
+	mu       sync.Mutex
+	trigger  *idiscovery.Trigger
+	id       int64
+	services map[int64]discovery.Service
+	// An item will be put in deleteCh when something has been deleted.
+	deleteCh chan struct{}
+}
+
+func (d *discoveryMock) Advertise(ctx *context.T, s discovery.Service, perms []security.BlessingPattern) error {
+	d.mu.Lock()
+	currId := d.id
+	d.services[currId] = s
+	d.id++
+	d.mu.Unlock()
+	c := func() {
+		d.mu.Lock()
+		delete(d.services, currId)
+		d.mu.Unlock()
+		d.deleteCh <- struct{}{}
+	}
+	d.trigger.Add(c, ctx.Done())
+	return nil
+}
+
+func (*discoveryMock) Scan(ctx *context.T, query string) (<-chan discovery.Update, error) {
+	return nil, nil
+}
+
+func (*discoveryMock) Close() {}
+
+func compare(want discovery.Service, got mojom.Service) error {
+	mwant := v2mService(want)
+	if !reflect.DeepEqual(mwant, got) {
+		return fmt.Errorf("Got %#v want %#v", got, want)
+	}
+	return nil
+}
+
+func TestAdvertising(t *testing.T) {
+	ctx, shutdown := vtest.V23Init()
+	defer shutdown()
+	mock := &discoveryMock{
+		trigger:  idiscovery.NewTrigger(),
+		services: map[int64]discovery.Service{},
+		deleteCh: make(chan struct{}),
+	}
+	s := NewDiscoveryService(ctx, mock)
+	testService := mojom.Service{
+		InterfaceName: "v.io/v23/discovery.T",
+		Attrs: map[string]string{
+			"key1": "value1",
+			"key2": "value2",
+		},
+		Addrs: []string{"addr1", "addr2"},
+	}
+	id, e1, e2 := s.Advertise(testService, nil)
+
+	if e1 != nil || e2 != nil {
+		t.Fatalf("Failed to start service: %v, %v", e1, e2)
+	}
+	if len(mock.services) != 1 {
+		t.Errorf("service missing in mock")
+	}
+
+	for _, service := range mock.services {
+		if err := compare(service, testService); err != nil {
+			t.Error(err)
+		}
+
+	}
+
+	testService2 := mojom.Service{
+		InterfaceName: "v.io/v23/naming.T",
+		Attrs: map[string]string{
+			"key1": "value1",
+			"key2": "value2",
+		},
+		Addrs: []string{"addr1", "addr2"},
+	}
+
+	_, e1, e2 = s.Advertise(testService2, nil)
+	if e1 != nil || e2 != nil {
+		t.Fatalf("Failed to start service: %v, %v", e1, e2)
+	}
+
+	s.Stop(id)
+	// Wait for the deletion to finish.
+	<-mock.deleteCh
+	if len(mock.services) != 1 {
+		t.Errorf("service should have been removed")
+	}
+
+	for _, service := range mock.services {
+		if err := compare(service, testService2); err != nil {
+			t.Error(err)
+		}
+
+	}
+
+	s.StopAll()
+	<-mock.deleteCh
+	if len(mock.services) != 0 {
+		t.Errorf("service should have been removed")
+	}
+}
diff --git a/mojoconfig b/mojoconfig
new file mode 100644
index 0000000..9e2c0d5
--- /dev/null
+++ b/mojoconfig
@@ -0,0 +1,14 @@
+# Derived from $MOJO_DIR/mojoconfig.
+
+{
+  'dev_servers': [
+    {
+      'host': 'https://mojo.v.io/',
+      'mappings': [
+        ('', [
+          '@{DISCOVERY_BUILD_DIR}',
+        ]),
+      ],
+    },
+  ],
+}
diff --git a/mojom/vanadium/discovery.mojom b/mojom/vanadium/discovery.mojom
new file mode 100644
index 0000000..1114bfe
--- /dev/null
+++ b/mojom/vanadium/discovery.mojom
@@ -0,0 +1,60 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+module discovery;
+
+// Copied from v.io/v23/discovery/types.vdl
+struct Service {
+    // The 128 bit (16 byte) universal unique identifier of a service instance.
+	// If this is not specified, a random UUID will be used.
+	array<uint8> InstanceUuid;
+	// The interface that the service implements.
+	// E.g., 'v.io/v23/services/vtrace.Store'.
+	string InterfaceName;
+	// The service attributes.
+	// E.g., {'resolution': '1024x768'}.
+	map<string, string> Attrs;
+	// The addresses that the service is served on.
+	// E.g., '/host:port/a/b/c'.
+	array<string> Addrs;
+};
+
+struct Error {
+   string id;
+   int32 action;
+   string msg;
+};
+
+// Advertiser provides methods to do Vanadium Advertising.
+interface Advertiser {
+    // Advertise advertises the service to be discovered by "Scanner" implementations.
+	// visibility is used to limit the principals that can see the advertisement. An
+	// empty set means that there are no restrictions on visibility (i.e, equivalent
+	// to []security.BlessingPattern{security.AllPrincipals}). Advertising will continue
+	// until the context is canceled or exceeds its deadline.
+	Advertise(Service s, array<string> visibility) => (uint32 Handle, Error? Err);
+
+	// Stop Stops the advertisement associated with the given handle.
+	Stop(uint32 h);
+};
+
+// Scanner provides methods to scan for Vanadium advertisements.
+interface Scanner {
+	// Scan scans for services matching the query passed nad calls ScanHandler with updates.
+	// Returns a handle to the active scanner that can be used to stop the scanning.
+	Scan(string query, ScanHandler scanHandler) => (uint32 Handle, Error? Err);
+
+	// StopScan stops the scanner associated weith the given handle.
+	Stop(uint32 h);
+};
+
+// ScanHandler is used to pass updates about Services that are found/lost during the
+// scan.
+interface ScanHandler {
+	// Found will be called when a Service is found.
+	Found(Service s);
+
+	// Lost will be called when a service is lost.
+	Lost(array<uint8> instanceId);
+};
\ No newline at end of file