Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[INTERNAL][CORE] Prepares Stream access #653

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

srossbach
Copy link
Contributor

This patch introduces an new class / interface which is just used for
the ITransmitter and IReceiver. This is necessary to distinguish between
plan stream connections and internal stuff.

This patch introduces new classes and interface. This is necessary to
distinguish between plain stream connections and internal stuff.

In general this patch is a whole rewrite of the DTM.

It now manages two connection pools. One for packet connections and one
for stream connections.

In addition this commits adds Javadoc, TODOs and FIXMEs.
@srossbach srossbach removed the request for review from stefaus August 27, 2019 04:53
@saros-project saros-project deleted a comment Aug 27, 2019
@srossbach srossbach requested a review from tobous August 27, 2019 16:23
@srossbach
Copy link
Contributor Author

@tobous can you just please have a look at the Javadoc and basically just the naming of the methods in the interfaces ? I guess the rest of this "commit" is not reviewable, however the whole logic of the DTM is tested with a bunch of test cases.

@tobous
Copy link
Member

tobous commented Aug 27, 2019

@srossbach Yes, I can have a look at it. But I'm busy for the rest of the week, so I won't get to it (or at least finish it) before next Monday.
Either way, with this mainly dealing with the network stuff, @stefaus should (also) have a look at this as it might interfere/intersect with his work.

@srossbach
Copy link
Contributor Author

He has not replied since 9 days, so I removed him as reviewer.

Copy link
Member

@tobous tobous left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got through everything but the DataTransfereManager (and its test). For that class, I am way out of my depth (and I have been reviewing for a while, so my concentration is fading). I will try the class again in the next couple of days.

* <p>It offers support for two connection types.
*
* <ol>
* <li>Establishing a connection using {@link #connect(String, Object)} to establish a connection
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the phrase "establish(ing) a connection" twice sounds a bit weird. But that is more of a nit-pick than a real complaint.

* @return <code>true</code> to accept the connection or <code>false</code> to reject the
* connection.
*/
public boolean connectionEstablished(IStreamConnection connection);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The public modifier is not needed for interface methods. Also, rename to better represent the "accepting/rejecting" nature?

Suggested change
public boolean connectionEstablished(IStreamConnection connection);
boolean checkIncomingConnection(IStreamConnection connection);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is from a TCP (depends on the stream service) point of the the connection IS established, it occupies a port.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Then how about something along the lines of checkNewConnection(...)?

try {
listener.connectionClosed(connectionId, connection);
accepted |= listener.connectionEstablished(connection);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The or-assignment is not necessary as you break anyways when accepted is true, i.e. when you encounter true for the first time.
(Also, you could avoid the unnecessary assignments by checking first and only assigning if the listener returns true and then breaking. But it makes the logic harder to read, so I'm not sure whether it's really worth it.

Suggested change
accepted |= listener.connectionEstablished(connection);
accepted = listener.connectionEstablished(connection);

* <p>Furthermore if a listener accepts the request every outstanding listener will <b>not</b> get
* notified about this connection establishment.
*/
public interface IStreamConnectionListener {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure I understand what this class is needed for. Could you explain the use case to me? Was it added so that we don't have to blindly accept any incoming stream?

Furthermore, using the name "listener" is a bit confusing in combination with the implemented behavior. This "listener" is only used to accept or reject connections and doesn't really do anything with the passed connection. Furthermore, it only runs until a registered listener accepts the connection, meaning not all listeners have to be notified (as stated in the javadoc).

I am struggling with finding a good name, but I somewhat like the metaphor of a bouncer for incoming connections (which doesn't completely match as all "bouncers" have to "reject" the connection for it to actually be rejected).

Suggested change
public interface IStreamConnectionListener {
public interface IStreamConnectionBouncer {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is quite simple and has to do with (D)DOS attacks. So imagine you open a socket (you can only accept 65535 connections). The first check after calling accept (see ServerSocket) is to do some mighty "magic" and close the connection just afterwards if the "magic" decided you shall not pass. Now it gets passes to the listener(s). If no listener is interested, should I keep the connection alive ? I guess not.

TBH the name is bad. It should be changed.

* A stream connection consists of an input and out stream. It up to the caller to gracefully
* shutdown the connections.
*/
public interface IStreamConnection extends IConnection {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this interface provide access to the streams but also direct access to some of their functionality (the timeout stuff)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because timeout stuff is session management, The connection only provides the "stream" but not the session you would put above it. To clearify things, we are talking about network sessions (see OSI layer), not about a Saros session.


private final Map<String, IConnection> pool = new HashMap<>();

ConnectionPool(final String name) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can tell, you want a pool for every connection type. You could also consider making the pool generic (<T extends IConnection>) in order to better differentiate between the connection types and make the usage easier. It doesn't really make the class more complicated and would me you wouldn't have to cast the result from get requests.

This would make the name somewhat unnecessary, but you could still keep it around for a better toString().

@@ -319,10 +320,10 @@ public void unblockOutgoingSessionPackets(JID jid) throws RemoteException {
return;
}

IByteStreamConnection connection =
getDataTransferManager().getConnection(ISarosSession.SESSION_CONNECTION_ID, jid);
IConnection connection =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The returned connection is a IPacketConnection. Why not hold it as such? (This would also make the cast in l.336 unnecessary.)
Also, why do you check the type in the while loop in l.326? Can this check ever fail? Instead, you can just do a null-check.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have basically two review modes.

Production = all the good stuff
Test Frameworks = just get this **** done.

However yes it seems that I did a refactor during multiple patches however this was already coded in such a bad way😆 after the first changes that I do not recognize any warnings here that may araised after the next refactoring steps.

* @author coezbek
* @author jurke
*/
@Component(module = "net")
public class DataTransferManager implements IConnectionListener, IConnectionManager {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a new javadoc?

}

private IByteStreamConnection connectInternal(String connectionID, JID peer) throws IOException {
private IConnection connectInternal(
final String id, final JID address, final boolean isPlainStream) throws IOException {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This solution using the Boolean to determine the return type is a bit ugly in my opinion. But using generics gets very ugly fast as far as I can tell, so this isn't an option either.

Would splitting this method into a stream and non-stream variant be a possibility without creating too much code duplication? The logic is kind of long/complicated, so I don't have a good overview.

for (ByteStream byteStream : establishedStreams)
try {
byteStream.close();
} catch (IOException e) { // ignore}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
} catch (IOException e) { // ignore}
} catch (IOException e) { // ignore

@srossbach
Copy link
Contributor Author

I currently have limited time. Will reply on friday, saturday, or sunday.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants