Something went wrong on our end
-
Brutzman, Don authoredBrutzman, Don authored
AllPduSender.java 25.90 KiB
package OpenDis7Examples;
import java.io.*;
import java.net.*;
import java.util.*;
import edu.nps.moves.dis7.pdus.*;
import edu.nps.moves.dis7.enumerations.*;
/**
* This is an application example that sends all types of PDUs. Useful for testing standards
* compliance or getting a full set of PDUs. It also writes the generated PDUs to an XML file.
* Adapted from OpenDIS library example package edu.nps.moves.examples
*
* @author DMcG
* @version $Id:$
*/
public class AllPduSender
{
/** Default multicast group address we send on.
* @see <a href="https://en.wikipedia.org/wiki/Multicast_address">https://en.wikipedia.org/wiki/Multicast_address</a> */
public static final String DEFAULT_MULTICAST_ADDRESS = "239.1.2.3"; // PduRecorder "225.4.5.6"; //
/** Default multicast port used, matches Wireshark DIS capture default
* @see <a href="https://en.wikipedia.org/wiki/Port_(computer_networking)">https://en.wikipedia.org/wiki/Port_(computer_networking)</a> */
public static final int DEFAULT_MULTICAST_PORT = 3000;
/** Duration in milliseconds, set to 0 to avoid pausing between PDU sends */
private long THREAD_SLEEP_INTERVAL = 0;
/** Number of complete loops to perform.
* Putting any upper limit on # packets sent avoids possibility of non-terminating infinite loops that continue sending packets. */
private int SEND_LOOPS_TO_PERFORM = 1;
private static InetAddress multicastInetAddress;
private static int port;
/** Object constructor
* @param newMulticastAddress address of interest
* @param newMulticastPort port of interest */
public AllPduSender(String newMulticastAddress, int newMulticastPort)
{
this.port = DEFAULT_MULTICAST_PORT;
try
{
multicastInetAddress = InetAddress.getByName(newMulticastAddress);
if (!multicastInetAddress.isMulticastAddress())
{
System.out.println("Not a multicast address: " + newMulticastAddress);
}
this.port = newMulticastPort;
}
catch (UnknownHostException e) {
System.out.println("Unable to open socket: " + e);
}
}
/** Begin operations
* @return number of PDUs received, -1 if exception occurs */
@SuppressWarnings("SleepWhileInLoop")
public int run()
{
System.out.println("OpenDis7Examples.AllPduSender started...");
if (SEND_LOOPS_TO_PERFORM != 1)
{
float waitIntervalSeconds = ((float)THREAD_SLEEP_INTERVAL / 1000);
float loopIntervalSeconds = ((float)THREAD_SLEEP_INTERVAL / 1000) * 72; // 72 PDUs
float totalDurationSeconds = loopIntervalSeconds * SEND_LOOPS_TO_PERFORM ;
System.out.println("... THREAD_SLEEP_INTERVAL = " + THREAD_SLEEP_INTERVAL + " milliseconds = " + waitIntervalSeconds + " seconds");
System.out.print ("... running for ");
if (SEND_LOOPS_TO_PERFORM > 1)
System.out.print (SEND_LOOPS_TO_PERFORM + " loops, ");
if (THREAD_SLEEP_INTERVAL > 0)
System.out.println("expected loop interval = " + loopIntervalSeconds + " seconds, total duration = " +
totalDurationSeconds + " seconds = " + (totalDurationSeconds/60.0) + " minutes");
}
System.out.println("Generate list of all PDU types and note issues, if any...");
List<Pdu> generatedPdusList = new ArrayList<>();
for (int i = 0; i < SEND_LOOPS_TO_PERFORM; i++) {
try {
// Loop through all the enumerated PDU types, create a PDU for each type,
// add that PDU to generatedPdusList, then send each one
for (DisPduType pduTypeValue : DisPduType.values())
{
// System.out.println("PDU " + pdu.getValue() + " " + pdu.name() + " " + pdu.getDescription()); // diagnostic
Pdu aPdu = null; // edu.nps.moves7.dis.PDU superclass for all PDUs, in preparation for custom assignment
try {
switch (pduTypeValue) // using enumeration values from edu.nps.moves.dis7.enumerations.DisPduType
{
// each case value is DisPduType
case OTHER: // 0
System.out.println ("*** Note: DisPduType." + pduTypeValue.name() + "=" + pduTypeValue.getValue() + " not supported"); // TODO why was this received?
break; // nothing to send
case ENTITY_STATE: // 1
aPdu = new EntityStatePdu();
EntityStatePdu espdu = (EntityStatePdu) aPdu;
EntityMarking entityMarking = new EntityMarking ();
entityMarking.setCharacters("AllPduSender".getBytes()); //entityMarking.setCharacters(Byte.valueOf("0")); // 11 characters max?
espdu.setMarking(entityMarking);
Vector3Double espduLocation = new Vector3Double();
espduLocation.setX(1.0);
espduLocation.setY(2.0);
espduLocation.setZ(3.0);
espdu.setEntityLocation(espduLocation);
// it is important to identify questions as you think of them
// TODO how to set azimuth, i.e. course direction over ground?
break;
case FIRE: // 2
aPdu = new FirePdu();
break;
case DETONATION: // 3
aPdu = new DetonationPdu();
break;
case COLLISION: // 4
aPdu = new CollisionPdu();
break;
case SERVICE_REQUEST: // 5
aPdu = new ServiceRequestPdu();
break;
case RESUPPLY_OFFER: // 6
aPdu = new ResupplyOfferPdu();
break;
case RESUPPLY_RECEIVED: // 7
aPdu = new ResupplyReceivedPdu();
break;
case RESUPPLY_CANCEL: //8
aPdu = new ResupplyCancelPdu();
break;
case REPAIR_COMPLETE: // 9
aPdu = new RepairCompletePdu();
break;
case REPAIR_RESPONSE: // 10
aPdu = new RepairResponsePdu();
break;
case CREATE_ENTITY: // 11
aPdu = new CreateEntityPdu();
break;
case REMOVE_ENTITY: // 12
aPdu = new RemoveEntityPdu();
break;
case START_RESUME: // 13
aPdu = new StartResumePdu();
break;
case STOP_FREEZE: // 14
aPdu = new StopFreezePdu();
break;
case ACKNOWLEDGE: // 15
aPdu = new AcknowledgePdu();
break;
case ACTION_REQUEST: // 16
aPdu = new ActionRequestPdu();
break;
case ACTION_RESPONSE: // 17
aPdu = new ActionResponsePdu();
break;
case DATA_QUERY: // 18
aPdu = new DataQueryPdu();
break;
case SET_DATA: // 19
aPdu = new SetDataPdu();
break;
case DATA: // 20
aPdu = new DataPdu();
break;
case EVENT_REPORT: // 21
aPdu = new EventReportPdu();
break;
case ELECTROMAGNETIC_EMISSION: // 23
aPdu = new ElectromagneticEmissionPdu();
break;
case DESIGNATOR: // 24
aPdu = new DesignatorPdu();
break;
case TRANSMITTER: // 25
aPdu = new TransmitterPdu();
break;
case SIGNAL: // 26
aPdu = new SignalPdu();
break;
case RECEIVER: // 27
aPdu = new ReceiverPdu();
break;
case IDENTIFICATION_FRIEND_OR_FOE: // 28
aPdu = new IdentificationFriendOrFoePdu();
break;
case UNDERWATER_ACOUSTIC: // 29
aPdu = new UnderwaterAcousticPdu();
break;
case SUPPLEMENTAL_EMISSION_ENTITY_STATE: // 30
aPdu = new SupplementalEmissionEntityStatePdu();
break;
case INTERCOM_SIGNAL: // 31
aPdu = new IntercomSignalPdu();
break;
case INTERCOM_CONTROL: // 32
aPdu = new IntercomControlPdu();
break;
case AGGREGATE_STATE: // 33
aPdu = new AggregateStatePdu();
break;
case ISGROUPOF: // 34
aPdu = new IsGroupOfPdu();
break;
case TRANSFER_OWNERSHIP: // 35
aPdu = new TransferOwnershipPdu();
break;
case ISPARTOF: // 36
aPdu = new IsPartOfPdu();
break;
case MINEFIELD_STATE: // 37
aPdu = new MinefieldStatePdu();
break;
case MINEFIELD_QUERY: // 38
aPdu = new MinefieldQueryPdu();
break;
case MINEFIELD_DATA: // 39
aPdu = new MinefieldDataPdu();
break;
case MINEFIELD_RESPONSE_NACK: // 40
aPdu = new MinefieldResponseNACKPdu();
break;
case ENVIRONMENTAL_PROCESS: // 41
aPdu = new EnvironmentalProcessPdu();
break;
case GRIDDED_DATA: // 42
aPdu = new GriddedDataPdu();
break;
case POINT_OBJECT_STATE: // 43
aPdu = new PointObjectStatePdu();
break;
case LINEAR_OBJECT_STATE: // 44
aPdu = new LinearObjectStatePdu();
break;
case AREAL_OBJECT_STATE: // 45
aPdu = new ArealObjectStatePdu();
break;
case TIME_SPACE_POSITION_INFORMATION: // 46
aPdu = new TimeSpacePositionInformationPdu();
break;
case APPEARANCE: // 47
aPdu = new AppearancePdu();
break;
case ARTICULATED_PARTS: // 48
aPdu = new ArticulatedPartsPdu();
break;
case LIVE_ENTITY_FIRE: // 49
aPdu = new LiveEntityFirePdu();
break;
case LIVE_ENTITY_DETONATION: // 50
aPdu = new LiveEntityDetonationPdu();
break;
case CREATE_ENTITY_RELIABLE: // 51
aPdu = new CreateEntityReliablePdu();
break;
case REMOVE_ENTITY_RELIABLE: // 52
aPdu = new RemoveEntityReliablePdu();
break;
case START_RESUME_RELIABLE: // 53
aPdu = new StartResumeReliablePdu();
break;
case STOP_FREEZE_RELIABLE: // 54
aPdu = new StopFreezeReliablePdu();
break;
case ACKNOWLEDGE_RELIABLE: // 55
aPdu = new AcknowledgeReliablePdu();
break;
case ACTION_REQUEST_RELIABLE: // 56
aPdu = new ActionRequestReliablePdu();
break;
case ACTION_RESPONSE_RELIABLE: // 57
aPdu = new ActionResponseReliablePdu();
break;
case DATA_QUERY_RELIABLE: // 58
aPdu = new DataQueryReliablePdu();
break;
case SET_DATA_RELIABLE: // 59
aPdu = new SetDataReliablePdu();
break;
case DATA_RELIABLE: // 60
aPdu = new DataReliablePdu();
break;
case EVENT_REPORT_RELIABLE: // 61
aPdu = new EventReportReliablePdu();
break;
case COMMENT_RELIABLE: // 62
aPdu = new CommentReliablePdu();
break;
case RECORD_RELIABLE: // 63
aPdu = new RecordReliablePdu();
break;
case SET_RECORD_RELIABLE: // 64
aPdu = new SetRecordReliablePdu();
break;
case RECORD_QUERY_RELIABLE: // 65
aPdu = new RecordQueryReliablePdu();
break;
case COLLISION_ELASTIC: // 66
aPdu = new CollisionElasticPdu();
break;
case ENTITY_STATE_UPDATE: // 67
aPdu = new EntityStateUpdatePdu();
break;
case DIRECTED_ENERGY_FIRE: // 68
aPdu = new DirectedEnergyFirePdu();
break;
case ENTITY_DAMAGE_STATUS: // 69
aPdu = new EntityDamageStatusPdu();
break;
case INFORMATION_OPERATIONS_ACTION: // 70
aPdu = new InformationOperationsActionPdu();
break;
case INFORMATION_OPERATIONS_REPORT: // 71
aPdu = new InformationOperationsReportPdu();
break;
case ATTRIBUTE: // 72
aPdu = new AttributePdu();
break;
case COMMENT:
// aPdu = new CommentPdu(); // default for this switch logic
// see Garrett Loffelman and Pete Severson's code for OpenDis version 4 example
// https://gitlab.nps.edu/Savage/NetworkedGraphicsMV3500/tree/master/assignments/src/MV3500Cohort2018JulySeptember/projects/LoeffelmanSeverson
CommentPdu newCommentPdu = new CommentPdu();
ArrayList<VariableDatum> payloadList = new ArrayList<>();
ArrayList<String> commentsList = new ArrayList<>();
commentsList.add("Hello CommentPDU");
commentsList.add("Here is a second line of text in this comment.");
if (!commentsList.isEmpty())
System.out.println("Preparing CommentPDU:");
for (String comment : commentsList)
{
VariableDatum newVariableDatum = new VariableDatum();
newVariableDatum.setVariableDatumValue (comment.getBytes()); // conversion
// TODO confirm whether method overloading is appropriate
// newVariableDatum.setVariableDatumLength(comment.getBytes().length);
newVariableDatum.setVariableDatumLengthInBytes(comment.getBytes().length); // also available in bits, see spec and javadoc
// alternatively, you do not need to set this and the marshaller will figure it out from the byte array
// (see javadoc for VariableDatum.setVariableDatumLength())
payloadList.add(newVariableDatum);
System.out.println(" \"" + comment + "\"");
}
newCommentPdu.setVariableDatums(payloadList);
aPdu = newCommentPdu; // hand off for sending
break;
default:
System.out.println("*** Warning: PDU " + pduTypeValue.getValue() + " " + pduTypeValue + " not supported, created or sent ");
// code generation block for this class follows:
// System.out.println(" case " + pdu + ": // " + pdu.getValue());
// System.out.println(" aPdu = new " + pdu.getDescription().replace(" ","").replace("-","").replace("/","") +
// "Pdu();");
// System.out.println(" break;");
// System.out.println();
}
if (aPdu != null)
{
// leave aPdu timestamp at default value for consistency of output unit tests
generatedPdusList.add(aPdu);
}
}
catch (Exception e)
{
System.out.print("Exception thrown for PDU " + pduTypeValue.getValue() + " " + pduTypeValue);
System.out.print(Arrays.toString(e.getStackTrace()));
// continue looping
}
}
if (generatedPdusList.size() != 72) // TODO create an enumeration DISType.TOTAL_PDU_TYPES
System.out.println("Error: " + generatedPdusList.size() + " PDUs generated, but 72 PDUs expected.");
// Send the PDUs we created
System.out.println("Send the " + generatedPdusList.size() + " PDUs we created...");
// =======================================================================
// prior appproach
// InetAddress localMulticastAddress = InetAddress.getByName(DEFAULT_MULTICAST_ADDRESS);
// MulticastSocket multicastSocket = new MulticastSocket(DEFAULT_MULTICAST_PORT);
// if (!localMulticastAddress.isMulticastAddress())
// {
// throw new RuntimeException("*** Error: sending to multicast address, but destination address " + localMulticastAddress.toString() + "is not multicast");
// }
// multicastSocket.joinGroup(localMulticastAddress); // deprecated
// =======================================================================
// updated approach using NetworkInterface
NetworkInterface networkInterface = NetworkInterface.getByInetAddress(multicastInetAddress);
if (networkInterface != null)
System.out.println("networkInterface=" + networkInterface.getDisplayName()); // typically null if loopback
SocketAddress localMulticastSocketAddress = new InetSocketAddress(multicastInetAddress, DEFAULT_MULTICAST_PORT);
MulticastSocket multicastSocket = new MulticastSocket(DEFAULT_MULTICAST_PORT);
multicastSocket.joinGroup(localMulticastSocketAddress, networkInterface);
// =======================================================================
byte[] buffer;
Pdu aPdu;
DatagramPacket packet;
for (int idx = 0; idx < generatedPdusList.size(); idx++)
{
// careful here! keep object instantiations inside of loop to avoid endless array and packet growth
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
aPdu = generatedPdusList.get(idx);
try
{
aPdu.marshal(dos); // dos is DataOutputStream connected to ByteArrayOutputStrea
buffer = baos.toByteArray();
packet = new DatagramPacket(buffer, buffer.length, multicastInetAddress, DEFAULT_MULTICAST_PORT);
multicastSocket.send(packet);
DisPduType disPduType= aPdu.getPduType();
// disPduType.setTRACE(true);
String currentIndexPadded = String.format("%2s", (idx + 1));
String currentPduTypeValuePadded = String.format("%2s", disPduType.getValue());
String currentPduTypePadded = String.format("%-49s", aPdu.getPduType().toString()); // - indicates right padding of whitespace
String packetLengthPadded = String.format("%3s", packet.getLength());
System.out.println ("Sent packet #" + currentIndexPadded + ", " +
// currentPduTypeValuePadded + " " +
currentPduTypePadded +
"(packet.getLength()=" + packetLengthPadded + ")" + // diagnostic, beware of ever-growing packet size!
" of type " + aPdu.getClass().getSimpleName());
Thread.sleep(THREAD_SLEEP_INTERVAL); // pause for debugging, if zero this process still yields
}
catch (Exception ex) {
System.out.println("Marshaling error" + ex);
}
}
}
catch (IOException e)
{
System.out.println(e);
return -1; // error condition
}
} // end repetion loop
// TODO write the PDUs out to an XML file.
//PduContainer container = new PduContainer();
//container.setPdus(generatedPdus);
//container.marshallToXml("examplePdus.xml");
return generatedPdusList.size();
}
/**
* Program invocation, execution starts here
* @param args command-line arguments
*/
public static void main(String args[])
{
AllPduSender allPduSender;
int totalSentPdus;
if (args.length == 2)
{
System.out.println("Usage: AllPduSender <multicast group> <port>");
System.out.println("Actual: AllPduSender " + multicastInetAddress.getHostAddress() + " " + port);
allPduSender = new AllPduSender(args[0], Integer.parseInt(args[1]));
}
else
{
System.out.println("Usage: AllPduSender <multicast group> <port>");
System.out.println("Default: AllPduSender " + DEFAULT_MULTICAST_ADDRESS + " " + DEFAULT_MULTICAST_PORT);
allPduSender = new AllPduSender(DEFAULT_MULTICAST_ADDRESS, DEFAULT_MULTICAST_PORT);
}
totalSentPdus = allPduSender.run(); // do it to it
System.out.println("OpenDis7Examples.AllPduSender complete, sent " + totalSentPdus + " PDUs total.");
}
}