/* * 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; } }