RuneHive-Game
Loading...
Searching...
No Matches
ChannelFilter.java
Go to the documentation of this file.
1package com.runehive.net;
2
3import com.google.common.collect.ConcurrentHashMultiset;
4import com.google.common.collect.Multiset;
5import com.runehive.Config;
6import com.runehive.game.world.entity.mob.player.IPBannedPlayers;
7import com.runehive.net.codec.login.LoginResponse;
8import com.runehive.net.codec.login.LoginResponsePacket;
9import io.netty.buffer.ByteBuf;
10import io.netty.channel.ChannelFutureListener;
11import io.netty.channel.ChannelHandler.Sharable;
12import io.netty.channel.ChannelHandlerContext;
13import io.netty.channel.ChannelInboundHandlerAdapter;
14
15import java.net.InetSocketAddress;
16import java.util.Objects;
17import java.util.concurrent.atomic.AtomicBoolean;
18
19/**
20 * The {@code ChannelInboundHandlerAdapter} implementation that will filter out
21 * unwanted connections from propagating down the pipeline.
22 *
23 * @author Seven
24 * @author Michael | Chex
25 */
26@Sharable
27public class ChannelFilter extends ChannelInboundHandlerAdapter {
28
29 /** A set of connections currently active within the server. */
30 private final Multiset<Connection> connections = ConcurrentHashMultiset.create();
31
32 @Override
33 public void channelActive(ChannelHandlerContext ctx) throws Exception {
34 Connection connection = getConenction(ctx);
35 connection.setCanConnect(true);
36 }
37
38 @Override
39 public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
40 Connection connection = getConenction(ctx);
41
42 /* Make sure this channel is not going to get flooded. */
43 if (!connection.canConnect()) {
44 return;
45 }
46
47 /*
48 * If this local then, do nothing and proceed to next handler in the
49 * pipeline.
50 */
51 if (connection.getHost().equalsIgnoreCase("127.0.0.1")) {
52 return;
53 }
54
55 /* Add the host */
56 connection.addConnection();
57
58 /* Evaluate the host */
59 if (connection.getConnections() > Config.CONNECTION_LIMIT) {
61 return;
62 }
63
64 if (IPBannedPlayers.ipBans.contains(connection.getHost())) {
66 return;
67 }
68
69 connections.add(connection);
70 connection.setCanConnect(false);
71
72 /*
73 * Nothing went wrong, so register the channel and forward the randomevent to
74 * next handler in the pipeline.
75 */
76 ctx.fireChannelRegistered();
77 }
78
79 @Override
80 public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
81 Connection connection = getConenction(ctx);
82
83 /*
84 * If this is local, do nothing and proceed to next handler in the
85 * pipeline.
86 */
87 if (connection.getHost().equalsIgnoreCase("127.0.0.1")) {
88 return;
89 }
90
91 connection.removeConnection();
92
93 /* Remove the host from the connection list */
94 if (connection.getConnections() == 0) {
95 connections.remove(connection);
96 }
97
98 /*
99 * The connection is unregistered so forward the randomevent to the next
100 * handler in the pipeline.
101 */
102 ctx.fireChannelUnregistered();
103 }
104
105 /**
106 * Disconnects {@code ctx} with {@code response} as the response code.
107 *
108 * @param ctx
109 * The channel handler context.
110 * @param response
111 * The response to disconnect with.
112 */
113 private void disconnect(ChannelHandlerContext ctx, LoginResponse response) {
114 LoginResponsePacket message = new LoginResponsePacket(response);
115 ByteBuf initialMessage = ctx.alloc().buffer(8).writeLong(0);
116
117 ctx.write(initialMessage, ctx.voidPromise());
118 ctx.writeAndFlush(message).addListener(ChannelFutureListener.CLOSE);
119 }
120
121 /**
122 * Gets the host address of the user logging in.
123 *
124 * @param ctx
125 * The context of this channel.
126 *
127 * @return The host address of this connection.
128 */
129 private Connection getConenction(ChannelHandlerContext ctx) {
130 String host = ((InetSocketAddress) ctx.channel().remoteAddress()).getAddress().getHostAddress();
131 return connections.stream().filter(conn -> conn.getHost().equalsIgnoreCase(host)).findFirst().orElse(new Connection(host));
132 }
133
134 /**
135 * Creates a conenction for a host address.
136 *
137 * @author Michael | Chex
138 */
139 private static class Connection {
140
141 /** The stopwatch which caches the time of our last login. */
142 private final AtomicBoolean canConnect = new AtomicBoolean(true);
143
144 /** The host address. */
145 private final String host;
146
147 /** The amount of connections associated with this host address. */
148 private int connections;
149
150 /**
151 * Constructs a new {@code Connection} object.
152 *
153 * @param host
154 * The host address.
155 */
156 public Connection(String host) {
157 this.host = host;
158 }
159
160 /**
161 * Gets the host address.
162 *
163 * @return The host address.
164 */
165 public String getHost() {
166 return host;
167 }
168
169 /**
170 * Gets the amount of connections associated with this host address.
171 *
172 * @return The amount of connections associated with this host address.
173 */
174 public int getConnections() {
175 return connections;
176 }
177
178 /**
179 * Checks if this host can connect.
180 *
181 * @return {@code True} if this host can connect.
182 */
183 public boolean canConnect() {
184 return canConnect.get();
185 }
186
187 /** Adds a connection. */
188 public void addConnection() {
189 connections++;
190 }
191
192 /** Removes a connection. */
193 public void removeConnection() {
194 connections--;
195 }
196
197 public void setCanConnect(boolean val) {
198 canConnect.compareAndSet(!val, val);
199 }
200
201 @Override
202 public int hashCode() {
203 return Objects.hash(host);
204 }
205
206 @Override
207 public boolean equals(Object obj) {
208 if (obj instanceof Connection) {
209 Connection other = (Connection) obj;
210 return host.equalsIgnoreCase(other.getHost());
211 }
212 return obj == this;
213 }
214
215 @Override
216 public String toString() {
217 return String.format("Connection[host=%s, connections=%s, elapsed=%s]", host, connections, canConnect);
218 }
219
220 }
221
222}
The class that contains setting-related constants for the server.
Definition Config.java:24
static final int CONNECTION_LIMIT
The maximum amount of connections that can be active at a time, or in other words how many clients ca...
Definition Config.java:73
Creates a conenction for a host address.
final AtomicBoolean canConnect
The stopwatch which caches the time of our last login.
int connections
The amount of connections associated with this host address.
Connection(String host)
Constructs a new Connection object.
void removeConnection()
Removes a connection.
boolean canConnect()
Checks if this host can connect.
int getConnections()
Gets the amount of connections associated with this host address.
String getHost()
Gets the host address.
The ChannelInboundHandlerAdapter implementation that will filter out unwanted connections from propag...
final Multiset< Connection > connections
A set of connections currently active within the server.
void channelUnregistered(ChannelHandlerContext ctx)
void channelActive(ChannelHandlerContext ctx)
void disconnect(ChannelHandlerContext ctx, LoginResponse response)
Disconnects ctx with response as the response code.
void channelRegistered(ChannelHandlerContext ctx)
Connection getConenction(ChannelHandlerContext ctx)
Gets the host address of the user logging in.
An immutable message that is written through a channel and forwarded to the LoginResponseEncoder wher...
Represents the enumerated login response codes.