Skip to content

Commit

Permalink
Velocity fixes
Browse files Browse the repository at this point in the history
Workarounds #8
  • Loading branch information
ishland committed Jul 10, 2022
1 parent 7679d9f commit 28c6e76
Show file tree
Hide file tree
Showing 6 changed files with 257 additions and 94 deletions.
Expand Up @@ -14,7 +14,6 @@
import io.netty.channel.FixedRecvByteBufAllocator;
import io.netty.channel.ReflectiveChannelFactory;
import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.unix.DomainSocketAddress;
import io.netty.util.AttributeKey;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
Expand Down Expand Up @@ -66,10 +65,11 @@ public class BungeeRaknetifyServer {
private static final Reference2ReferenceOpenHashMap<Channel, ReferenceOpenHashSet<ChannelFuture>> channels = new Reference2ReferenceOpenHashMap<>();
private static final ReferenceOpenHashSet<ChannelFuture> nonWildcardChannels = new ReferenceOpenHashSet<>();

private static boolean active = false;
private static volatile boolean active = false;
private static volatile int activeIndex = 0;
private static boolean injected = false;

private static Consumer<NetworkInterfaceListener.InterfaceChangeEvent> listener = null;
private static volatile Consumer<NetworkInterfaceListener.InterfaceAddressChangeEvent> listener = null;

public static void inject() {
if (active) return;
Expand All @@ -96,11 +96,14 @@ public static void inject() {
}
}

int currentActiveIndex = ++activeIndex;
listener = event -> {
if (!active) {
NetworkInterfaceListener.removeListener(listener);
}

if (currentActiveIndex != activeIndex) return; // we can't remove ourselves now, is plugin reloaded?

if (event.added()) {
for (Channel channel : channels.keySet()) {
injectChannel(instance, channel, false);
Expand All @@ -109,20 +112,12 @@ public static void inject() {
for (ReferenceOpenHashSet<ChannelFuture> futures : channels.values()) {
for (ObjectIterator<ChannelFuture> iterator = futures.iterator(); iterator.hasNext(); ) {
ChannelFuture future = iterator.next();
final Iterator<InetAddress> iterator1 = event.networkInterface().getInetAddresses().asIterator();

__loop0:
while (iterator1.hasNext()) {
final InetAddress address = iterator1.next();
if (((InetSocketAddress) future.channel().localAddress()).getAddress().equals(address)) {
RaknetifyBungeePlugin.LOGGER.info("Closing Raknetify server %s".formatted(future.channel().localAddress()));
future.channel().close();
iterator.remove();
break __loop0;
}
if (((InetSocketAddress) future.channel().localAddress()).getAddress().equals(event.address())) {
RaknetifyBungeePlugin.LOGGER.info("Closing Raknetify server %s".formatted(future.channel().localAddress()));
future.channel().close();
iterator.remove();
}
}

}
}
};
Expand Down
@@ -1,15 +1,14 @@
package com.ishland.raknetify.common.util;

import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
import it.unimi.dsi.fastutil.objects.ReferenceSet;
import it.unimi.dsi.fastutil.objects.ReferenceSets;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -39,44 +38,45 @@ public class NetworkInterfaceListener {
public static void init() {
}

private static final Object2ObjectOpenHashMap<String, NetworkInterface> knownInterfaces = new Object2ObjectOpenHashMap<>();
private static final ReferenceSet<Consumer<InterfaceChangeEvent>> listeners = ReferenceSets.synchronize(new ReferenceOpenHashSet<>());
private static final ObjectOpenHashSet<InetAddress> knownAddresses = new ObjectOpenHashSet<>();
private static final ReferenceSet<Consumer<InterfaceAddressChangeEvent>> listeners = ReferenceSets.synchronize(new ReferenceOpenHashSet<>());

private static void pollChanges() {
try {
final List<NetworkInterface> networkInterfaces = NetworkInterface.networkInterfaces().toList();
ObjectOpenHashSet<String> currentInterfaces = new ObjectOpenHashSet<>();
ObjectOpenHashSet<InetAddress> currentAddresses = new ObjectOpenHashSet<>();
for (NetworkInterface networkInterface : networkInterfaces) {
if (networkInterface.isUp()) {
currentInterfaces.add(networkInterface.getName());
if (knownInterfaces.put(networkInterface.getName(), networkInterface) == null) {
listeners.forEach(consumer -> consumer.accept(new InterfaceChangeEvent(true, networkInterface)));
for (InetAddress address : networkInterface.inetAddresses().toList()) {
currentAddresses.add(address);
if (knownAddresses.add(address)) {
listeners.forEach(consumer -> consumer.accept(new InterfaceAddressChangeEvent(true, address)));
}
}
}
}
final ObjectIterator<Map.Entry<String, NetworkInterface>> iterator = knownInterfaces.entrySet().iterator();
final ObjectIterator<InetAddress> iterator = knownAddresses.iterator();
while (iterator.hasNext()) {
final Map.Entry<String, NetworkInterface> entry = iterator.next();
if (!currentInterfaces.contains(entry.getKey())) {
final NetworkInterface networkInterface = entry.getValue();
final InetAddress address = iterator.next();
if (!currentAddresses.contains(address)) {
iterator.remove();
listeners.forEach(consumer -> consumer.accept(new InterfaceChangeEvent(false, networkInterface)));
listeners.forEach(consumer -> consumer.accept(new InterfaceAddressChangeEvent(false, address)));
}
}
} catch (Throwable t) {
t.printStackTrace();
}
}

public static void addListener(Consumer<InterfaceChangeEvent> consumer) {
public static void addListener(Consumer<InterfaceAddressChangeEvent> consumer) {
listeners.add(consumer);
}

public static void removeListener(Consumer<InterfaceChangeEvent> consumer) {
public static void removeListener(Consumer<InterfaceAddressChangeEvent> consumer) {
listeners.remove(consumer);
}

public record InterfaceChangeEvent(boolean added, NetworkInterface networkInterface) {
public record InterfaceAddressChangeEvent(boolean added, InetAddress address) {
}

}
Expand Up @@ -52,7 +52,7 @@ public abstract class MixinServerNetworkIo {

@Shadow @Final private List<ChannelFuture> channels;
@Unique
private Consumer<NetworkInterfaceListener.InterfaceChangeEvent> raknetify$eventListener = null;
private Consumer<NetworkInterfaceListener.InterfaceAddressChangeEvent> raknetify$eventListener = null;

@Inject(method = "bind", at = @At("HEAD"))
private void bindUdp(InetAddress address, int port, CallbackInfo ci) throws IOException {
Expand All @@ -65,7 +65,7 @@ private void bindUdp(InetAddress address, int port, CallbackInfo ci) throws IOEx
final Iterator<InetAddress> iterator = networkInterface.getInetAddresses().asIterator();
while (iterator.hasNext()) {
final InetAddress inetAddress = iterator.next();
System.out.println("Starting raknetify server on interface %s address %s".formatted(networkInterface.getName(), inetAddress));
System.out.println("Starting raknetify server on %s".formatted(inetAddress));
bind(inetAddress, hasPortOverride ? raknetify$portOverride : port);
}
}
Expand All @@ -78,29 +78,26 @@ private void bindUdp(InetAddress address, int port, CallbackInfo ci) throws IOEx
}
try {
ThreadLocalUtil.setInitializingRaknet(true);
final Iterator<InetAddress> iterator = event.networkInterface().getInetAddresses().asIterator();
while (iterator.hasNext()) {
final InetAddress inetAddress = iterator.next();
if (event.added()) {
System.out.println("Starting raknetify server on interface %s address %s".formatted(event.networkInterface().getName(), inetAddress));
try {
bind(inetAddress, hasPortOverride ? raknetify$portOverride : port);
} catch (IOException t) {
System.out.println("**** FAILED TO BIND TO PORT! %s".formatted(t.getMessage()));
} catch (Throwable t) {
t.printStackTrace();
}
} else {
synchronized (this.channels) {
for (Iterator<ChannelFuture> iter = this.channels.iterator(); iter.hasNext(); ) {
ChannelFuture channel = iter.next();
final SocketAddress socketAddress = channel.channel().localAddress();
if (socketAddress instanceof InetSocketAddress channelAddress) {
if (inetAddress.equals(channelAddress.getAddress())) {
System.out.println("Stopping raknetify server on interface %s address %s".formatted(event.networkInterface().getName(), inetAddress));
channel.channel().close();
iter.remove();
}
final InetAddress inetAddress = event.address();
if (event.added()) {
System.out.println("Starting raknetify server on %s".formatted(inetAddress));
try {
bind(inetAddress, hasPortOverride ? raknetify$portOverride : port);
} catch (IOException t) {
System.out.println("**** FAILED TO BIND TO PORT! %s".formatted(t.getMessage()));
} catch (Throwable t) {
t.printStackTrace();
}
} else {
synchronized (this.channels) {
for (Iterator<ChannelFuture> iter = this.channels.iterator(); iter.hasNext(); ) {
ChannelFuture channel = iter.next();
final SocketAddress socketAddress = channel.channel().localAddress();
if (socketAddress instanceof InetSocketAddress channelAddress) {
if (inetAddress.equals(channelAddress.getAddress())) {
System.out.println("Stopping raknetify server on %s".formatted(inetAddress));
channel.channel().close();
iter.remove();
}
}
}
Expand All @@ -115,6 +112,7 @@ private void bindUdp(InetAddress address, int port, CallbackInfo ci) throws IOEx
NetworkInterfaceListener.addListener(event -> this.server.submit(() -> raknetify$eventListener.accept(event)));
}
} else {
System.out.println("Starting raknetify server on %s".formatted(address));
bind(address, hasPortOverride ? raknetify$portOverride : port);
}
} finally {
Expand Down
@@ -0,0 +1,48 @@
package com.ishland.raknetify.velocity;

import com.ishland.raknetify.common.data.ProtocolMultiChannelMappings;
import com.ishland.raknetify.velocity.connection.RakNetVelocityConnectionUtil;
import com.ishland.raknetify.velocity.init.VelocityPacketRegistryInjector;
import com.ishland.raknetify.velocity.init.VelocityRaknetifyServer;
import com.velocitypowered.api.event.PostOrder;
import com.velocitypowered.api.event.connection.LoginEvent;
import com.velocitypowered.api.event.player.ServerPostConnectEvent;
import com.velocitypowered.api.event.proxy.ListenerBoundEvent;
import com.velocitypowered.api.event.proxy.ListenerCloseEvent;

import static com.ishland.raknetify.velocity.RaknetifyVelocityPlugin.INSTANCE;
import static com.ishland.raknetify.velocity.RaknetifyVelocityPlugin.LOGGER;
import static com.ishland.raknetify.velocity.RaknetifyVelocityPlugin.PROXY;

public class RaknetifyVelocityLaunchWrapper {

public static void launch() {
if (!isCompatible()) {
Runnable runnable = () -> {
LOGGER.error("This version of Raknetify is NOT compatible with your version of Velocity");
LOGGER.error("Please update your Velocity at https://papermc.io/downloads#Velocity");
};
runnable.run();
PROXY.getEventManager().register(INSTANCE, ListenerBoundEvent.class, PostOrder.LAST, ignored -> runnable.run());
return;
}

ProtocolMultiChannelMappings.init();
VelocityPacketRegistryInjector.inject();

PROXY.getEventManager().register(INSTANCE, LoginEvent.class, PostOrder.LAST, RakNetVelocityConnectionUtil::onPlayerLogin);
PROXY.getEventManager().register(INSTANCE, ListenerBoundEvent.class, PostOrder.LAST, VelocityRaknetifyServer::start);
PROXY.getEventManager().register(INSTANCE, ListenerCloseEvent.class, PostOrder.LAST, VelocityRaknetifyServer::stop);
PROXY.getEventManager().register(INSTANCE, ServerPostConnectEvent.class, PostOrder.LAST, RakNetVelocityConnectionUtil::onServerSwitch);
}

private static boolean isCompatible() {
try {
Class.forName("com.velocitypowered.proxy.crypto.EncryptionUtils");
return true;
} catch (ClassNotFoundException e) {
return false;
}
}

}

0 comments on commit 28c6e76

Please sign in to comment.