/*******************************************************************************
* gMix open source project - https://svs.informatik.uni-hamburg.de/gmix/
* Copyright (C) 2014 SVS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************/
package staticContent.framework.socket.datagram;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Random;
import staticContent.framework.AnonNode;
import staticContent.framework.routing.RoutingMode;
import staticContent.framework.socket.socketInterfaces.AdaptiveAnonSocket;
import staticContent.framework.socket.socketInterfaces.AnonMessage;
import staticContent.framework.socket.socketInterfaces.DatagramAnonSocket;
import staticContent.framework.util.Util;
public class DatagramAnonSocketClientImpl extends AdaptiveAnonSocket implements DatagramAnonSocket {
private HashMap<Integer, Integer> pseudonymToDestAddress = null;
public DatagramAnonSocketClientImpl(
AnonNode owner,
CommunicationDirection communicationMode,
boolean isReliable,
boolean isOrderPreserving,
boolean isFreeRoute
) {
super( owner,
communicationMode,
false,
isReliable,
isOrderPreserving,
isFreeRoute
);
if (isDuplex)
this.pseudonymToDestAddress = new HashMap<Integer, Integer>(100);
if (owner.ROUTING_MODE == RoutingMode.GLOBAL_ROUTING)
layer4.connect();
}
@Override
public void sendMessage(int destPort, byte[] payload) {
if (isFreeRoute)
throw new RuntimeException("no destination address specified; use \"sendMessage(destinationPseudonym, destPort, payload\" instead");
payload = Util.concatArrays(Util.shortToByteArray(destPort), payload); // add destination port (= which layer 5 service/ServerSocket shall be addressed)
//Request request = MixMessage.getInstanceRequest(payload);
layer4.write(payload);
}
@Override
public void sendMessage(int destinationPseudonym, int destinationPort, byte[] payload) {
if (!isFreeRoute)
throw new RuntimeException("this is a fixed route socket; you cannot specify a destination address; use \"sendMessage(destPort, payload\" instead");
if (isDuplex) { // add a pseudonym so the receiver's reply can be identified (the receiver will include this pseudonym in his reply)
int endToEndPseudonym = new Random().nextInt(); // TODO
pseudonymToDestAddress.put(endToEndPseudonym, destinationPseudonym);
payload = Util.concatArrays(Util.intToByteArray(endToEndPseudonym), payload);
}
payload = Util.concatArrays(Util.shortToByteArray(destinationPort), payload); // add destination port (= which layer 5 service/ServerSocket shall be addressed)
//Request request = MixMessage.getInstanceRequest(payload);
//request.destinationPseudonym = destinationPseudonym;
layer4.write(payload, destinationPseudonym);
}
@Override
public AnonMessage receiveMessage() {
if (!isDuplex)
throw new RuntimeException("this is a simplex socket");
byte[] reply = layer4.receive();
assert reply != null && reply.length != 0;
AnonMessage result = new AnonMessage(reply);
// TODO: add support for multiple services (requires l4-plugin-support...)
//int sourcePort = Util.byteArrayToShort(Arrays.copyOf(reply, 2));
//result.setByteMessage(Arrays.copyOfRange(reply, 2, reply.length));
//result.setSourcePort(sourcePort);
if (isFreeRoute) {
int endToEndPseudonym = Util.byteArrayToInt(Arrays.copyOf(result.getByteMessage(), 4));
result.setByteMessage(Arrays.copyOfRange(result.getByteMessage(), 4, result.getByteMessage().length));
Integer sourcePseudonym = pseudonymToDestAddress.remove(endToEndPseudonym);
if (sourcePseudonym == null) {
System.err.println("received reply with unknown id");
return receiveMessage();
}
result.setSourcePseudonym(sourcePseudonym);
}
return result;
}
@Override
public int getMaxSizeForNextMessageSend() {
if (isFreeRoute)
return layer4.getMaxSizeOfNextWrite() -6; // -2 for port; -4 for pseudonym; see sendMessage()
else
return layer4.getMaxSizeOfNextWrite() -2; // -2 for port; see sendMessage()
}
@Override
public int getMaxSizeForNextMessageReceive() {
if (!isDuplex)
throw new RuntimeException("this socket is simplex only");
// TODO: add support for multiple services (requires l4-plugin-support...)
//int maxSize = layer4.getMaxSizeOfNextReply() -2; // -2 for port
//if (isFreeRoute)
// maxSize -= 4; // pseudonym
//return maxSize;
if (isFreeRoute)
return layer4.getMaxSizeOfNextReply() - 4;
else
return layer4.getMaxSizeOfNextReply();
}
@Override
public AdaptiveAnonSocket getImplementation() {
return this;
}
@Override
public int availableReplies() {
return layer4.availableReplies();
}
}