/******************************************************************************* * Copyright 2015 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.util.net.udp; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.SocketTimeoutException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; /** * udp stream sender used by the udp and voip qos test * @author lb * */ public class UdpStreamSender implements StreamSender<DatagramSocket> { UdpStreamSenderSettings<DatagramSocket> settings; UdpStreamCallback callback; final AtomicBoolean isRunning = new AtomicBoolean(false); public UdpStreamSender(UdpStreamSenderSettings<DatagramSocket> settings, UdpStreamCallback callback) { this.settings = settings; this.callback = callback; } public void stop() { isRunning.set(false); } /** * send a stream of udp packets * @return the {@link DatagramSocket} used for this stream or null if an exception occurred * @throws InterruptedException * @throws TimeoutException */ public DatagramSocket send() throws InterruptedException, TimeoutException { System.out.println("UDP Stream: " + settings); isRunning.set(true); int packetsSent = 0; final ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); final DataOutputStream dataOut = new DataOutputStream(byteOut); byte[] data; final long delayMs = TimeUnit.MILLISECONDS.convert(settings.delay, settings.timeUnit); long lastSendTimestamp = 0; final long startTimeMs = System.currentTimeMillis(); final long timeoutMs = TimeUnit.MILLISECONDS.convert(settings.timeout, settings.timeUnit); final long stopTimeMs = timeoutMs > 0 ? timeoutMs + startTimeMs : 0; while(isRunning.get()) { if (Thread.interrupted()) { isRunning.set(false); throw new InterruptedException(); } if (stopTimeMs > 0 && stopTimeMs < System.currentTimeMillis()) { isRunning.set(false); throw new TimeoutException(); } //calculate correct packet delay long currentDelay = System.currentTimeMillis() - lastSendTimestamp; currentDelay = currentDelay > delayMs ? 0 : delayMs - currentDelay; if (currentDelay > 0) { Thread.sleep(currentDelay); } byteOut.reset(); try { if (callback != null && callback.onSend(dataOut, packetsSent)) { data = byteOut.toByteArray(); DatagramPacket packet = null; if (!settings.socket.isConnected()) { packet = new DatagramPacket(data, data.length, settings.targetHost, settings.targetPort); } else { packet = new DatagramPacket(data, data.length); } settings.socket.send(packet); packetsSent++; lastSendTimestamp = System.currentTimeMillis(); } if (!settings.writeOnly) { try { byte buffer[] = new byte[1024]; DatagramPacket dp = new DatagramPacket(buffer, buffer.length); settings.socket.setSoTimeout((int) TimeUnit.MILLISECONDS.convert(settings.responseSoTimeout, settings.timeUnit)); settings.socket.receive(dp); if (callback != null) { callback.onReceive(dp); } } catch (SocketTimeoutException e) { e.printStackTrace(); } } if (packetsSent >= settings.packets) { isRunning.set(false); } } catch (IOException e) { e.printStackTrace(); if (settings.closeOnFinish) { settings.socket.close(); } return null; } } return settings.socket; } }