The support for server-side in 2.4 (beta) was preliminary.  WidcommBluetoothListener only attempted to handle one pending connection at a time and rather than implementing its own initiating and event handling code it just piggy-backed on the consumer code’s Begin-/ AcceptBluetoothClient call.  (The latter aspect, as we discussed at http://inthehand.com/forums/p/2223/7752.aspx#7752, meaning of course that a connection couldn’t be accepted until BeginAcceptBluetoothClient had been called, and thus we couldn’t support the Pending method).

So for a full implementation we need to keep: 1. a queue of accepted connections, 2. a queue of waiting ports, and also 3. a queue of waiting acceptors (if the consumer has called Begin-/AcceptBluetoothClient one or more times before connection(s) have arrived).

If one looks at the UNIX Sockets internal e.g. via W. Richard Stevens’ book then one sees that there’s no “waiting sockets” queue.  The Widcomm API however requires a port is created and set into server-mode for a connection to be accepted.

I’v implemented this and my current version of the code is at https://32feetnetdev.wordpress.com/widcommbtlistener-2-0/.  However testing it threw up interesting behaviour so I have not committed it yet.  If anyone can have a play and confirm my solution then we can get it checked in.

The odd behaviour that I saw was that if I opened a connection to the server and closed it from the remote device, then the next connection would reuse the old port (Widcomm CRfCommPort) instead of using a port from the waiting queue.  This was surprising behaviour to me, and I had to add lots of diagnostic code to the stream and port classes (WidcommRfcommStream and WidcommRfcommPort) to confirm it.  (The odd behaviour became apparent promptly as an Assert on the old port instance reported that a CONNECT event was occurring when it was in PeerDidClose state, without the assert I may have been confused for much longer).  It is not discussed in the Widcomm documentation, neither explicitly not by implication as far as I can see.

Anyway, the solution to this should be simple.  Currently we don’t call the CRfCommPort.Close method until we Close/ Dispose the NetworkStream/ BluetoothClient (actually WidcommRfcommStream).   Thus the port is still active and apparently Widcomm will reuse it then.  So we simply have to Close the port as soon as we receive the event signalling that the peer close (i.e. CONNECT_ERR).

The diff is this:

--- d:\temp\temp\WidcommRfcommStream;C56017.cs	2009-08-06 21:54:50.250000000 +0100
+++ d:\working\InTheHand.Net.Personal\InTheHand.Net.Personal\Net.Bluetooth.Widcomm\WidcommRfcommStream.cs	2009-08-06 21:53:24.734375000 +0100
@@ -614,6 +614,7 @@
                         DebugId + ": " +
                         eventId + ": m_state wanted: " + "Connected" + ", but was: " + m_state_);
                     Console.WriteLine("HandlePortEvent: closed when open.");
+                    m_port.Close();
                     // No information whether this is a hard or clean close! :-(
                     m_state_ = State.PeerDidClose;
                     if (GetPendingReceiveDataLength() == 0) {

There’s another possibility, that is to return the disconnected port to a pool from where it can be used when we start the next waiter.  However we’re not creating enough ports for that to be necessary and it would be rather more complex and could make debugging more difficult so we’ll just go ahead and close the port.

This change affects all connection both client as well server.  We have to make sure it doesn’t break anything.  In particular we have to make sure that once a port is disconnected by the remote device (state PeerClose) that we don’t access the port.   All feedback  welcomed.

Advertisements