/*
* TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
* Jitsi community (http://jitsi.org).
*
* Copyright @ 2015 Atlassian Pty Ltd
*
* 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 org.jitsi.turnserver.stack;
import java.util.*;
import java.util.logging.*;
import org.ice4j.*;
import org.ice4j.message.*;
import org.ice4j.stack.*;
/**
* Class to handle UDP messages coming from Peer. The class first checks if
* there is a non-expired ChannelBind for the peer if yes it then sends a
* ChannelData message to Client. If no it then finds if there is a non-expired
* permission if yes then it sends a DataIndicatio to Client. All the mesages
* sent to client here are from the address on which the allocation request was
* received or the serverAddress of fiveTuple of corresponding Allocation.
*
* @author Aakash Garg
*/
public class ServerPeerUdpEventHandler
implements PeerUdpMessageEventHandler
{
/**
* The <tt>Logger</tt> used by the <tt>PeerUdpMessageEventHandler</tt> class
* and its instances for logging output.
*/
private static final Logger logger = Logger
.getLogger(ServerPeerUdpEventHandler.class.getName());
/**
* The turnStack to call.
*/
private TurnStack turnStack;
/**
* Default constructor.
*/
public ServerPeerUdpEventHandler()
{
}
/**
* Parametrized constructor.
*
* @param turnStack the turnStack to set for this class.
*/
public ServerPeerUdpEventHandler(StunStack turnStack)
{
if (turnStack instanceof TurnStack)
{
this.turnStack = (TurnStack) turnStack;
}
else
{
throw new IllegalArgumentException("This is not a TurnStack!");
}
}
public void setTurnStack(TurnStack turnStack)
{
this.turnStack = turnStack;
}
/**
* Handles the PeerUdpMessageEvent.
*
* @param evt the PeerUdpMessageEvent to handle/process.
*/
@Override
public void handleMessageEvent(PeerUdpMessageEvent evt)
{
if (logger.isLoggable(Level.FINER))
{
logger.setLevel(Level.FINEST);
logger.finer("Received Peer UdP message message " + evt);
}
byte[] data = evt.getBytes();
TransportAddress localAddress = evt.getLocalAddress();
TransportAddress remoteAddress = evt.getRemoteAddress();
logger.finest("Received a UDP message on: " + localAddress + ", data: "
+ byteArrayToHex(data));
Allocation allocation =
this.turnStack.getServerAllocation(localAddress);
if (remoteAddress.getTransport() == Transport.TCP)
{
FiveTuple fiveTuple =
new FiveTuple(remoteAddress, localAddress, Transport.TCP);
logger.finest("Send message request from "+fiveTuple);
if (allocation == null) // came from client
{
// get client allocation
logger.finest("Message came from TCP Client");
int connectionId =
this.turnStack.getConnectionIdForDataConn(fiveTuple);
logger.finest("Connection Id extracted for "+fiveTuple+" is "+connectionId);
allocation = this.turnStack.getAllocationFromConnectionId(connectionId);
logger.finest("Allocation extracted is "+allocation+" for client-"+fiveTuple);
FiveTuple peerTuple =
allocation.getPeerTCPConnection(connectionId);
TransportAddress peerAddress =
peerTuple.getClientTransportAddress();
TransportAddress relayAddress =
peerTuple.getServerTransportAddress();
RawMessage rawMessage =
RawMessage.build(data, data.length, peerAddress,
relayAddress);
try
{
logger.finest("Relaying data to peer-" + peerAddress
+ " from " + remoteAddress+" data-");
this.turnStack.sendUdpMessage(
rawMessage, peerAddress, relayAddress);
}
catch (StunException e)
{
System.err.println("Unable to relay message to peer-"
+ peerAddress + " from client-" + remoteAddress
+ " message-" + Arrays.toString(data));
}
}
else
{
// else came from peer
logger.finest("Message came from TCP peer.");
int connectionId =
this.turnStack.getConnectionIdForPeer(fiveTuple);
if (!allocation.isPermitted(remoteAddress))
{
logger.finest("No permission installed for peer-"+remoteAddress);
return;
}
else
{
TransportAddress dataConn = allocation.getDataConnection(
connectionId).getClientTransportAddress();
if (dataConn != null)
{
RawMessage rawMessage =
RawMessage.build(data, data.length, dataConn,
allocation.getServerAddress());
try
{
logger.finest("Relaying data to client-" + dataConn
+ " from peer-" + remoteAddress);
this.turnStack.sendUdpMessage(
rawMessage, dataConn,
allocation.getServerAddress());
}
catch (StunException e)
{
System.err
.println("Unable to relay message to client-"
+ dataConn + " from peer-" + remoteAddress
+ " message-" + Arrays.toString(data));
}
}else{
logger.finest("No data connection found for peer-"
+ remoteAddress);
}
}
}
}
else if (allocation != null
&& allocation.getChannel(remoteAddress) != 0x1000)
{
char channelNo = allocation.getChannel(remoteAddress);
ChannelData channelData = new ChannelData();
channelData.setChannelNumber(channelNo);
channelData.setData(data);
try
{
logger.finest("Sending a ChannelData message " + channelData
+ " from " + allocation.getServerAddress() + " to "
+ allocation.getClientAddress());
this.turnStack.sendChannelData(
channelData, allocation.getClientAddress(),
allocation.getServerAddress());
}
catch (StunException ex)
{
logger.finer(ex.getMessage());
}
}
else if (allocation != null && allocation.isPermitted(remoteAddress))
{
TransactionID tranID = TransactionID.createNewTransactionID();
Indication dataInd = MessageFactory.createDataIndication(
remoteAddress, data, tranID.getBytes());
try
{
logger.finest("Sending a ChannelData message " + dataInd
+ " from " + allocation.getServerAddress() + " to "
+ allocation.getClientAddress());
this.turnStack.sendIndication(
dataInd, allocation.getClientAddress(),
allocation.getServerAddress());
}
catch (StunException e)
{
logger.finer(e.getMessage());
}
}else{
logger
.finest("unable to find allocation and the message is not on TCP.");
}
}
private String byteArrayToHex(byte[] data){
String arrayToHex= "";
for(int i=0; i<data.length; i++){
arrayToHex += String.format("%02X, ", data[i]);
}
return arrayToHex;
}
}