Skip to content

Commit 7c77026

Browse files
committed
feature: Cancellable connection establish event
1 parent f884e04 commit 7c77026

File tree

2 files changed

+124
-21
lines changed

2 files changed

+124
-21
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright (C) 2018-2021 Velocity Contributors
3+
*
4+
* The Velocity API is licensed under the terms of the MIT License. For more details,
5+
* reference the LICENSE file in the api top-level directory.
6+
*/
7+
8+
package com.velocitypowered.api.event.connection;
9+
10+
import com.google.common.base.Preconditions;
11+
import com.velocitypowered.api.event.ResultedEvent;
12+
import com.velocitypowered.api.event.annotation.AwaitingEvent;
13+
import com.velocitypowered.api.proxy.InboundConnection;
14+
import org.checkerframework.checker.nullness.qual.NonNull;
15+
import org.checkerframework.checker.nullness.qual.Nullable;
16+
17+
/**
18+
* Event called when a connection is initially established with the proxy.
19+
* Velocity will wait for this event to fire before continuing with the connection.
20+
*/
21+
@AwaitingEvent
22+
public class ConnectionEstablishEvent implements ResultedEvent<ResultedEvent.GenericResult> {
23+
private final InboundConnection connection;
24+
private final Intention intention;
25+
private GenericResult result = GenericResult.allowed();
26+
27+
public ConnectionEstablishEvent(
28+
final @NonNull InboundConnection connection,
29+
final @Nullable Intention intention
30+
) {
31+
this.connection = Preconditions.checkNotNull(connection, "connection");
32+
this.intention = intention;
33+
}
34+
35+
/**
36+
* The intention of the connection.
37+
*/
38+
public enum Intention {
39+
/**
40+
* The user intends to ping the server to fetch the status.
41+
*/
42+
STATUS,
43+
/**
44+
* The user intends to log in to the server.
45+
*/
46+
LOGIN,
47+
}
48+
49+
/**
50+
* Returns the inbound connection that is being established.
51+
*
52+
* @return the connection
53+
*/
54+
public @NonNull InboundConnection getConnection() {
55+
return this.connection;
56+
}
57+
58+
/**
59+
* Returns the intention for which the connection is being established, if known.
60+
*
61+
* @return the intention
62+
*/
63+
public @Nullable Intention getIntention() {
64+
return this.intention;
65+
}
66+
67+
@Override
68+
public GenericResult getResult() {
69+
return this.result;
70+
}
71+
72+
@Override
73+
public void setResult(final @NonNull GenericResult result) {
74+
this.result = Preconditions.checkNotNull(result, "result");
75+
}
76+
}

proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import com.google.common.annotations.VisibleForTesting;
2121
import com.google.common.base.Preconditions;
22+
import com.velocitypowered.api.event.connection.ConnectionEstablishEvent;
2223
import com.velocitypowered.api.event.connection.ConnectionHandshakeEvent;
2324
import com.velocitypowered.api.network.ProtocolVersion;
2425
import com.velocitypowered.proxy.VelocityServer;
@@ -85,31 +86,57 @@ public boolean handle(LegacyHandshake packet) {
8586
public boolean handle(Handshake handshake) {
8687
InitialInboundConnection ic = new InitialInboundConnection(connection,
8788
cleanVhost(handshake.getServerAddress()), handshake);
88-
StateRegistry nextState = getStateForProtocol(handshake.getNextStatus());
89-
if (nextState == null) {
90-
LOGGER.error("{} provided invalid protocol {}", ic, handshake.getNextStatus());
91-
connection.close(true);
92-
} else {
93-
connection.setProtocolVersion(handshake.getProtocolVersion());
94-
connection.setAssociation(ic);
95-
96-
switch (nextState) {
97-
case STATUS:
98-
connection.setActiveSessionHandler(StateRegistry.STATUS,
99-
new StatusSessionHandler(server, ic));
100-
break;
101-
case LOGIN:
102-
this.handleLogin(handshake, ic);
103-
break;
104-
default:
105-
// If you get this, it's a bug in Velocity.
106-
throw new AssertionError("getStateForProtocol provided invalid state!");
107-
}
108-
}
89+
90+
// Handle connection establish event.
91+
connection.setAutoReading(false);
92+
server.getEventManager()
93+
.fire(new ConnectionEstablishEvent(
94+
ic, getIntentionForStatus(handshake.getNextStatus())))
95+
.thenAcceptAsync(result -> {
96+
// Clean up the disabling of auto-read.
97+
connection.setAutoReading(true);
98+
99+
if (!result.getResult().isAllowed()) {
100+
connection.close(true);
101+
} else {
102+
StateRegistry nextState = getStateForProtocol(handshake.getNextStatus());
103+
if (nextState == null) {
104+
LOGGER.error("{} provided invalid protocol {}", ic, handshake.getNextStatus());
105+
connection.close(true);
106+
} else {
107+
connection.setProtocolVersion(handshake.getProtocolVersion());
108+
connection.setAssociation(ic);
109+
110+
switch (nextState) {
111+
case STATUS:
112+
connection.setActiveSessionHandler(StateRegistry.STATUS,
113+
new StatusSessionHandler(server, ic));
114+
break;
115+
case LOGIN:
116+
this.handleLogin(handshake, ic);
117+
break;
118+
default:
119+
// If you get this, it's a bug in Velocity.
120+
throw new AssertionError("getStateForProtocol provided invalid state!");
121+
}
122+
}
123+
}
124+
});
109125

110126
return true;
111127
}
112128

129+
private static ConnectionEstablishEvent.@Nullable Intention getIntentionForStatus(int status) {
130+
switch (status) {
131+
case StateRegistry.STATUS_ID:
132+
return ConnectionEstablishEvent.Intention.STATUS;
133+
case StateRegistry.LOGIN_ID:
134+
return ConnectionEstablishEvent.Intention.LOGIN;
135+
default:
136+
return null;
137+
}
138+
}
139+
113140
private static @Nullable StateRegistry getStateForProtocol(int status) {
114141
switch (status) {
115142
case StateRegistry.STATUS_ID:

0 commit comments

Comments
 (0)