/******************************************************************************* * Copyright 2013-2016 alladin-IT GmbH * * 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 at.alladin.rmbt.qos.testserver.udp; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.text.DateFormat; import java.util.Date; import java.util.concurrent.atomic.AtomicBoolean; import at.alladin.rmbt.qos.testserver.ServerPreferences.TestServerServiceEnum; import at.alladin.rmbt.qos.testserver.servers.AbstractUdpServer; import at.alladin.rmbt.qos.testserver.TestServer; import at.alladin.rmbt.qos.testserver.util.TestServerConsole; import at.alladin.rmbt.util.net.rtp.RealtimeTransportProtocol.RtpVersion; import at.alladin.rmbt.util.net.rtp.RtpUtil; /** * * @author lb * */ public class UdpMultiClientServer extends AbstractUdpServer<DatagramSocket> implements Runnable { private final static String TAG = UdpMultiClientServer.class.getCanonicalName(); private final AtomicBoolean isRunning; public final static int BUFFER_LENGTH = 1024; final InetAddress address; final int port; private final String name; private long lastClientTime = 0; protected final DatagramSocket socket; /** * * @param port * @param timeOut * @throws Exception */ public UdpMultiClientServer(int port, InetAddress address) throws Exception { super(DatagramSocket.class); TestServerConsole.log("Initializing " + TAG + " on " + address + ":" + port, 1, TestServerServiceEnum.TEST_SERVER); //this.socket = new DatagramSocket(port, TestServer.serverPreferences.getInetAddrBindTo()); this.socket = TestServer.createDatagramSocket(port, address); this.port = port; this.isRunning = new AtomicBoolean(false); this.address = address; this.name = "UdpMultiClientServer [" + address + ":" + port + "]"; } /** * * @param socket */ public UdpMultiClientServer(DatagramSocket socket) { super(DatagramSocket.class); this.socket = socket; this.port = socket.getLocalPort(); this.address = socket.getLocalAddress(); this.isRunning = new AtomicBoolean(false); this.name = "UdpMultiClientServer [" + address + ":" + socket.getLocalPort() + "]"; } /* * (non-Javadoc) * @see java.lang.Runnable#run() */ @Override public void run() { isRunning.set(true); TestServerConsole.log("Starting " + TAG + " on address: " + socket.getLocalAddress() + ":" + socket.getLocalPort() + " ...", 2, TestServerServiceEnum.UDP_SERVICE); try { while (isRunning.get()) { byte[] buffer = new byte[BUFFER_LENGTH]; final DatagramPacket dp = new DatagramPacket(buffer, BUFFER_LENGTH); socket.receive(dp); //set last client timestamp lastClientTime = System.currentTimeMillis(); final byte[] data = dp.getData(); final RtpVersion rtpVersion = RtpUtil.getVersion(data[0]); String clientUuid = null; if (!RtpVersion.VER2.equals(rtpVersion)) { //Non RTP packet: final int packetNumber = data[1]; String timeStamp = null; try { char[] uuid = new char[36]; for (int i = 2; i < 38; i++) { uuid[i - 2] = (char) data[i]; } clientUuid = String.valueOf(uuid); char[] ts = new char[dp.getLength() - 38]; for (int i = 38; i < dp.getLength(); i++) { ts[i - 38] = (char) data[i]; } timeStamp = String.valueOf(ts); } catch (Exception e) { TestServerConsole.error(getName(), e, 1, TestServerServiceEnum.UDP_SERVICE); } TestServerConsole.log("received UDP from: " + dp.getAddress().toString() + ":" + dp.getPort() + " (on local port :" + socket.getLocalPort() + ") , #" + packetNumber + " TimeStamp: " + timeStamp + ", containing: " + clientUuid, 1, TestServerServiceEnum.UDP_SERVICE); } else { //RtpPacket received: clientUuid = "VOIP_" + RtpUtil.getSsrc(data); } if (clientUuid != null) { synchronized (incomingMap) { final UdpTestCandidate clientData; final String uuid = clientUuid; if (!incomingMap.containsKey(clientUuid)) { clientData = new UdpTestCandidate(); clientData.setNumPackets(Integer.MAX_VALUE); clientData.setRemotePort(dp.getPort()); incomingMap.put(clientUuid, clientData); } else { clientData = (UdpTestCandidate) incomingMap.get(clientUuid); if (clientData.isError()) { continue; } } //if a callback has been provided by the clienthandler run it in the background: if (clientData.getOnUdpPacketReceivedCallback() != null) { Runnable onReceiveRunnable = new Runnable() { @Override public void run() { clientData.getOnUdpPacketReceivedCallback().onReceive(dp, uuid, UdpMultiClientServer.this); } }; TestServer.getCommonThreadPool().submit(onReceiveRunnable); } } } } } catch (IOException e) { TestServerConsole.error(getName(), e, 0, TestServerServiceEnum.UDP_SERVICE); } finally { if (!socket.isClosed()) { socket.close(); } } TestServerConsole.log("UdpMultiServer shutdown on port: " + socket.getLocalPort(), 1, TestServerServiceEnum.UDP_SERVICE); } /** * * @return */ public boolean getIsRunning() { return isRunning.get(); } /** * */ public void quit() { isRunning.set(false); TestServerConsole.log("UdpServer received quit command on port: " + socket.getLocalPort(), 1, TestServerServiceEnum.UDP_SERVICE); } /* * (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "UdpMultiClientServer [isRunning=" + isRunning + ", socket=" + socket + ", address=" + address + ", incomingMap=" + incomingMap + "]" + toStringExtra(); } /** * * @return */ public String toStringExtra() { return " \n\t Socket additional info [local port=" + socket.getLocalPort() + ", connected=" + socket.isConnected() + ", bound=" + socket.isBound() + ", closed=" + socket.isClosed() +"]"; } /** * * @return */ public String getName() { return name; } /** * * @return */ public InetAddress getAddress() { return address; } /** * */ public int getLocalPort() { return port; } /* * (non-Javadoc) * @see at.alladin.rmbt.qos.testserver.udp.AbstractCandidateHandler#getSocket() */ @Override public DatagramSocket getSocket() { return socket; } /* * (non-Javadoc) * @see at.alladin.rmbt.qos.testserver.udp.AbstractUdpServer#send(java.net.DatagramPacket) */ @Override public void send(DatagramPacket dp) throws IOException { socket.send(dp); } /* * (non-Javadoc) * @see at.alladin.rmbt.qos.testserver.udp.AbstractUdpServer#isHealthy() */ @Override public boolean isHealthy() { return socket != null && !socket.isClosed(); } /* * (non-Javadoc) * @see at.alladin.rmbt.qos.testserver.entity.Observable#getStatusMessage() */ @Override public String getStatusMessage() { return "Last client timestamp: " + DateFormat.getDateTimeInstance().format(new Date(lastClientTime)); } }