@ShortName("UDPSocket")
@Permissions(values = {"android.permission.INTERNET"})
@Events(values={"PacketArrived (Packet As UDPPacket)"})
public static class UDPSocket {
private UDPReader reader;
private DatagramSocket ds;
/**
* Initializes the socket and starts listening for packets.
*EventName - The name of the Sub that will handle the events.
*Port - Local port to listen on. Passing 0 will cause the OS to choose an available port automatically.
*ReceiveBufferSize - The size of the receiving packet. Packets larger than this value will be truncated.
*Pass 0 if you do not want to receive any packets.
*/
public void Initialize(BA ba, String EventName, int Port, int ReceiveBufferSize) throws SocketException {
Close();
if (Port == 0)
ds = new DatagramSocket();
else
ds = new DatagramSocket(Port);
if (ReceiveBufferSize > 0) {
reader = new UDPReader();
reader.working = true;
reader.socket = ds;
reader.receiveLength = ReceiveBufferSize;
reader.ba = ba;
reader.eventName = EventName.toLowerCase(BA.cul);
Thread t = new Thread(reader);
t.setDaemon(true);
t.start();
}
}
/**
* Tests whether this object is initialized.
*/
public boolean IsInitialized() {
return ds != null && !ds.isClosed();
}
/**
* Gets the local port that this socket listens to.
*/
public int getPort() {
return ds.getLocalPort();
}
/**
* Sends a Packet.
*/
public void Send(DatagramPacket Packet) throws IOException {
ds.send(Packet);
}
/**
* Closes the socket.
*/
public void Close() {
if (ds != null)
ds.close();
if (reader != null)
reader.working = false;
reader = null;
ds = null;
}
@Override
public String toString() {
if (ds == null)
return "Not initialized";
return "Port=" + getPort();
}
private static class UDPReader implements Runnable {
volatile boolean working;
DatagramSocket socket;
int receiveLength;
BA ba;
String eventName;
@Override
public void run() {
while (working) {
try {
DatagramPacket p = new DatagramPacket(new byte[receiveLength], receiveLength);
socket.receive(p);
UDPPacket u = new UDPPacket();
u.setObject(p);
ba.raiseEventFromDifferentThread(null, null, 0, eventName + "_packetarrived", false, new Object[] {u});
} catch (IOException e) {
e.printStackTrace();
if (working) {
try {
Thread.sleep(100);
} catch (InterruptedException e1) {
}
}
}
}
}
}
/**
* A packet of data that is being sent or received.
*To send a packet call one of the Initialize methods and then send the packet by passing it to UDPSocket.Send.
*When a packet arrives you can get the data in the packet from the available properties.
*/
@ShortName("UDPPacket")
public static class UDPPacket extends AbsObjectWrapper<DatagramPacket> {
/**
* Initializes the packet and makes it ready for sending.
*Data - The data that will be send.
*Host - The target host name or IP address.
*Port - The target port.
*/
public void Initialize(byte[] Data, String Host, int Port) throws SocketException {
Initialize2(Data, 0, Data.length, Host, Port);
}
/**
* Similar to Initialize. The data sent is based on the Offset and Length values.
*/
public void Initialize2(byte[] Data, int Offset, int Length, String Host, int Port) throws SocketException {
DatagramPacket d = new DatagramPacket(Data, Offset, Length, new InetSocketAddress(Host, Port));
setObject(d);
}
/**
* Gets the length of available bytes in the data. This can be shorter than the array length.
*/
public int getLength() {
return getObject().getLength();
}
/**
* Gets the data array received.
*/
public byte[] getData() {
return getObject().getData();
}
/**
* Gets the offset in the data array where the available data starts.
*/
public int getOffset() {
return getObject().getOffset();
}
/**
* Gets the port of the sending machine.
*/
public int getPort() {
return getObject().getPort();
}
/**
* Gets the host name or IP address of the sending machine.
*/
public String getHost() {
return getObject().getAddress().getHostName();
}
@Override
public String toString() {
if (getObjectOrNull() == null)
return super.toString();
return "Length=" + getLength() + ", Offset=" + getOffset() + ", Host=" + getHost() + ", Port=" + getPort();
}
}
}