veyron/lib/bluetooth,veyron/runtimes/google/ipc/stream: Support for VCs
created over bluetooth RFCOMM connections on Linux.

This commit enables Linux-based veyron processes to use bluetooth to
establish VCs between each other. For example, to create a tunnel
(veyron/examples/tunnel), the server can be started with:

./bin/tunneld --protocol=bluetooth --address=00:00:00:00:00:00-0

A client can then transparently connect to this server via bluetooth
by simply connecting to the object name exported by the server.

For non-linux platforms, currently connections to bluetooth-based
endpoints will fail.

Tested using raspberry pi's and my linux desktop.

Specific changes:
(1) bluetooth net.Addr implementation now uses a "-" instead of a "/"
    to separate the MAC address from the channel id since the "/"
    confuses object name parsing (veyron2/naming)
(2) Hook up the bluetooth package's net.Conn implementation with
    veyron/runtimes/google/ipc/stream.
(3) Return string descriptions of error messages in addition
    to errno from bt.c
(4) Ensure that the net.Conn implementation returns n=0 on
    failures to Read/Write. io.Reader/io.Writer implementations
    are supposed to do this and clients (such as iobuf.Reader)
    rely on non-negative return values.
(5) rename "port" to "channel" to more closely reflect RFCOMM
    terminology

While this commit enables bluetooth support, there are still caveats
to it:
(1) Only works with Linux
(2) the net.Conn and net.Listener implementations are not safe for
    concurrent method invocations, which they should be (as per the
    interface guidelines).
and thus bluetooth should only be used for toys right now, till
these problems, particularly (2) are addressed.

Change-Id: Iebdc7a6062133dc5a7f9a3c4871042083388160e
diff --git a/lib/bluetooth/addr.go b/lib/bluetooth/addr.go
index cc387ba..70e5392 100644
--- a/lib/bluetooth/addr.go
+++ b/lib/bluetooth/addr.go
@@ -8,12 +8,16 @@
 	"strings"
 )
 
-// addr represents one bluetooth address in the <MAC:port> format, where
-// port denotes one of the available bluetooth channels (1-30).
+// Network string for net.Addr implementations used by the bluetooth package.
+const Network = "bluetooth"
+
+// addr represents an RFCOMM over bluetooth address in the <MAC-channelID>
+// format, where channelID denotes one of the available RFCOMM channels.
+//
 // It implements the net.Addr interface.
 type addr struct {
-	mac  net.HardwareAddr
-	port int
+	mac     net.HardwareAddr
+	channel int
 }
 
 // anyMAC is a MAC address "00:00:00:00:00:00", which means first available
@@ -27,44 +31,44 @@
 	}
 }
 
-// parseAddress parses an address string in the <MAC/Port> format (e.g.,
-// "01:23:45:67:89:AB/1").  It returns an error if the address is in the wrong
+// parseAddress parses an address string in the <MAC-channelID> format (e.g.,
+// "01:23:45:67:89:AB-1").  It returns an error if the address is in the wrong
 // format.  It is legal for a MAC address sub-part to be empty, in which case
 // it will be treated as anyMAC (i.e., "00:00:00:00:00:00").
 func parseAddress(address string) (*addr, error) {
-	parts := strings.Split(address, "/")
+	parts := strings.Split(address, "-")
 	if len(parts) != 2 {
-		return nil, fmt.Errorf("too many or too few \"/\" in address: %s", address)
+		return nil, fmt.Errorf("too many or too few \"-\" in address: %s", address)
 	}
 	ms := parts[0]
 	ps := parts[1]
 	if len(ms) == 0 {
-		port, err := strconv.ParseInt(ps, 0, 32)
+		channel, err := strconv.ParseInt(ps, 0, 32)
 		if err != nil {
 			return nil, err
 		}
-		return &addr{anyMAC, int(port)}, nil
+		return &addr{anyMAC, int(channel)}, nil
 	} else {
 		mac, err := net.ParseMAC(ms)
 		if err != nil {
 			return nil, err
 		}
-		port, err := strconv.ParseInt(ps, 0, 32)
+		channel, err := strconv.ParseInt(ps, 0, 32)
 		if err != nil {
 			return nil, err
 		}
-		return &addr{mac, int(port)}, nil
+		return &addr{mac, int(channel)}, nil
 	}
 }
 
 // Implements the net.Addr interface.
 func (a *addr) Network() string {
-	return "bluetooth"
+	return Network
 }
 
 // Implements the net.Addr interface.
 func (a *addr) String() string {
-	return fmt.Sprintf("%s/%d", a.mac, a.port)
+	return fmt.Sprintf("%s-%d", a.mac, a.channel)
 }
 
 // isAnyMAC returns true iff the mac address is "any" (i.e.,
diff --git a/lib/bluetooth/addr_test.go b/lib/bluetooth/addr_test.go
new file mode 100644
index 0000000..e581bbe
--- /dev/null
+++ b/lib/bluetooth/addr_test.go
@@ -0,0 +1,33 @@
+package bluetooth
+
+import "testing"
+
+func TestParseValidAddr(t *testing.T) {
+	testdata := []struct{ before, after string }{
+		{"-1", "00:00:00:00:00:00-1"},
+		{"0A:0B:33:55:C9:9a-8", "0a:0b:33:55:c9:9a-8"},
+	}
+	for _, d := range testdata {
+		addr, err := parseAddress(d.before)
+		if err != nil {
+			t.Errorf("failed to parse %q: %v", d.before, err)
+			continue
+		}
+		if got, want := addr.String(), d.after; got != want {
+			t.Errorf("Got %q, want %q", got, want)
+		}
+	}
+}
+
+func TestParseInvalidAddr(t *testing.T) {
+	testdata := []string{
+		"00:01:02:03:04:05",      // missing channel
+		"00:01:02:03:04:05:06-1", // invalid MAC addr
+	}
+	for _, d := range testdata {
+		addr, err := parseAddress(d)
+		if err == nil {
+			t.Errorf("Got %q, want error for parseAddress(%q)", addr, d)
+		}
+	}
+}
diff --git a/lib/bluetooth/bluetooth.go b/lib/bluetooth/bluetooth_linux.go
similarity index 91%
rename from lib/bluetooth/bluetooth.go
rename to lib/bluetooth/bluetooth_linux.go
index 208858b..10c4346 100644
--- a/lib/bluetooth/bluetooth.go
+++ b/lib/bluetooth/bluetooth_linux.go
@@ -1,7 +1,5 @@
 // +build linux
 
-// Package bluetooth provides methods for interacting with attached bluetooth
-// devices.
 package bluetooth
 
 import (
@@ -35,9 +33,9 @@
 	// https://www.bluetooth.org/en-us/specification/adopted-specifications
 	MaxLEAdvertisingPayloadSize = int(C.kMaxLEPayloadSize)
 
-	// MaxPort represents the highest bluetooth port that can be used
+	// MaxChannel represents the highest channel id that can be used
 	// for establishing RFCOMM connections.
-	MaxPort = int(C.kMaxPort)
+	MaxChannel = int(C.kMaxChannel)
 
 	// maxDevices denotes a maximum number of local devices to scan over
 	// when a particular device isn't explicitly specified (e.g.,
@@ -84,9 +82,9 @@
 }
 
 // Listen creates a new listener for RFCOMM connections on the provided
-// local address, specified in the <MAC/Port> format (e.g.,
-// "01:23:45:67:89:AB/1").  Port number 0 means pick the first available
-// port.  Empty MAC address means pick the first available bluetooth device.
+// local address, specified in the <MAC-Channel> format (e.g.,
+// "01:23:45:67:89:AB-1").  Channel number 0 means pick the first available
+// channel.  Empty MAC address means pick the first available bluetooth device.
 // Error is returned if a listener cannot be created.
 // Note that the returned net.Listener won't use the runtime network poller
 // and hence a new OS thread will be created for every outstanding connection.
@@ -95,8 +93,8 @@
 	if err != nil {
 		return nil, fmt.Errorf("listen error: invalid local address format %s, error: %s", localAddr, err)
 	}
-	if local.port > MaxPort {
-		return nil, fmt.Errorf("listen error: port %d too large - max: %d", local.port, MaxPort)
+	if local.channel > MaxChannel {
+		return nil, fmt.Errorf("listen error: channel %d too large - max: %d", local.channel, MaxChannel)
 	}
 
 	// Open a new local bluetooth socket.
@@ -111,17 +109,18 @@
 		localMAC = C.CString(local.mac.String())
 	}
 	defer C.free(unsafe.Pointer(localMAC))
-	localPort := C.int(local.port)
-	if es := C.bt_bind(socket, &localMAC, &localPort); es != nil {
+	localChannel := C.int(local.channel)
+	if es := C.bt_bind(socket, &localMAC, &localChannel); es != nil {
 		defer C.free(unsafe.Pointer(es))
 		syscall.Close(int(socket))
 		return nil, fmt.Errorf("listen error: %v", C.GoString(es))
 	}
 	// Re-parse the address as it may have changed.
 	if local.mac, err = net.ParseMAC(C.GoString(localMAC)); err != nil {
+		syscall.Close(int(socket))
 		return nil, fmt.Errorf("listen error: invalid local MAC address: %s, err: %v", C.GoString(localMAC), err)
 	}
-	local.port = int(localPort)
+	local.channel = int(localChannel)
 
 	// Create a listener for incoming connections.
 	const maxPendingConnections = 100
@@ -137,7 +136,7 @@
 }
 
 // Dial creates a new RFCOMM connection with the remote address, specified in
-// the <MAC/Port> format (e.g., "01:23:45:67:89:AB/1").  It returns an error
+// the <MAC/Channel> format (e.g., "01:23:45:67:89:AB-1").  It returns an error
 // if the connection cannot be established.
 // Note that the returned net.Conn won't use the runtime network poller and
 // hence a new OS thread will be created for every outstanding connection.
@@ -149,8 +148,8 @@
 	if remote.isAnyMAC() {
 		return nil, fmt.Errorf("dial error: must specify remote MAC address: %s", remoteAddr)
 	}
-	if remote.port > MaxPort {
-		return nil, fmt.Errorf("dial error: port %d too large - max: %d", remote.port, MaxPort)
+	if remote.channel > MaxChannel {
+		return nil, fmt.Errorf("dial error: channel %d too large - max: %d", remote.channel, MaxChannel)
 	}
 
 	// Open a new local bluetooth socket.
@@ -160,9 +159,9 @@
 	}
 
 	// Bind to the local socket.
-	var localMAC *C.char  // bind to first available device
-	localPort := C.int(0) // bind to first available port
-	if es := C.bt_bind(socket, &localMAC, &localPort); es != nil {
+	var localMAC *C.char     // bind to first available device
+	localChannel := C.int(0) // bind to first available channel
+	if es := C.bt_bind(socket, &localMAC, &localChannel); es != nil {
 		defer C.free(unsafe.Pointer(es))
 		syscall.Close(int(socket))
 		return nil, fmt.Errorf("dial error: %v", C.GoString(es))
@@ -173,13 +172,13 @@
 	if local.mac, err = net.ParseMAC(C.GoString(localMAC)); err != nil {
 		return nil, fmt.Errorf("dial error: invalid local MAC address: %s, err: %s", C.GoString(localMAC), err)
 	}
-	local.port = int(localPort)
+	local.channel = int(localChannel)
 
 	// Connect to the remote address.
 	remoteMAC := C.CString(remote.mac.String())
 	defer C.free(unsafe.Pointer(remoteMAC))
-	remotePort := C.int(remote.port)
-	if es := C.bt_connect(socket, remoteMAC, remotePort); es != nil {
+	remoteChannel := C.int(remote.channel)
+	if es := C.bt_connect(socket, remoteMAC, remoteChannel); es != nil {
 		defer C.free(unsafe.Pointer(es))
 		return nil, fmt.Errorf("dial error: error connecting to remote address: %s, error: %s", remoteAddr, C.GoString(es))
 	}
diff --git a/lib/bluetooth/bluetooth_other.go b/lib/bluetooth/bluetooth_other.go
new file mode 100644
index 0000000..fa75d80
--- /dev/null
+++ b/lib/bluetooth/bluetooth_other.go
@@ -0,0 +1,20 @@
+// +build !linux
+
+package bluetooth
+
+import (
+	"errors"
+	"net"
+)
+
+// Dial always returns an error since bluetooth RFCOMM is not implemented on this
+// platform.
+func Dial(remoteaddr string) (net.Conn, error) {
+	return nil, errors.New("bluetooth Dialing not implemented on this platform")
+}
+
+// Listen always returns an error since bluetooth RFCOMM is not implemented on
+// this platform.
+func Listen(localaddr string) (net.Listener, error) {
+	return nil, errors.New("bluetooth Listening not implemented on this platform")
+}
diff --git a/lib/bluetooth/bt.c b/lib/bluetooth/bt.c
index 0584498..1dde981 100644
--- a/lib/bluetooth/bt.c
+++ b/lib/bluetooth/bt.c
@@ -5,6 +5,7 @@
 #include <assert.h>
 #include <errno.h>
 #include <stdio.h>
+#include <string.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
 #include <sys/select.h>
@@ -31,7 +32,7 @@
 static const int kMaxAddrStrSize = 18;
 
 const int kMaxLEPayloadSize = 26;
-const int kMaxPort = 30;
+const int kMaxChannel = 30;
 const int kMaxDevices = 5;
 
 char* bt_open_device(int dev_id, int* dd, char** name, char** local_address) {
@@ -48,14 +49,14 @@
 
   // Open HCI socket.
   if ((sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) {
-    asprintf(&err, "can't open HCI socket, error: %d", errno);
+    asprintf(&err, "can't open HCI socket:%d[%s]", errno, strerror(errno));
     return err;
   }
 
   // Get device's name.
   di.dev_id = dev_id;
   if (ioctl(sock, HCIGETDEVINFO, (void *)&di) < 0) {
-    asprintf(&err, "can't get device info, error: %d", errno);
+    asprintf(&err, "can't get device info:%d[%s]", errno, strerror(errno));
     close(sock);
     return err;
   }
@@ -66,7 +67,7 @@
   ioctl(sock, HCIDEVUP, dev_id);
   *dd = hci_open_dev(dev_id);
   if (*dd < 0) {
-    asprintf(&err, "can't open device %d. error: %d", dev_id, errno);
+    asprintf(&err, "can't open device %d:%d[%s]", dev_id, errno, strerror(errno));
     close(sock);
     return err;
   }
@@ -83,7 +84,7 @@
   return NULL;
 }
 
-char* bt_bind(int sock, char** local_address, int* port) {
+char* bt_bind(int sock, char** local_address, int* channel) {
   char* err = NULL;
   int dev_id, dd;
   struct sockaddr_rc addr = { 0 };
@@ -98,7 +99,7 @@
       }
       bt_close_device(dd);
       assert(*local_address != NULL);
-      if ((err = bt_bind(sock, local_address, port)) != NULL) {
+      if ((err = bt_bind(sock, local_address, channel)) != NULL) {
         free(err);
         free(*local_address);
         continue;
@@ -107,24 +108,24 @@
     }
     asprintf(&err, "can't find an available bluetooth device");
     return err;
-  } else if (*port == 0) {
-    // Find the first available port.
-    for (*port = 1; *port < kMaxPort; (*port)++) {
-      if ((err = bt_bind(sock, local_address, port)) != NULL) {
+  } else if (*channel == 0) {
+    // Find the first available channel.
+    for (*channel = 1; *channel < kMaxChannel; (*channel)++) {
+      if ((err = bt_bind(sock, local_address, channel)) != NULL) {
         free(err);
         continue;
       }
       return NULL;
     }
-    asprintf(&err, "can't find an available bluetooth port");
+    asprintf(&err, "can't find an available bluetooth channel");
     return err;
-  } else {  // *local_address != NULL && *port > 0
+  } else {  // *local_address != NULL && *channel > 0
     addr.rc_family = AF_BLUETOOTH;
     str2ba(*local_address, &addr.rc_bdaddr);
-    addr.rc_channel = (uint8_t) *port;
+    addr.rc_channel = (uint8_t) *channel;
     if (bind(sock, (struct sockaddr*) &addr, sizeof(addr)) < 0) {
-      asprintf(&err, "can't bind to socket %d, addr %s, port %d, error: %d",
-               sock, *local_address, *port, errno);
+      asprintf(&err, "can't bind to socket %d, addr %s, channel %d, error: %d[%s]",
+               sock, *local_address, *channel, errno, strerror(errno));
       return err;
     }
     return NULL;
@@ -137,8 +138,8 @@
   socklen_t opt = sizeof(remote_addr);
 
   if ((*fd = accept(sock, (struct sockaddr *)&remote_addr, &opt)) < 0) {
-    asprintf(&err, "error accepting connection on socket %d, error: %d",
-             sock, errno);
+    asprintf(&err, "error accepting connection on socket %d, error: %d[%s]",
+             sock, errno, strerror(errno));
     return err;
   }
   *remote_address = (char*) malloc(kMaxAddrStrSize * sizeof(char));
@@ -147,17 +148,17 @@
   return NULL;
 }
 
-char* bt_connect(int sock, const char* remote_address, int remote_port) {
+char* bt_connect(int sock, const char* remote_address, int remote_channel) {
   char* err = NULL;
   struct sockaddr_rc remote_addr = { 0 };
 
   remote_addr.rc_family = AF_BLUETOOTH;
   str2ba(remote_address, &remote_addr.rc_bdaddr);
-  remote_addr.rc_channel = (uint8_t) remote_port;
+  remote_addr.rc_channel = (uint8_t) remote_channel;
   if (connect(sock, (struct sockaddr*) &remote_addr, sizeof(remote_addr)) < 0) {
-    asprintf(&err, "can't connect to remote address %s and port %d "
-             "on socket %d, error: %d", remote_address, remote_port,
-             sock, errno);
+    asprintf(&err, "can't connect to remote address %s and channel %d "
+             "on socket %d: %d[%s]", remote_address, remote_channel,
+             sock, errno, strerror(errno));
     return err;
   }
   return NULL;
@@ -166,7 +167,7 @@
 char* bt_close_device(int dd) {
   char* err = NULL;
   if (hci_close_dev(dd) < 0) {
-    asprintf(&err, "can't close device with dd: %d, error: %d", dd, errno);
+    asprintf(&err, "can't close device with dd: %d, error: %d[%s]", dd, errno, strerror(errno));
     return err;
   }
   return NULL;
diff --git a/lib/bluetooth/bt.h b/lib/bluetooth/bt.h
index 0fb5a2a..2a72c97 100644
--- a/lib/bluetooth/bt.h
+++ b/lib/bluetooth/bt.h
@@ -6,9 +6,9 @@
 // Bluetooth LE payload structure:
 //   https://www.bluetooth.org/en-us/specification/adopted-specifications
 const int kMaxLEPayloadSize;
-// The highest bluetooth port that can be used for establishing RFCOMM
+// The highest bluetooth channel that can be used for establishing RFCOMM
 // connections.
-const int kMaxPort;
+const int kMaxChannel;
 
 // Maximum number of local devices to scan over when a particular device isn't
 // explicitly specified.
@@ -29,17 +29,17 @@
 // string is returned, the caller must free it.
 char* bt_close_device(int dd);
 
-// Binds the given socket to the provided MAC address/port.  If '*local_address'
+// Binds the given socket to the provided MAC address/channel.  If '*local_address'
 // is NULL, it will bind to the first available bluetooth device and overwrite
-// '*local_address' to contain that device's MAC address.  If '*port' is zero,
-// it will bind to the first available port on a given device and overwrite
-// '*port' to contain that port value.  (If both of the above are true, we will
-// find the first device/port pair that works and overwrite both values.)
+// '*local_address' to contain that device's MAC address.  If '*channel' is zero,
+// it will bind to the first available channel on a given device and overwrite
+// '*channel' to contain that channel value.  (If both of the above are true, we will
+// find the first device/channel pair that works and overwrite both values.)
 // Returns an error string if any error is encoutered.  If a non-NULL error
 // string is returned, the caller must free it.
 // The caller must free '*local_address' string whenever a NULL value was passed
 // in and a NULL error string is returned.
-char* bt_bind(int sock, char** local_address, int* port);
+char* bt_bind(int sock, char** local_address, int* channel);
 
 // Accepts the next connection on the provided socket.  Stores the file
 // descriptor for the newly established connection into 'fd', and the MAC
@@ -50,10 +50,10 @@
 // is returned.
 char* bt_accept(int sock, int* fd, char** remote_address);
 
-// Connects to the remote address/port pair, using the provided local socket.
+// Connects to the remote address/channel pair, using the provided local socket.
 // Returns an error string if any error is encountered.  If a non-NULL error
 // string is returned, the caller must free it.
-char* bt_connect(int sock, const char* remote_address, int remote_port);
+char* bt_connect(int sock, const char* remote_address, int remote_channel);
 
 // Starts bluetooth LE advertising on the provided device descriptor, sending
 // one advertising packet every 'adv_interval_ms' milliseconds.
diff --git a/lib/bluetooth/conn.go b/lib/bluetooth/conn.go
index 8b09b54..6b50941 100644
--- a/lib/bluetooth/conn.go
+++ b/lib/bluetooth/conn.go
@@ -9,6 +9,9 @@
 
 // conn represents one RFCOMM connection between two bluetooth devices.
 // It implements the net.Conn interface.
+//
+// TODO(ashankar,spetrovic): net.Conn implementations are supposed to be safe
+// for concurrent method invocations. This implementation is not. Fix.
 type conn struct {
 	fd                    int
 	localAddr, remoteAddr *addr
@@ -20,14 +23,24 @@
 	return fmt.Sprintf("Bluetooth (%s) <--> (%s)", c.localAddr, c.remoteAddr)
 }
 
+// helper method for Read and Write that ensures:
+// - the returned 'n' is always >= 0, as per guidelines for the io.Reader and
+//   io.Writer interfaces.
+func (c *conn) rw(n int, err error) (int, error) {
+	if n < 0 {
+		n = 0
+	}
+	return n, err
+}
+
 // Implements the net.Conn interface.
 func (c *conn) Read(p []byte) (n int, err error) {
-	return syscall.Read(c.fd, p)
+	return c.rw(syscall.Read(c.fd, p))
 }
 
 // Implements the net.Conn interface.
 func (c *conn) Write(p []byte) (n int, err error) {
-	return syscall.Write(c.fd, p)
+	return c.rw(syscall.Write(c.fd, p))
 }
 
 // Implements the net.Conn interface.
diff --git a/lib/bluetooth/doc.go b/lib/bluetooth/doc.go
new file mode 100644
index 0000000..b1d0622
--- /dev/null
+++ b/lib/bluetooth/doc.go
@@ -0,0 +1,3 @@
+// Package bluetooth provides methods for interacting with attached bluetooth
+// devices.
+package bluetooth
diff --git a/lib/bluetooth/listener.go b/lib/bluetooth/listener.go
index 86e99a3..5d53386 100644
--- a/lib/bluetooth/listener.go
+++ b/lib/bluetooth/listener.go
@@ -40,8 +40,8 @@
 	if remote.mac, err = net.ParseMAC(C.GoString(remoteMAC)); err != nil {
 		return nil, fmt.Errorf("invalid remote MAC address: %s, err: %s", C.GoString(remoteMAC), err)
 	}
-	// There's no way to get accurate remote port number, so use 0.
-	remote.port = 0
+	// There's no way to get accurate remote channel number, so use 0.
+	remote.channel = 0
 
 	return &conn{
 		fd:         int(fd),
diff --git a/runtimes/google/ipc/stream/manager/manager.go b/runtimes/google/ipc/stream/manager/manager.go
index 7e3a279..a7895b6 100644
--- a/runtimes/google/ipc/stream/manager/manager.go
+++ b/runtimes/google/ipc/stream/manager/manager.go
@@ -9,6 +9,7 @@
 	"strings"
 	"sync"
 
+	"veyron/lib/bluetooth"
 	"veyron/runtimes/google/ipc/stream/crypto"
 	"veyron/runtimes/google/ipc/stream/vif"
 	"veyron/runtimes/google/ipc/version"
@@ -48,6 +49,13 @@
 	shutdown    bool              // GUARDED_BY(muListeners)
 }
 
+func dial(network, address string) (net.Conn, error) {
+	if network == bluetooth.Network {
+		return bluetooth.Dial(address)
+	}
+	return net.Dial(network, address)
+}
+
 // FindOrDialVIF returns the network connection (VIF) to the provided address
 // from the cache in the manager. If not already present in the cache, a new
 // connection will be created using net.Dial.
@@ -57,7 +65,7 @@
 		return vf, nil
 	}
 	vlog.VI(1).Infof("(%q, %q) not in VIF cache. Dialing", network, address)
-	conn, err := net.Dial(network, address)
+	conn, err := dial(network, address)
 	if err != nil {
 		return nil, fmt.Errorf("net.Dial(%q, %q) failed: %v", network, address, err)
 	}
@@ -108,6 +116,13 @@
 	return nil, verror.Internalf("should not reach here")
 }
 
+func listen(protocol, address string) (net.Listener, error) {
+	if protocol == bluetooth.Network {
+		return bluetooth.Listen(address)
+	}
+	return net.Listen(protocol, address)
+}
+
 func (m *manager) Listen(protocol, address string, opts ...stream.ListenerOpt) (stream.Listener, naming.Endpoint, error) {
 	var rewriteEP string
 	var filteredOpts []stream.ListenerOpt
@@ -135,7 +150,7 @@
 		}
 		return m.remoteListen(ep, opts)
 	}
-	netln, err := net.Listen(protocol, address)
+	netln, err := listen(protocol, address)
 	if err != nil {
 		return nil, nil, fmt.Errorf("net.Listen(%q, %q) failed: %v", protocol, address, err)
 	}