Skip to content

Commit 8789e41

Browse files
committed
extracted encounter management from ASAPAndroid
1 parent 8041e66 commit 8789e41

27 files changed

+1370
-14
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package net.sharksystem;
2+
3+
public class SharkNotSupportedException extends RuntimeException {
4+
public SharkNotSupportedException() {
5+
super();
6+
}
7+
public SharkNotSupportedException(String message) {
8+
super(message);
9+
}
10+
public SharkNotSupportedException(String message, Throwable cause) {
11+
super(message, cause);
12+
}
13+
public SharkNotSupportedException(Throwable cause) {
14+
super(cause);
15+
}
16+
}

src/net/sharksystem/asap/ASAPConnectionHandler.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,6 @@ ASAPConnection handleConnection(
4646
*/
4747
ASAPConnection handleConnection(InputStream is, OutputStream os) throws IOException, ASAPException;
4848

49+
ASAPConnection handleConnection(InputStream inputStream, OutputStream outputStream,
50+
EncounterConnectionType connectionType) throws IOException, ASAPException;
4951
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package net.sharksystem.asap;
2+
3+
import net.sharksystem.asap.utils.Helper;
4+
5+
import java.io.IOException;
6+
import java.net.InetAddress;
7+
import java.net.Socket;
8+
9+
public class ASAPEncounterHelper {
10+
public static final String getRemoteAddress(Socket connectedSocket) throws IOException {
11+
InetAddress inetAddress = connectedSocket.getInetAddress();
12+
int port = connectedSocket.getPort();
13+
return inetAddress.getHostAddress() + ":" + port;
14+
}
15+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package net.sharksystem.asap;
2+
3+
import net.sharksystem.streams.StreamPair;
4+
5+
import java.io.IOException;
6+
7+
/**
8+
* An ASAP peer can handle ASAP encounter as they come. It takes in- and output stream and runs an ASAP session.
9+
* Where are those streams from? They are created from underlying protocol engines. There are probably and hopefully
10+
* more than one protocol engines in a real environment. A smartphone would provide Bluetooth, Wifi direct and
11+
* maybe it has allows communicating via an ASAPHub.
12+
* <br/><br/>
13+
* We could of course ignore this somewhat more complex environment and create a connection whenever possible and
14+
* run an ASAP session. That not very efficient, though. It has even the tendency to be a considerable wast of
15+
* resources. Why is that?
16+
* <br/><br/>
17+
* Take ad-hoc networks as an example: A connection can be established within a given radius, like 10m with Bluetooth.
18+
* A connection gets lost if two devices are over that threshold and can be re-established if they get closer. This
19+
* leads to flickering effects. Connection gone / re-established / gone again etc. That's ok and useful if we are about
20+
* implementing streaming services. But we war not. ASAP is basically meant to be platform for distributed apps which
21+
* are based on the command pattern. There are no streams but data packages.
22+
* <br/><br/>
23+
* Application developers will have a pretty good understanding of how often such messages are created. Even very fast
24+
* human writers will barely produce more than a message per second, presumably far less. Exchange rate in a sensor
25+
* network observing outside temperature is better be measured in hours than minutes. This will be different in
26+
* industrial processes. Apparently: It depends on the application scenario. We want to give application developers
27+
* as much help for optimization as possible. That is one way to safe most probably a lot of energy.
28+
* <br/><br/>
29+
* ASAP is an opportunistic protocol. Connections should be established whenever possible. This could and will be a
30+
* serious leak on resources in a multi-protocol environment. It is hardly useful that two smartphones create a
31+
* Bluetooth <i>and</i> a Wifi-direct connection if they can. One is sufficient.
32+
* <br/><br/>
33+
* An encounter manager deals with those problems. It is highly recommended to use it. We do, see e.g. our ASAPAndroid
34+
* lib which is even more highly recommend.
35+
*/
36+
public interface ASAPEncounterManager {
37+
/**
38+
* Other devices can be detected by a point-to-point protocol. This method is to be called before a connection
39+
* is established.
40+
* <br/><br/>
41+
* It can be checked when a last encounter happened. This is most useful e.g. in ad-hoc networks. Communication can
42+
* get lost by a (slight) movement and could be reestablished a moment later. A kind of cool-down-period can be
43+
* defined.
44+
* <br/><br/>
45+
* Peers could communicate over different channels. Same argument: It can be decided <i>not</i> to establish
46+
* a connection due to an existing one over another protocol.
47+
* @param addressOrPeerID address of remote device or a peer id. It is only used as an index, an id.
48+
* There will be no attempts to establish a connection.
49+
* @param connectionType Describes the connection that is planned to be established.
50+
* @return true: a connection should be established or not.
51+
* @see EncounterConnectionType
52+
*/
53+
boolean shouldCreateConnectionToPeer(CharSequence addressOrPeerID, EncounterConnectionType connectionType);
54+
55+
/**
56+
* A connection to another device was established. This method can be called to handle this new connection.
57+
* It can lead to an immediate shutdown, e.g. the other device already made a successful attempt to connect e.g.
58+
* over another protocol.
59+
* <br/><br/>
60+
* In a lot of cases an ASAP session will be launched.
61+
*
62+
* @param streamPair most likely a socket that is can be used for an ASAP session.
63+
* @throws IOException something can go wrong when sending data. This object has no obligation to deal with this.
64+
*/
65+
void handleEncounter(StreamPair streamPair, EncounterConnectionType connectionType) throws IOException;
66+
67+
/**
68+
* This method is a variant of the one with less parameters.
69+
*
70+
* Here is the catch:
71+
* <br/><br/>
72+
* We have a race condition in any ad-hoc network based on this library. What happens if both devices come into
73+
* sending range?
74+
* <br/><br/>
75+
* <ul>
76+
* <li>Each asks this object if it should establish a connection by calling shouldConnect. It is highly likely
77+
* that both side get same answer. Let's assume it is a yes.</li>
78+
* <li>Both would open a passive endpoint (most likely a server socket). In most cases it is already open
79+
* before the previous step. In any case..</li>
80+
* <li>Both would try to establish a connection to the other side... An here starts the race...</li>
81+
* <li>Let's assume Alice and Bob are in that situation: Alice would recognize an connection attempt from
82+
* Bob on her server socket. She is also aware that she is also doing a connection attempt to Bob. That's in the
83+
* nature of this process. We do not want this. We do not want to parallel connections between those two devices.
84+
* One should be canceled. But what: Alice -> Bob or Bob -> Alice ?</li>
85+
* <li>Bob is in the same situation. That problem arose when working with Bluetooth. It happens very often.
86+
* This simple solution does <i>not</i> work: If we see a connection attempt on our server we drop out active
87+
* connection attempt. Both side would do the same and both connection attempts are canceled. That is the race
88+
* condition.
89+
* </li>
90+
* </ul>
91+
*
92+
* This problem can be solved by adding an additional parameter. This boolean value states if this method is
93+
* called by an <i>initiator</i>. What is that? A process that create e.g. a client socket is - per definition -
94+
* an initiator. It initiated this connection. A server socket waits for connection attempts and is
95+
* - per definition - no initiator. Please, choose very carefully this parameter. The race condition is solved
96+
* by an implementation of this interface.
97+
* <br/><br/>
98+
* If you are interested: Here is an idea of an implementation.
99+
* <ul>
100+
* <li>It is checked if there is an open connection to the other side before anything other happens.
101+
* If so: stream pair is closed and we are ready here.</li>
102+
* <li>Both sides exchange a random value over this stream pair. One side will be initiator - the other not.
103+
* (If you chose that parameter carefully). No we can decide:
104+
* What is the random number of the initiator and what is the non-initiator value.</li>
105+
* <li>Is the initiator value smaller than the non-initial value? If so:
106+
* We let this thread sleep a little while. We have produced an asymmetry. One process waits, the other not.
107+
* </li>
108+
* <li>After wake-up: We check again if there is already a connection established. If so - there was a race
109+
* condition and we solved it. If not - we establish a connection.</li>
110+
* </ul>
111+
*
112+
* You should call this variant in any ad-hoc network. You should also uses this variant if you have a fully
113+
* symmetric situation - both devices offer a port to connect to any make and active attempt to connect.
114+
*
115+
* @param streamPair
116+
* @param initiator
117+
* @throws IOException
118+
* @see ASAPEncounterManager#handleEncounter(StreamPair, EncounterConnectionType)
119+
*/
120+
void handleEncounter(StreamPair streamPair, EncounterConnectionType connectionType, boolean initiator) throws IOException;
121+
}

0 commit comments

Comments
 (0)