[bt][fidl] ConnectL2Cap returns nullable socket

Sockets with ZX_INVALID_HANDLE can't be passed through FIDL, so there is
no way to send a non-handle if the channel opening fails somehow.  Make
the socket return nullable.

Previously this would crash the FIDL connection as the profile server
delivers an invalid socket in this case.

BT-659

Test: new integration test: connect_unknown_peer
  fx run-test bluetooth-tests -t bt-integration-tests

Change-Id: I4f9114c1cd43f0b3a703573b74d934f3274bf5d6
diff --git a/sdk/fidl/fuchsia.bluetooth.bredr/profile.fidl b/sdk/fidl/fuchsia.bluetooth.bredr/profile.fidl
index 5f3e264..56122c9 100644
--- a/sdk/fidl/fuchsia.bluetooth.bredr/profile.fidl
+++ b/sdk/fidl/fuchsia.bluetooth.bredr/profile.fidl
@@ -52,7 +52,7 @@
     /// Returns the channel after it has been connected. |status| will indicate
     /// an error if the channel could not be connected.
     ConnectL2cap(string peer_id, uint16 psm)
-        -> (fuchsia.bluetooth.Status status, handle<socket> channel);
+        -> (fuchsia.bluetooth.Status status, handle<socket>? channel);
 
     /// Produced when a protocol channel is connected for this profile.
     /// |channel| contains the channel connected to, and information about the
diff --git a/src/connectivity/bluetooth/tests/integration/src/main.rs b/src/connectivity/bluetooth/tests/integration/src/main.rs
index bb61339..e27f3ce 100644
--- a/src/connectivity/bluetooth/tests/integration/src/main.rs
+++ b/src/connectivity/bluetooth/tests/integration/src/main.rs
@@ -20,7 +20,9 @@
         },
         lifecycle::lifecycle_test,
         low_energy_central::{enable_and_disable_scan, enable_scan},
-        profile::{add_fake_profile, add_remove_profile, same_psm_twice_fails},
+        profile::{
+            add_fake_profile, add_remove_profile, connect_unknown_peer, same_psm_twice_fails,
+        },
     },
 };
 
@@ -69,6 +71,7 @@
         run_test!(add_fake_profile),
         run_test!(same_psm_twice_fails),
         run_test!(add_remove_profile),
+        run_test!(connect_unknown_peer),
     ])?;
     Ok(())
 }
diff --git a/src/connectivity/bluetooth/tests/integration/src/tests/profile.rs b/src/connectivity/bluetooth/tests/integration/src/tests/profile.rs
index 4f210a3..0c1185b 100644
--- a/src/connectivity/bluetooth/tests/integration/src/tests/profile.rs
+++ b/src/connectivity/bluetooth/tests/integration/src/tests/profile.rs
@@ -7,7 +7,7 @@
     fidl_fuchsia_bluetooth as bt,
     fidl_fuchsia_bluetooth_bredr::{
         DataElement, DataElementData, DataElementType, ProtocolDescriptor, ProtocolIdentifier,
-        SecurityLevel, ServiceDefinition,
+        SecurityLevel, ServiceDefinition, PSM_AVDTP,
     },
     fuchsia_bluetooth::error::Error as BTError,
 };
@@ -65,5 +65,17 @@
     await!(add_fake_profile(profile))
 }
 
-// TODO(BT-659): connect_l2cap
+pub async fn connect_unknown_peer(profile: ProfileHarness) -> Result<(), Error> {
+    let (status, socket) = await!(profile.aux().connect_l2cap("unknown_peer", PSM_AVDTP as u16))?;
+    // Should be an error
+    if status.error.is_none() {
+        return Err(format_err!("Expected an error from connecting to an unknown peer"));
+    }
+    if socket.is_some() {
+        return Err(format_err!("Should not have a socket when we don't connect"));
+    }
+    Ok(())
+}
+
+// TODO(BT-659): the rest of connect_l2cap tests (that acutally succeed)
 // TODO(BT-759): add_search / on_service_found