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

lowentry.ue4.classes.sockets.SocketConnectionHandler Maven / Gradle / Ivy

There is a newer version: 9.9.9.DELETED
Show newest version
package lowentry.ue4.classes.sockets;


import java.io.IOException;
import java.nio.ByteBuffer;

import lowentry.ue4.classes.sockets.SocketConnection.InternalFunctionCall;
import lowentry.ue4.classes.sockets.SocketConnection.InternalLatentFunctionCall;
import lowentry.ue4.libs.pyronet.jawnae.pyronet.PyroClient;
import lowentry.ue4.libs.pyronet.jawnae.pyronet.events.PyroClientListener;
import lowentry.ue4.libs.pyronet.lowentry.pyronet.udp.event.PyroClientUdpListener;


public class SocketConnectionHandler implements PyroClientListener, PyroClientUdpListener
{
	protected static enum ConnectingStage
	{
		WAITING, UNCONNECTABLE, CONNECTED
	};
	
	protected static enum ReceivingStage
	{
		RECEIVE_TYPE, RECEIVE_FUNCTION_CALL_ID, RECEIVE_PACKET_SIZE, RECEIVE_PACKET
	};
	
	
	protected final SocketConnectionListener	socketListener;
	protected final SocketConnection			connection;
	
	protected ConnectingStage					connectingStage					= ConnectingStage.WAITING;
	
	
	protected boolean							socketListenerCalledConnected	= false;
	
	
	protected boolean							stopReceivingAnything			= false;
	
	protected ReceivingStage					receivingStage					= ReceivingStage.RECEIVE_TYPE;
	protected byte								receivingType					= 0;
	protected int								receivingFunctionCallId			= 0;
	protected int								receivingPacketSize				= 0;
	protected byte[]							receivingPacket					= null;
	protected int								receivingPacketPosition			= 0;
	
	protected ByteBuffer						receivedIntegerBuffer			= ByteBuffer.allocate(4);
	
	
	public SocketConnectionHandler(SocketConnectionListener socketListener, SocketConnection connection)
	{
		this.socketListener = socketListener;
		this.connection = connection;
	}
	
	
	@Override
	public void unconnectableClient(final PyroClient client)
	{
		if(connectingStage == ConnectingStage.WAITING)
		{
			connectingStage = ConnectingStage.UNCONNECTABLE;
		}
	}
	
	@Override
	public void connectedClient(final PyroClient client)
	{
		if(connectingStage == ConnectingStage.WAITING)
		{
			connectingStage = ConnectingStage.CONNECTED;
		}
	}
	
	public void callConnected()
	{
		if(!socketListenerCalledConnected)
		{
			socketListenerCalledConnected = true;
			socketListener.connected(connection);
		}
	}
	
	@Override
	public void droppedClient(final PyroClient client, final IOException cause)
	{
		stopReceivingAnything = true;
		receivingPacket = null;
		receivedIntegerBuffer = null;
		if(socketListenerCalledConnected)
		{
			socketListener.disconnected(connection);
		}
		connection.failAllFunctionCalls();
	}
	
	@Override
	public void disconnectedClient(final PyroClient client)
	{
		stopReceivingAnything = true;
		receivingPacket = null;
		receivedIntegerBuffer = null;
		if(socketListenerCalledConnected)
		{
			socketListener.disconnected(connection);
		}
		connection.failAllFunctionCalls();
	}
	
	@Override
	public void sentData(final PyroClient client, final int bytes)
	{
	}
	
	public void disconnect()
	{
		stopReceivingAnything = true;
		receivingPacket = null;
		receivedIntegerBuffer = null;
		connection.disconnect();
	}
	
	@Override
	public void receivedDataUdp(ByteBuffer data)
	{
		if(connection.connectionUdp != null)
		{
			byte[] bytes = new byte[data.remaining()];
			data.get(bytes);
			socketListener.receivedUnreliableMessage(connection, bytes);
		}
	}
	
	/**
	 * Returns -1 if it failed.
	 */
	protected int receiveUint(final ByteBuffer data)
	{
		if(!data.hasRemaining())
		{
			return -1;
		}
		if(receivedIntegerBuffer.position() == 0)
		{
			byte firstByte = data.get();
			if(((firstByte >> 7) & 1) == 0)
			{
				return (firstByte & 0xFF);
			}
			receivedIntegerBuffer.put(firstByte);
		}
		while(data.hasRemaining() && (receivedIntegerBuffer.position() < 4))
		{
			receivedIntegerBuffer.put(data.get());
		}
		if(receivedIntegerBuffer.position() < 4)
		{
			// not enough bytes to get the an integer
			return -1;
		}
		receivedIntegerBuffer.flip();
		byte b1 = receivedIntegerBuffer.get();
		byte b2 = receivedIntegerBuffer.get();
		byte b3 = receivedIntegerBuffer.get();
		byte b4 = receivedIntegerBuffer.get();
		receivedIntegerBuffer.clear();
		int value = (((b1 & 0xFF) & ~(1 << 7)) << 24) | ((b2 & 0xFF) << 16) | ((b3 & 0xFF) << 8) | (b4 & 0xFF);
		if(value <= 127)
		{
			// should not be possible
			disconnect();
			return -1;
		}
		return value;
	}
	
	@Override
	public void receivedData(final PyroClient client, final ByteBuffer data)
	{
		if(stopReceivingAnything)
		{
			return;
		}
		while(data.hasRemaining())
		{
			{// get type >>
				if(receivingStage == ReceivingStage.RECEIVE_TYPE)
				{
					receivingType = data.get();
					
					if(receivingType == SocketMessageType.MESSAGE)
					{
						receivingStage = ReceivingStage.RECEIVE_PACKET_SIZE;
					}
					else if(receivingType == SocketMessageType.FUNCTION_CALL_RESPONSE)
					{
						receivingStage = ReceivingStage.RECEIVE_FUNCTION_CALL_ID;
					}
					else if(receivingType == SocketMessageType.LATENT_FUNCTION_CALL_RESPONSE)
					{
						receivingStage = ReceivingStage.RECEIVE_FUNCTION_CALL_ID;
					}
					else if(receivingType == SocketMessageType.LATENT_FUNCTION_CALL_CANCELED)
					{
						receivingStage = ReceivingStage.RECEIVE_FUNCTION_CALL_ID;
					}
					else
					{
						// received invalid type
						disconnect();
						return;
					}
				}
			}// get type <<
			
			{// get function call id >>
				if(receivingStage == ReceivingStage.RECEIVE_FUNCTION_CALL_ID)
				{
					int receivedUint = receiveUint(data);
					if(receivedUint < 0)
					{
						return;
					}
					receivingFunctionCallId = receivedUint;
					
					if(receivingType == SocketMessageType.LATENT_FUNCTION_CALL_CANCELED)
					{
						InternalLatentFunctionCall functionCall = null;
						synchronized(connection.latentFunctionCalls)
						{
							functionCall = connection.latentFunctionCalls.remove(receivingFunctionCallId);
						}
						if(functionCall != null)
						{
							if(functionCall.latentAction != null)
							{
								functionCall.latentAction.canceledByServer();
							}
							if(functionCall.listener != null)
							{
								connection.canceledLatentFunctionCall(functionCall.listener);
							}
						}
						
						receivingStage = ReceivingStage.RECEIVE_TYPE;
					}
					else
					{
						receivingStage = ReceivingStage.RECEIVE_PACKET_SIZE;
					}
				}
			}// get function call id <<
			
			{// get packet size >>
				if(receivingStage == ReceivingStage.RECEIVE_PACKET_SIZE)
				{
					int receivedUint = receiveUint(data);
					if(receivedUint < 0)
					{
						return;
					}
					receivingPacketSize = receivedUint;
					
					receivingPacket = new byte[receivingPacketSize];
					receivingStage = ReceivingStage.RECEIVE_PACKET;
				}
			}// get packet size <<
			
			{// receiving packet >>
				if(receivingStage == ReceivingStage.RECEIVE_PACKET)
				{
					if(!data.hasRemaining())
					{
						return;
					}
					
					int packetBytesRemaining = receivingPacketSize - receivingPacketPosition;
					if(data.remaining() <= packetBytesRemaining)
					{
						int length = data.remaining();
						data.get(receivingPacket, receivingPacketPosition, length);
						receivingPacketPosition += length;
					}
					else
					{
						int length = packetBytesRemaining;
						data.get(receivingPacket, receivingPacketPosition, length);
						receivingPacketPosition += length;
					}
					
					if(receivingPacketPosition >= receivingPacketSize) // packetBytesRemaining <= 0
					{
						if(receivingType == SocketMessageType.MESSAGE)
						{
							socketListener.receivedMessage(connection, receivingPacket);
						}
						else if(receivingType == SocketMessageType.FUNCTION_CALL_RESPONSE)
						{
							InternalFunctionCall functionCall = null;
							synchronized(connection.functionCalls)
							{
								functionCall = connection.functionCalls.remove(receivingFunctionCallId);
							}
							if((functionCall != null) && (functionCall.listener != null))
							{
								connection.receivedResponseFunctionCall(functionCall.listener, receivingPacket);
							}
						}
						else if(receivingType == SocketMessageType.LATENT_FUNCTION_CALL_RESPONSE)
						{
							InternalLatentFunctionCall functionCall = null;
							synchronized(connection.latentFunctionCalls)
							{
								functionCall = connection.latentFunctionCalls.remove(receivingFunctionCallId);
							}
							if(functionCall != null)
							{
								if(functionCall.latentAction != null)
								{
									functionCall.latentAction.done();
								}
								if(functionCall.listener != null)
								{
									connection.receivedResponseLatentFunctionCall(functionCall.listener, receivingPacket);
								}
							}
						}
						else
						{
							// received invalid type
							disconnect();
							return;
						}
						
						receivingStage = ReceivingStage.RECEIVE_TYPE;
						receivingPacket = null;
						receivingPacketPosition = 0;
					}
				}
			}// receiving packet <<
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy