com.iiitd.networking.UDPMessenger.java Source code

Java tutorial

Introduction

Here is the source code for com.iiitd.networking.UDPMessenger.java

Source

/*
    
UDP Messenger by Giacomo Furlan.
http://giacomofurlan.name
    
This software is being distributed under the Creative Common's Attribution 3.0 Unported licence (CC BY 3.0)
http://creativecommons.org/licenses/by/3.0/
    
You are not allowed to use this source code for pirate purposes.
    
This software is provided "as-is" and it comes with no warranties.
    
*/

package com.iiitd.networking;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.List;

import org.apache.http.conn.util.InetAddressUtils;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.MulticastLock;
import android.os.Handler;
import android.os.Looper;
import android.text.format.Formatter;
import android.util.Log;

public abstract class UDPMessenger {
    protected static String DEBUG_TAG = "UDPMessenger";
    protected static final Integer BUFFER_SIZE = 4096;

    protected String TAG;
    protected int MULTICAST_PORT;

    private boolean receiveMessages = false;

    protected Context context;
    private DatagramSocket socket;

    protected abstract Runnable getIncomingMessageAnalyseRunnable();

    private final Handler incomingMessageHandler;
    protected Message incomingMessage;
    private Thread receiverThread;

    /**
     * Class constructor
     * @param context the application's context
     * @param tag a valid string, used to filter the UDP broadcast messages (in and out). It can't be null or 0-characters long.
     * @param multicastPort the port to multicast to. Must be between 1025 and 49151 (inclusive)
     * @param connectionPort the port to get the connection back. Must be between 1025 and 49151
     */
    public UDPMessenger(Context context, String tag, int multicastPort) throws IllegalArgumentException {
        if (context == null || tag == null || tag.length() == 0 || multicastPort <= 1024 || multicastPort > 49151)
            throw new IllegalArgumentException();

        this.context = context.getApplicationContext();
        TAG = tag;
        MULTICAST_PORT = multicastPort;

        incomingMessageHandler = new Handler(Looper.getMainLooper());
    }

    /**
     * Sends a broadcast message (TAG EPOCH_TIME message). Opens a new socket in case it's closed.
     * @param message the message to send (multicast). It can't be null or 0-characters long.
     * @return
     * @throws IllegalArgumentException
     */
    public boolean sendMessage(String message) throws IllegalArgumentException {
        if (message == null || message.length() == 0)
            throw new IllegalArgumentException();

        // Check for WiFi connectivity
        ConnectivityManager connManager = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo mWifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);

        if (mWifi == null || !mWifi.isConnected()) {
            Log.d(DEBUG_TAG,
                    "Sorry! You need to be in a WiFi network in order to send UDP multicast packets. Aborting.");
            return false;
        }

        // Check for IP address
        WifiManager wim = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        int ip = wim.getConnectionInfo().getIpAddress();

        // Create the send socket
        if (socket == null) {
            try {
                socket = new DatagramSocket();
            } catch (SocketException e) {
                Log.d(DEBUG_TAG, "There was a problem creating the sending socket. Aborting.");
                e.printStackTrace();
                return false;
            }
        }

        // Build the packet
        DatagramPacket packet;
        Message msg = new Message(TAG, message);
        byte data[] = msg.toString().getBytes();

        WifiInfo wifiInfo = wim.getConnectionInfo();
        int ipa = wifiInfo.getIpAddress();
        String ipAddress = Formatter.formatIpAddress(ipa);

        try {
            //         packet = new DatagramPacket(data, data.length, InetAddress.getByName(ipToString(ip, true)), MULTICAST_PORT);
            packet = new DatagramPacket(data, data.length, InetAddress.getByName(ipAddress), MULTICAST_PORT);
        } catch (UnknownHostException e) {
            Log.d(DEBUG_TAG, "It seems that " + ipToString(ip, true) + " is not a valid ip! Aborting.");
            e.printStackTrace();
            return false;
        }

        try {
            socket.send(packet);
        } catch (IOException e) {
            Log.d(DEBUG_TAG, "There was an error sending the UDP packet. Aborted.");
            e.printStackTrace();
            return false;
        }

        return true;
    }

    public void startMessageReceiver() {
        Runnable receiver = new Runnable() {

            @Override
            public void run() {
                WifiManager wim = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
                if (wim != null) {
                    MulticastLock mcLock = wim.createMulticastLock(TAG);
                    mcLock.acquire();
                }

                byte[] buffer = new byte[BUFFER_SIZE];
                DatagramPacket rPacket = new DatagramPacket(buffer, buffer.length);
                MulticastSocket rSocket;

                try {
                    rSocket = new MulticastSocket(MULTICAST_PORT);
                } catch (IOException e) {
                    Log.d(DEBUG_TAG, "Impossible to create a new MulticastSocket on port " + MULTICAST_PORT);
                    e.printStackTrace();
                    return;
                }

                while (receiveMessages) {
                    try {
                        rSocket.receive(rPacket);
                    } catch (IOException e1) {
                        Log.d(DEBUG_TAG, "There was a problem receiving the incoming message.");
                        e1.printStackTrace();
                        continue;
                    }

                    if (!receiveMessages)
                        break;

                    byte data[] = rPacket.getData();
                    int i;
                    for (i = 0; i < data.length; i++) {
                        if (data[i] == '\0')
                            break;
                    }

                    String messageText;

                    try {
                        messageText = new String(data, 0, i, "UTF-8");
                    } catch (UnsupportedEncodingException e) {
                        Log.d(DEBUG_TAG, "UTF-8 encoding is not supported. Can't receive the incoming message.");
                        e.printStackTrace();
                        continue;
                    }

                    try {
                        incomingMessage = new Message(messageText, rPacket.getAddress());
                    } catch (IllegalArgumentException ex) {
                        Log.d(DEBUG_TAG, "There was a problem processing the message: " + messageText);
                        ex.printStackTrace();
                        continue;
                    }

                    incomingMessageHandler.post(getIncomingMessageAnalyseRunnable());
                }
            }

        };

        receiveMessages = true;
        if (receiverThread == null)
            receiverThread = new Thread(receiver);

        if (!receiverThread.isAlive())
            receiverThread.start();
    }

    public void stopMessageReceiver() {
        receiveMessages = false;
    }

    public static String ipToString(int ip, boolean broadcast) {
        String result = new String();

        Integer[] address = new Integer[4];
        for (int i = 0; i < 4; i++)
            address[i] = (ip >> 8 * i) & 0xFF;
        for (int i = 0; i < 4; i++) {
            if (i != 3)
                result = result.concat(address[i] + ".");
            else
                result = result.concat("255.");
        }
        return result.substring(0, result.length() - 2);
    }

    /**
      * Get IP address from first non-localhost interface
      * @param ipv4  true=return ipv4, false=return ipv6
      * @return  address or empty string
      */
    public static String getIPAddress(boolean useIPv4) {
        try {
            List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
            for (NetworkInterface intf : interfaces) {
                List<InetAddress> addrs = Collections.list(intf.getInetAddresses());
                for (InetAddress addr : addrs) {
                    if (!addr.isLoopbackAddress()) {
                        String sAddr = addr.getHostAddress().toUpperCase();
                        boolean isIPv4 = InetAddressUtils.isIPv4Address(sAddr);
                        if (useIPv4) {
                            if (isIPv4)
                                return sAddr;
                        } else {
                            if (!isIPv4) {
                                int delim = sAddr.indexOf('%'); // drop ip6 port suffix
                                return delim < 0 ? sAddr : sAddr.substring(0, delim);
                            }
                        }
                    }
                }
            }
        } catch (Exception ex) {
        } // for now eat exceptions
        return "";
    }

}