package com.safemobile.services; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.wifi.WifiManager; import android.util.Log; import com.safemobile.lib.AppParams; import com.safemobile.lib.SM; import com.safemobile.lib.TCPmsg; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; import java.net.UnknownHostException; import java.util.LinkedList; import java.util.NoSuchElementException; import java.util.Timer; import java.util.TimerTask; public class TCPhandler implements Runnable { private final String TAG = "TCPhandler"; private boolean alive = true; public String serverHostname; private int port; private Thread listenThread; private Socket soc = null; private DataInputStream input; private DataOutputStream output; private String leftOver = ""; public static LinkedList msgList; public Boolean isConnectionUP = false; public Boolean previousConnectionWasUP = false; private final Context context; private boolean isWiFiOn; public TCPhandler(Context context, String hostName, int p) { this.context = context; serverHostname = hostName; port = p; msgList = new LinkedList<>(); SM.Debug("---TCPhandler constructor [" + hostName + "," + p + "] ---"); listenThread = new Thread(this, "TCPlisten"); listenThread.start(); // (2) Start the thread. // create timer to check socket status Timer timer = new Timer(); try { timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { try { previousConnectionWasUP = isConnectionUP; // try to send something TCPmsgParser._fireonTCPConnectionStatusEvent(isConnectionUP, previousConnectionWasUP); } catch (Exception e) { SM.Exception("TIMERException", e.toString()); } } }, 0, 3000); } catch(Exception e) { Log.v("Exception", e.getMessage()); } // get WiFi state isWiFiOn = isNetworkConnected(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); context.registerReceiver(mReceived, intentFilter); } private boolean isNetworkConnected() { ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected(); } @Override public void run() { try { if (soc != null) soc.close(); soc = new Socket(); soc.connect(new InetSocketAddress(serverHostname, port), 5000); input = new DataInputStream(soc.getInputStream()); output = new DataOutputStream(soc.getOutputStream()); if (soc != null) { isConnectionUP = true; triggerTCPConnectionStateEvent(); } } catch (UnknownHostException e) { SM.Debug("UnknownHostException", "TCPhandler break:"+ e); } catch (IllegalArgumentException e) { SM.Debug("IllegalArgumentException", "TCPhandler break:"+ e); } catch (IOException e) { SM.Debug("IOException", "TCPhandler break:"+ e); } catch (Exception e) { Log.v("Exception", e.getMessage()); } while (alive) { try { Thread.sleep(3000); } catch (InterruptedException e) { SM.Debug("TCPhandler Crash1 on sleep:"+ e); } catch (Exception e) { Log.v("Exception", e.getMessage()); } while (Boolean.TRUE.equals(isConnectionUP)) { try { Thread.sleep(100); //process leftover try { boolean FinishLeftOver = true; while (FinishLeftOver) { String[] tempArr2 = leftOver.split("#"); if (tempArr2.length > 1) { int messLen; try { messLen = Integer.parseInt(tempArr2[1]); } catch (Exception e) { SM.Debug("leftovers", "incorect msg len leftOver =" + tempArr2[1]); messLen = -1; } if (messLen > leftOver.length()) { FinishLeftOver = false; break; } else if (messLen == leftOver.length()) { TCPmsg msg = new TCPmsg(leftOver.toCharArray()); SM.Debug("leftovers", "RX from leftOver:" + msg.allData); if (msg.allData.contains("#92#")) prioritizePongReceived(); msgList.add(msg); leftOver = ""; FinishLeftOver = false; break; } else // we have more message in leftover { TCPmsg msg = new TCPmsg(leftOver.substring(0, messLen).toCharArray()); SM.Debug("leftovers", "RX from leftOver:" + msg.allData); if (msg.allData.contains("#92#")) prioritizePongReceived(); msgList.add(msg); leftOver = leftOver.substring(messLen, leftOver.length()); } } else FinishLeftOver = false; } } catch (Exception e) { SM.Debug("leftovers", "Error on process leftover" + e.toString()); } //end process leftover String data = ""; int n = 0; byte[] buf = new byte[1024]; // read data into buffer n = input.read(buf); //connection closed by server if (n == -1) { SM.Debug("TCP Client", "Connection closed by server!"); soc.close(); isConnectionUP = false; triggerTCPConnectionStateEvent(); soc = null; break; } byte[] temp = new byte[n]; if (n >= 0) System.arraycopy(buf, 0, temp, 0, n); // decryptData temp = decryptTEA(temp); data = new String(temp); //if we have any leftovers from previous message add them if(leftOver.length() > 1) { // avoid case with only one # data = leftOver+data; leftOver = ""; } //search for overflow message String[] tempArr = data.split("#"); if ((tempArr.length == 0) || (tempArr.length == 1)) { SM.Debug("TCP Client", "incorect messagebuss message=" + data); continue; } //get msg len int messLen; try { messLen = Integer.parseInt(tempArr[1]); } catch (Exception e) { SM.Debug("TCP Client", "incorect msg len =" + tempArr[1]); continue; } //messLen not int if (messLen == -1) { continue; } char[] temMSG = data.toCharArray(); if (data.length() != messLen) { //if expected string message is smaller then actual string then exit processing; if (messLen > data.length()) { leftOver = data; // Add by bigu continue; } //perform cut temMSG = data.substring(0,messLen).toCharArray(); leftOver = data.substring(messLen); } //decode TCP msg TCPmsg msg = new TCPmsg(temMSG); SM.Debug("������� RX �������", msg.allData); if (msg.allData.contains("#92#")) prioritizePongReceived(); msgList.add(msg); } catch(Exception ex) { SM.Debug("TCPHandler", "TCPhandler/run/break:"+ ex); isConnectionUP = false; triggerTCPConnectionStateEvent(); } } // try { Thread.sleep(1000); } catch (InterruptedException e) { SM.Debug("TCPhandler Crash2 on sleep:"+ e); } catch (Exception e) { Log.v("Exception", e.getMessage()); } //try to restart connection if (alive && isWiFiOn) restartTCP(); } SM.Debug("=================================="); SM.Debug("TCP listenThread stoped!! alive = false"); SM.Debug("=================================="); } /** * Create a bypass in order to trigger the ping received event */ private void prioritizePongReceived() { TCPmsgParser._firePONGReceivedEvent(); } /* Broadcast Received for WiFi Connect/Disconnect */ public BroadcastReceiver mReceived = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); SM.Debug("WIFI STATE", action); if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)){ // close socket if the wifi is disconnecting or disconnected isWiFiOn = isNetworkConnected(); if (!isWiFiOn) closeSocket(); } } }; /** Send a message through the TCP Socket * @param seqID The messages's sequence ID (a number of order) * @param msg The messages which will be sent * @return True if the message was sent */ public boolean Write(String seqID, String msg) { try { if (output != null) { try { Thread.sleep(10); String cmdok = "#" + seqID + msg; Integer tmp = cmdok.length() + 1; tmp += Integer.toString(tmp).length(); if ((tmp == 10) || (tmp == 100) || (tmp == 1000)) tmp++; cmdok = "#" + Integer.toString(tmp) + cmdok; byte[] mess = encryptTEA(cmdok); Thread tcpThread = new Thread(() -> { try { output.write(mess); output.flush(); } catch (Exception e) { e.printStackTrace(); } }); tcpThread.start(); SM.Debug(" ", new String(mess)); return true; } catch (InterruptedException e) { SM.Exception("TCPClient[Send]", e.toString()); Thread.currentThread().interrupt(); } catch (NoSuchElementException e) { SM.Exception("TCPClient[Send]", e.toString()); } } else { return false; } } catch (Exception e) { SM.Debug("TCPhandler Write Procedure:" + e); } return false; } /* Encrypt a string using an encryption algorithm, * in this case TEA */ public static byte[] encryptTEA(String toEncryptData) { // no encryption return toEncryptData.getBytes(); } /* Decrypt a string using an encryption algorithm, * in this case TEA */ public static byte[] decryptTEA(byte[] toDecryptData) { byte[] decryptedByteArray; // no decryption decryptedByteArray = toDecryptData; return decryptedByteArray; } public int getPort() { return port; } public void updateTCPparameters(String ip, String _port) { // stop socket try { if (soc != null) soc.close(); } catch (IOException e1) { Log.v("IOException", e1.getMessage()); e1.printStackTrace(); } serverHostname = ip; try { port = Integer.parseInt(_port); } catch (Exception ignored) { } finally { port = 13589; } } public void triggerTCPConnectionStateEvent() { if (!isConnectionUP) TCPmsgParser._fireTCPConnectionDownEvent(previousConnectionWasUP); else TCPmsgParser._fireTCPConnectionUpEvent(previousConnectionWasUP); } private void restartTCP() { try { Log.v(TAG, "restartTCP"); isConnectionUP = false; previousConnectionWasUP = false; SM.Debug("Restarting TCP...ip:" + serverHostname + ":" + port); soc = new Socket(); soc.connect(new InetSocketAddress(serverHostname, port), 50000); input = new DataInputStream(soc.getInputStream()); //output stream output = new DataOutputStream(soc.getOutputStream()); if (soc != null) { isConnectionUP = true; } } catch (NullPointerException | IOException e) { SM.Exception("restartTCP break:" + e); isConnectionUP = false; } catch (IllegalArgumentException e) { SM.Debug("IllegalArgumentException", "restartTCP break:" + e); } triggerTCPConnectionStateEvent(); } /** close Socket when unReachable */ public void closeSocket() { try { input = null; output = null; if (soc != null) soc.close(); soc = null; } catch (IOException e) { Log.v("IOException", e.getMessage()); e.printStackTrace(); } } public void Stop() { SM.Debug("Stopping TCP", "TCP Connection is stopping on " + AppParams.IP + ":" + port); alive = false; if (mReceived!= null) try { context.unregisterReceiver(mReceived); } catch(Exception ex) {/* receiver not registered //*/} // stop thread if (listenThread != null) { Thread moribund = listenThread; listenThread = null; moribund.interrupt(); } if (input != null) { try { input.close(); input = null; } catch (IOException e) { e.printStackTrace(); } } if (output != null) { try { output.close(); output = null; } catch (IOException e) { e.printStackTrace(); } } if (soc !=null) { try { soc.close(); soc = null; } catch (IOException e) { SM.Exception("TCPClient[STOP]", "Stop break:"+ e); } } } }