All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dorkbox.network.connection.RegistrationWrapper Maven / Gradle / Ivy

/*
 * Copyright 2010 dorkbox, llc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package dorkbox.network.connection;

import dorkbox.network.connection.registration.MetaChannel;
import dorkbox.network.pipeline.KryoEncoder;
import dorkbox.network.pipeline.KryoEncoderCrypto;
import dorkbox.util.collections.IntMap;
import dorkbox.util.crypto.CryptoECC;
import dorkbox.util.exceptions.SecurityException;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.slf4j.Logger;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.security.SecureRandom;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Just wraps common/needed methods of the client/server endpoint by the registration stage/handshake.
 * 

* This is in the connection package, so it can access the endpoint methods that it needs to. */ public class RegistrationWrapper implements UdpServer { private final org.slf4j.Logger logger; private final KryoEncoder kryoEncoder; private final KryoEncoderCrypto kryoEncoderCrypto; private final EndPoint endPoint; // keeps track of connections (TCP/UDT/UDP-client) private final ReentrantLock channelMapLock = new ReentrantLock(); private final IntMap channelMap = new IntMap(); // keeps track of connections (UDP-server) // this is final, because the REFERENCE to these will never change. They ARE NOT immutable objects (meaning their content can change) private final ConcurrentMap udpRemoteMap; public RegistrationWrapper(final EndPoint endPoint, final Logger logger, final KryoEncoder kryoEncoder, final KryoEncoderCrypto kryoEncoderCrypto) { this.endPoint = endPoint; this.logger = logger; this.kryoEncoder = kryoEncoder; this.kryoEncoderCrypto = kryoEncoderCrypto; if (endPoint instanceof EndPointServer) { this.udpRemoteMap = new ConcurrentHashMap(); } else { this.udpRemoteMap = null; } } /** * @return true if RMI is enabled */ public boolean rmiEnabled() { return endPoint.globalRmiBridge != null; } public KryoEncoder getKryoEncoder() { return this.kryoEncoder; } public KryoEncoderCrypto getKryoEncoderCrypto() { return this.kryoEncoderCrypto; } /** * Locks, and then returns the channelMap used by the registration process. *

* Make SURE to use this in a try/finally block with releaseChannelMap in the finally block! */ public IntMap getAndLockChannelMap() { // try to lock access, also guarantees that the contents of this map are visible across threads this.channelMapLock.lock(); return this.channelMap; } public void releaseChannelMap() { // try to unlock access this.channelMapLock.unlock(); } /** * The amount of milli-seconds that must elapse with no read or write before {@link Listener:idle()} will be triggered */ public int getIdleTimeout() { return this.endPoint.getIdleTimeout(); } /** * Internal call by the pipeline to notify the client to continue registering the different session protocols. The server does not use * this. * * @return true if we are done registering bootstraps */ public boolean registerNextProtocol0() { return this.endPoint.registerNextProtocol0(); } /** * Internal call by the pipeline to notify the "Connection" object that it has "connected", meaning that modifications to the pipeline * are finished. */ public void connectionConnected0(ConnectionImpl networkConnection) { this.endPoint.connectionConnected0(networkConnection); } /** * Internal call by the pipeline when: - creating a new network connection - when determining the baseClass for generics * * @param metaChannel * can be NULL (when getting the baseClass) */ public Connection connection0(MetaChannel metaChannel) { return this.endPoint.connection0(metaChannel); } public SecureRandom getSecureRandom() { return this.endPoint.secureRandom; } public ECPublicKeyParameters getPublicKey() { return this.endPoint.publicKey; } public CipherParameters getPrivateKey() { return this.endPoint.privateKey; } public boolean validateRemoteServerAddress(final InetSocketAddress tcpRemoteServer, final ECPublicKeyParameters publicKey) throws SecurityException { if (this.endPoint.disableRemoteKeyValidation) { return true; } InetAddress address = tcpRemoteServer.getAddress(); byte[] hostAddress = address.getAddress(); ECPublicKeyParameters savedPublicKey = this.endPoint.propertyStore.getRegisteredServerKey(hostAddress); Logger logger2 = this.logger; if (savedPublicKey == null) { if (logger2.isDebugEnabled()) { logger2.debug("Adding new remote IP address key for {}", address.getHostAddress()); } this.endPoint.propertyStore.addRegisteredServerKey(hostAddress, publicKey); } else { // COMPARE! if (!CryptoECC.compare(publicKey, savedPublicKey)) { String byAddress; try { byAddress = InetAddress.getByAddress(hostAddress) .getHostAddress(); } catch (UnknownHostException e) { byAddress = "Unknown"; } //whoa! abort since something messed up! logger2.error("Invalid or non-matching public key from remote server. Their public key has changed. To fix, remove entry for: {}", byAddress); return false; } } return true; } @SuppressWarnings("AutoBoxing") public void removeRegisteredServerKey(final byte[] hostAddress) throws SecurityException { ECPublicKeyParameters savedPublicKey = this.endPoint.propertyStore.getRegisteredServerKey(hostAddress); if (savedPublicKey != null) { Logger logger2 = this.logger; if (logger2.isDebugEnabled()) { logger2.debug("Deleteing remote IP address key {}.{}.{}.{}", hostAddress[0], hostAddress[1], hostAddress[2], hostAddress[3]); } this.endPoint.propertyStore.removeRegisteredServerKey(hostAddress); } } /** * ONLY SERVER SIDE CALLS THIS Called when creating a connection. Only called if we have a UDP channel */ @Override public final void registerServerUDP(final MetaChannel metaChannel) { if (metaChannel != null && metaChannel.udpRemoteAddress != null) { this.udpRemoteMap.put(metaChannel.udpRemoteAddress, metaChannel.connection); this.logger.info("Connected to remote UDP connection. [{} <== {}]", metaChannel.udpChannel.localAddress(), metaChannel.udpRemoteAddress); } } /** * ONLY SERVER SIDE CALLS THIS Called when closing a connection. */ @Override public final void unRegisterServerUDP(final InetSocketAddress udpRemoteAddress) { if (udpRemoteAddress != null) { this.udpRemoteMap.remove(udpRemoteAddress); logger.info("Closed remote UDP connection: {}", udpRemoteAddress); } } /** * ONLY SERVER SIDE CALLS THIS */ @Override public ConnectionImpl getServerUDP(final InetSocketAddress udpRemoteAddress) { if (udpRemoteAddress != null) { return this.udpRemoteMap.get(udpRemoteAddress); } else { return null; } } public void abortRegistrationIfClient() { if (this.endPoint instanceof EndPointClient) { ((EndPointClient) this.endPoint).abortRegistration(); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy