summaryrefslogtreecommitdiff
path: root/base/src/main/java/com/smartdevicelink
diff options
context:
space:
mode:
authorBrettyWhite <geekman3454@protonmail.com>2019-03-06 14:16:17 -0500
committerBrettyWhite <geekman3454@protonmail.com>2019-03-06 14:16:17 -0500
commit361f5e0a27cd8fe71fae372eb16467ff9d560d37 (patch)
tree4ac2afd0aa3d99c6d329def66d26d8fbfed41971 /base/src/main/java/com/smartdevicelink
parent87b90592975b56b201a29d6df55b4e0afeb573d4 (diff)
downloadsdl_android-361f5e0a27cd8fe71fae372eb16467ff9d560d37.tar.gz
git mv trace, transport, util
Diffstat (limited to 'base/src/main/java/com/smartdevicelink')
-rw-r--r--base/src/main/java/com/smartdevicelink/trace/DiagLevel.java61
-rw-r--r--base/src/main/java/com/smartdevicelink/trace/ISTListener.java5
-rw-r--r--base/src/main/java/com/smartdevicelink/trace/Mime.java100
-rw-r--r--base/src/main/java/com/smartdevicelink/trace/OpenRPCMessage.java86
-rw-r--r--base/src/main/java/com/smartdevicelink/trace/enums/DetailLevel.java16
-rw-r--r--base/src/main/java/com/smartdevicelink/trace/enums/InterfaceActivityDirection.java15
-rw-r--r--base/src/main/java/com/smartdevicelink/trace/enums/Mod.java18
-rw-r--r--base/src/main/java/com/smartdevicelink/transport/BaseTransportConfig.java35
-rw-r--r--base/src/main/java/com/smartdevicelink/transport/ITransportListener.java17
-rw-r--r--base/src/main/java/com/smartdevicelink/transport/SdlPsm.java261
-rw-r--r--base/src/main/java/com/smartdevicelink/transport/SdlTransport.java122
-rw-r--r--base/src/main/java/com/smartdevicelink/transport/SiphonServer.java384
-rw-r--r--base/src/main/java/com/smartdevicelink/transport/TransportConstants.java263
-rw-r--r--base/src/main/java/com/smartdevicelink/transport/utl/TransportRecord.java126
-rw-r--r--base/src/main/java/com/smartdevicelink/util/BitConverter.java116
-rw-r--r--base/src/main/java/com/smartdevicelink/util/ByteEnumer.java60
-rw-r--r--base/src/main/java/com/smartdevicelink/util/CorrelationIdGenerator.java25
-rw-r--r--base/src/main/java/com/smartdevicelink/util/IConsole.java10
-rw-r--r--base/src/main/java/com/smartdevicelink/util/SdlDataTypeConverter.java63
-rw-r--r--base/src/main/java/com/smartdevicelink/util/Version.java75
20 files changed, 1858 insertions, 0 deletions
diff --git a/base/src/main/java/com/smartdevicelink/trace/DiagLevel.java b/base/src/main/java/com/smartdevicelink/trace/DiagLevel.java
new file mode 100644
index 000000000..26dfdebff
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/trace/DiagLevel.java
@@ -0,0 +1,61 @@
+package com.smartdevicelink.trace;
+
+import com.smartdevicelink.trace.enums.DetailLevel;
+import com.smartdevicelink.trace.enums.Mod;
+
+
+public class DiagLevel {
+
+ static private DetailLevel[] levels;
+
+ static { // this is a static c-tor!!
+ levels = new DetailLevel[Mod.values().length];
+ setAllLevels(DetailLevel.OFF);
+ }
+
+ public static void setAllLevels(DetailLevel thisDetail) {
+ if (thisDetail != null) {
+ for (int i = 0; i < levels.length; i++) {
+ levels[i] = thisDetail; //
+ }
+ }
+ }
+
+ public static void setLevel(Mod thisMod, DetailLevel thisDetail) {
+ if (thisMod != null && thisDetail != null) {
+ levels[thisMod.ordinal()] = thisDetail;
+ }
+ }
+
+ public static DetailLevel getLevel(Mod thisMod) {
+ if (thisMod != null) {
+ return levels[thisMod.ordinal()];
+ }
+ return null;
+ }
+
+ public static boolean isValidDetailLevel(String dtString) {
+ // Assume false
+ Boolean isValid = false;
+
+ if (dtString != null) {
+ if (dtString.equalsIgnoreCase("verbose"))
+ isValid = true;
+ else if (dtString.equalsIgnoreCase("terse"))
+ isValid = true;
+ else if (dtString.equalsIgnoreCase("off"))
+ isValid = true;
+ }
+
+ return isValid;
+ }
+
+ public static DetailLevel toDetailLevel(String dtString) {
+ DetailLevel dt = DetailLevel.OFF;
+ if (dtString.equalsIgnoreCase("verbose"))
+ dt = DetailLevel.VERBOSE;
+ else if (dtString.equalsIgnoreCase("terse"))
+ dt = DetailLevel.TERSE;
+ return dt;
+ }
+}
diff --git a/base/src/main/java/com/smartdevicelink/trace/ISTListener.java b/base/src/main/java/com/smartdevicelink/trace/ISTListener.java
new file mode 100644
index 000000000..3af7d5020
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/trace/ISTListener.java
@@ -0,0 +1,5 @@
+package com.smartdevicelink.trace;
+
+public interface ISTListener {
+ void logXmlMsg(String msg, String token);
+} // end-interface \ No newline at end of file
diff --git a/base/src/main/java/com/smartdevicelink/trace/Mime.java b/base/src/main/java/com/smartdevicelink/trace/Mime.java
new file mode 100644
index 000000000..799ac98f4
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/trace/Mime.java
@@ -0,0 +1,100 @@
+package com.smartdevicelink.trace;
+
+// Borrowed from Dave Boll's infamous SdlLinkRelay.java
+
+public class Mime {
+
+ private static final String BASE_64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ /**
+ * @param str A String to encode into base64 String.
+ * @return Base64 encoded String or a null String if input is null.
+ */
+ public static String base64Encode(String str) {
+ if(str == null){
+ return null;
+ }
+
+ String b64String = "";
+ try {
+ byte[] strBytes = str.getBytes("US-ASCII");
+ b64String = base64Encode(strBytes);
+ } catch (Exception ex) {
+ // Don't care?
+ }
+ return b64String;
+ }
+
+ /**
+ * @param bytesToEncode A byte array to encode into base64 String.
+ * @return Base64 encoded String or a null String if input array is null.
+ */
+ public static String base64Encode(byte bytesToEncode[]) {
+ if(bytesToEncode != null){
+ return base64Encode(bytesToEncode, 0, bytesToEncode.length);
+ }
+ return null;
+ }
+
+ /**
+ * @param bytesToEncode A byte array to encode into base64 String.
+ * @param offset Offset to begin at
+ * @param length Length to read
+ * @return Base64 encoded String or a null String if input array is null or the input range is out of bounds.
+ */
+ public static String base64Encode(byte bytesToEncode[], int offset, int length) {
+ if (bytesToEncode == null || bytesToEncode.length < length || bytesToEncode.length < offset + length) {
+ return null;
+ }
+
+ StringBuilder sb = new StringBuilder();
+
+ int idxin = 0;
+ int b64idx = 0;
+
+ for (idxin = offset; idxin < offset + length; idxin++) {
+ switch ((idxin - offset) % 3) {
+ case 0:
+ b64idx = (bytesToEncode[idxin] >> 2) & 0x3f;
+ break;
+ case 1:
+ b64idx = (bytesToEncode[idxin] >> 4) & 0x0f;
+ b64idx |= ((bytesToEncode[idxin - 1] << 4) & 0x30);
+ break;
+ case 2:
+ b64idx = (bytesToEncode[idxin] >> 6) & 0x03;
+ b64idx |= ((bytesToEncode[idxin - 1] << 2) & 0x3c);
+ sb.append(getBase64Char(b64idx));
+ b64idx = bytesToEncode[idxin] & 0x3f;
+ break;
+ }
+ sb.append(getBase64Char(b64idx));
+ }
+
+ switch ((idxin - offset) % 3) {
+ case 0:
+ break;
+ case 1:
+ b64idx = (bytesToEncode[idxin - 1] << 4) & 0x30;
+ sb.append(getBase64Char(b64idx));
+ sb.append("==");
+ break;
+ case 2:
+ b64idx = ((bytesToEncode[idxin - 1] << 2) & 0x3c);
+ sb.append(getBase64Char(b64idx));
+ sb.append('=');
+ break;
+ }
+
+ return sb.toString();
+
+ }
+
+ private static char getBase64Char(int b64idx){
+ if(b64idx >= 0 && b64idx < BASE_64_CHARS.length()) {
+ return BASE_64_CHARS.charAt(b64idx);
+ }else{
+ return 0x20;
+ }
+ }
+} \ No newline at end of file
diff --git a/base/src/main/java/com/smartdevicelink/trace/OpenRPCMessage.java b/base/src/main/java/com/smartdevicelink/trace/OpenRPCMessage.java
new file mode 100644
index 000000000..35a8de749
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/trace/OpenRPCMessage.java
@@ -0,0 +1,86 @@
+package com.smartdevicelink.trace;
+
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+
+import com.smartdevicelink.proxy.RPCMessage;
+import com.smartdevicelink.proxy.RPCStruct;
+
+class OpenRPCMessage extends RPCMessage {
+ private OpenRPCMessage() {super("");}
+ public OpenRPCMessage(RPCMessage rpcm) {
+ super(rpcm);
+ } // end-method
+
+ public OpenRPCMessage(RPCStruct rpcs) {
+ super(rpcs);
+ } // end-method
+
+ public String msgDump() {
+ StringBuilder pd = new StringBuilder();
+
+ pd.append(this.getFunctionName() + " " + this.getMessageType());
+
+ msgDump(pd);
+
+ return pd.toString();
+ } // end-method
+
+ public void msgDump(StringBuilder pd) {
+ pd.append("[");
+
+ dumpParams(parameters, pd);
+
+ pd.append("]");
+
+ return;
+ } // end-method
+
+ private void dumpParams(Hashtable<String, Object> ht, StringBuilder pd) {
+ Iterator<String> keySet = ht.keySet().iterator();
+ Object obj = null;
+ String key = "";
+ boolean isFirstParam = true;
+
+ while (keySet.hasNext()) {
+ key = (String)keySet.next();
+ obj = ht.get(key);
+ if (isFirstParam) {
+ isFirstParam = false;
+ } else {
+ pd.append(", ");
+ } // end-if
+
+ dumpParamNode(key, obj, pd);
+
+ } // end-while
+ } // end-method
+
+ @SuppressWarnings("unchecked")
+ private void dumpParamNode(String key, Object obj, StringBuilder pd) {
+
+ if (obj instanceof Hashtable) {
+ pd.append("[");
+ dumpParams((Hashtable<String, Object>)obj, pd);
+ pd.append("]");
+ } else if (obj instanceof RPCStruct) {
+ pd.append("[");
+ OpenRPCMessage orpcm = new OpenRPCMessage((RPCStruct)obj);
+ orpcm.msgDump(pd);
+ pd.append("]");
+ } else if (obj instanceof List) {
+ pd.append("[");
+ List<?> list = (List<?>)obj;
+ for (int idx=0;idx < list.size();idx++) {
+ if (idx > 0) {
+ pd.append(", ");
+ }
+ dumpParamNode(key, list.get(idx), pd);
+ } // end-for
+ pd.append("]");
+ } else {
+ pd.append("\"" + key + "\" = \"" + obj.toString() + "\"");
+ }
+ } // end-method
+} // end-class OpenRPCMessage
diff --git a/base/src/main/java/com/smartdevicelink/trace/enums/DetailLevel.java b/base/src/main/java/com/smartdevicelink/trace/enums/DetailLevel.java
new file mode 100644
index 000000000..bd213679d
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/trace/enums/DetailLevel.java
@@ -0,0 +1,16 @@
+package com.smartdevicelink.trace.enums;
+
+
+public enum DetailLevel {
+ OFF,
+ TERSE,
+ VERBOSE;
+
+ public static DetailLevel valueForString(String value) {
+ try{
+ return valueOf(value);
+ }catch(Exception e){
+ return null;
+ }
+ }
+}
diff --git a/base/src/main/java/com/smartdevicelink/trace/enums/InterfaceActivityDirection.java b/base/src/main/java/com/smartdevicelink/trace/enums/InterfaceActivityDirection.java
new file mode 100644
index 000000000..0865d2e32
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/trace/enums/InterfaceActivityDirection.java
@@ -0,0 +1,15 @@
+package com.smartdevicelink.trace.enums;
+
+public enum InterfaceActivityDirection {
+ Transmit,
+ Receive,
+ None;
+
+ public static InterfaceActivityDirection valueForString(String value) {
+ try{
+ return valueOf(value);
+ }catch(Exception e){
+ return null;
+ }
+ }
+} \ No newline at end of file
diff --git a/base/src/main/java/com/smartdevicelink/trace/enums/Mod.java b/base/src/main/java/com/smartdevicelink/trace/enums/Mod.java
new file mode 100644
index 000000000..b363473b2
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/trace/enums/Mod.java
@@ -0,0 +1,18 @@
+package com.smartdevicelink.trace.enums;
+
+public enum Mod {
+ tran,
+ proto,
+ mar,
+ rpc,
+ app,
+ proxy;
+
+ public static Mod valueForString(String value) {
+ try{
+ return valueOf(value);
+ }catch(Exception e){
+ return null;
+ }
+ }
+}; \ No newline at end of file
diff --git a/base/src/main/java/com/smartdevicelink/transport/BaseTransportConfig.java b/base/src/main/java/com/smartdevicelink/transport/BaseTransportConfig.java
new file mode 100644
index 000000000..4b7fe79be
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/transport/BaseTransportConfig.java
@@ -0,0 +1,35 @@
+package com.smartdevicelink.transport;
+
+import com.smartdevicelink.transport.enums.TransportType;
+
+/**
+ * Defines base abstract class for transport configurations.
+ */
+public abstract class BaseTransportConfig {
+
+ protected boolean shareConnection = true;
+ protected int iHeartBeatTimeout = Integer.MAX_VALUE;
+ /**
+ * Gets transport type for this transport configuration.
+ *
+ * @return One of {@link TransportType} enumeration values that represents type of this transport configuration.
+ */
+ public abstract TransportType getTransportType();
+
+ /**
+ * Indicate whether the application want to share connection with others.
+ *
+ * @return
+ */
+ public boolean shareConnection() {
+ return shareConnection;
+ }
+
+ public int getHeartBeatTimeout() {
+ return iHeartBeatTimeout;
+ }
+
+ public void setHeartBeatTimeout(int iTimeout) {
+ iHeartBeatTimeout = iTimeout;
+ }
+}
diff --git a/base/src/main/java/com/smartdevicelink/transport/ITransportListener.java b/base/src/main/java/com/smartdevicelink/transport/ITransportListener.java
new file mode 100644
index 000000000..b4c4a9b33
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/transport/ITransportListener.java
@@ -0,0 +1,17 @@
+package com.smartdevicelink.transport;
+
+import com.smartdevicelink.protocol.SdlPacket;
+
+public interface ITransportListener {
+ // Called to indicate and deliver a packet received from transport
+ void onTransportPacketReceived(SdlPacket packet);
+
+ // Called to indicate that transport connection was established
+ void onTransportConnected();
+
+ // Called to indicate that transport was disconnected (by either side)
+ void onTransportDisconnected(String info);
+
+ // Called to indicate that some error occurred on the transport
+ void onTransportError(String info, Exception e);
+} // end-interface \ No newline at end of file
diff --git a/base/src/main/java/com/smartdevicelink/transport/SdlPsm.java b/base/src/main/java/com/smartdevicelink/transport/SdlPsm.java
new file mode 100644
index 000000000..f5b650722
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/transport/SdlPsm.java
@@ -0,0 +1,261 @@
+package com.smartdevicelink.transport;
+
+import com.smartdevicelink.protocol.SdlPacket;
+
+import static com.smartdevicelink.protocol.SdlProtocol.V1_HEADER_SIZE;
+import static com.smartdevicelink.protocol.SdlProtocol.V1_V2_MTU_SIZE;
+
+
+public class SdlPsm{
+ //private static final String TAG = "Sdl PSM";
+ //Each state represents the byte that should be incomming
+
+ public static final int START_STATE = 0x0;
+ public static final int SERVICE_TYPE_STATE = 0x02;
+ public static final int CONTROL_FRAME_INFO_STATE = 0x03;
+ public static final int SESSION_ID_STATE = 0x04;
+ public static final int DATA_SIZE_1_STATE = 0x05;
+ public static final int DATA_SIZE_2_STATE = 0x06;
+ public static final int DATA_SIZE_3_STATE = 0x07;
+ public static final int DATA_SIZE_4_STATE = 0x08;
+ public static final int MESSAGE_1_STATE = 0x09;
+ public static final int MESSAGE_2_STATE = 0x0A;
+ public static final int MESSAGE_3_STATE = 0x0B;
+ public static final int MESSAGE_4_STATE = 0x0C;
+ public static final int DATA_PUMP_STATE = 0x0D;
+ public static final int FINISHED_STATE = 0xFF;
+ public static final int ERROR_STATE = -1;
+
+
+ private static final byte FIRST_FRAME_DATA_SIZE = 0x08;
+
+ private static final int VERSION_MASK = 0xF0; //4 highest bits
+ private static final int COMPRESSION_MASK = 0x08; //4th lowest bit
+ private static final int FRAME_TYPE_MASK = 0x07; //3 lowest bits
+
+
+
+ int state ;
+
+ int version;
+ boolean compression;
+ int frameType;
+ int serviceType;
+ int controlFrameInfo;
+ int sessionId;
+ int dumpSize, dataLength;
+ int messageId = 0;
+
+ byte[] payload;
+
+ public SdlPsm(){
+ reset();
+ }
+
+ public boolean handleByte(byte data) {
+ //Log.trace(TAG, data + " = incomming");
+ state = transitionOnInput(data,state);
+
+ if(state==ERROR_STATE){
+ return false;
+ }
+ return true;
+ }
+
+ private int transitionOnInput(byte rawByte, int state){
+ switch(state){
+ case START_STATE:
+ version = (rawByte&(byte)VERSION_MASK)>>4;
+ //Log.trace(TAG, "Version: " + version);
+ if(version==0){ //It should never be 0
+ return ERROR_STATE;
+ }
+ compression = (1 == ((rawByte&(byte)COMPRESSION_MASK)>>3));
+
+
+ frameType = rawByte&(byte)FRAME_TYPE_MASK;
+ //Log.trace(TAG, rawByte + " = Frame Type: " + frameType);
+
+ if((version < 1 || version > 5) //These are known versions supported by this library.
+ && frameType!=SdlPacket.FRAME_TYPE_CONTROL){
+ return ERROR_STATE;
+ }
+
+ if(frameType<SdlPacket.FRAME_TYPE_CONTROL || frameType > SdlPacket.FRAME_TYPE_CONSECUTIVE){
+ return ERROR_STATE;
+ }
+
+ return SERVICE_TYPE_STATE;
+
+ case SERVICE_TYPE_STATE:
+ serviceType = (int)(rawByte&0xFF);
+ return CONTROL_FRAME_INFO_STATE;
+
+ case CONTROL_FRAME_INFO_STATE:
+ controlFrameInfo = (int)(rawByte&0xFF);
+ //Log.trace(TAG,"Frame Info: " + controlFrameInfo);
+ switch(frameType){
+ case SdlPacket.FRAME_TYPE_CONTROL:
+ /*if(frameInfo<FRAME_INFO_HEART_BEAT
+ || (frameInfo>FRAME_INFO_END_SERVICE_ACK
+ && (frameInfo!=FRAME_INFO_SERVICE_DATA_ACK || frameInfo!=FRAME_INFO_HEART_BEAT_ACK))){
+ return ERROR_STATE;
+ }*/ //Although some bits are reserved...whatever
+ break;
+ case SdlPacket.FRAME_TYPE_SINGLE: //Fall through since they are both the same
+ case SdlPacket.FRAME_TYPE_FIRST:
+ if(controlFrameInfo!=0x00){
+ return ERROR_STATE;
+ }
+ break;
+ case SdlPacket.FRAME_TYPE_CONSECUTIVE:
+ //It might be a good idea to check packet sequence numbers here
+ break;
+
+ default:
+ return ERROR_STATE;
+ }
+ return SESSION_ID_STATE;
+
+ case SESSION_ID_STATE:
+ sessionId = (int)(rawByte&0xFF);
+ return DATA_SIZE_1_STATE;
+
+ case DATA_SIZE_1_STATE:
+ //First data size byte
+ //Log.d(TAG, "Data byte 1: " + rawByte);
+ dataLength += ((int)(rawByte& 0xFF))<<24; //3 bytes x 8 bits
+ //Log.d(TAG, "Data Size 1 : " + dataLength);
+ return DATA_SIZE_2_STATE;
+
+ case DATA_SIZE_2_STATE:
+ //Log.d(TAG, "Data byte 2: " + rawByte);
+ dataLength += ((int)(rawByte& 0xFF))<<16; //2 bytes x 8 bits
+ //Log.d(TAG, "Data Size 2 : " + dataLength);
+ return DATA_SIZE_3_STATE;
+
+ case DATA_SIZE_3_STATE:
+ //Log.d(TAG, "Data byte 3: " + rawByte);
+ dataLength += ((int)(rawByte& 0xFF))<<8; //1 byte x 8 bits
+ //Log.d(TAG, "Data Size 3 : " + dataLength);
+ return DATA_SIZE_4_STATE;
+
+ case DATA_SIZE_4_STATE:
+ //Log.d(TAG, "Data byte 4: " + rawByte);
+ dataLength+=((int)rawByte) & 0xFF;
+ //Log.trace(TAG, "Data Size: " + dataLength);
+ //We should have data length now for the pump state
+ switch(frameType){ //If all is correct we should break out of this switch statement
+ case SdlPacket.FRAME_TYPE_SINGLE:
+ case SdlPacket.FRAME_TYPE_CONSECUTIVE:
+ break;
+ case SdlPacket.FRAME_TYPE_CONTROL:
+ //Ok, well here's some interesting bit of knowledge. Because the start session request is from the phone with no knowledge of version it sends out
+ //a v1 packet. THEREFORE there is no message id field. **** Now you know and knowing is half the battle ****
+ if(version==1 && controlFrameInfo == SdlPacket.FRAME_INFO_START_SERVICE){
+ if(dataLength==0){
+ return FINISHED_STATE; //We are done if we don't have any payload
+ }
+ if(dataLength <= V1_V2_MTU_SIZE - V1_HEADER_SIZE){ // sizes from protocol/WiProProtocol.java
+ payload = new byte[dataLength];
+ }else{
+ return ERROR_STATE;
+ }
+ dumpSize = dataLength;
+ return DATA_PUMP_STATE;
+ }
+ break;
+
+ case SdlPacket.FRAME_TYPE_FIRST:
+ if(dataLength==FIRST_FRAME_DATA_SIZE){
+ break;
+ }
+ default:
+ return ERROR_STATE;
+ }
+ if(version==1){ //Version 1 packets will not have message id's
+ if(dataLength == 0){
+ return FINISHED_STATE; //We are done if we don't have any payload
+ }
+ if(dataLength <= V1_V2_MTU_SIZE - V1_HEADER_SIZE){ // sizes from protocol/WiProProtocol.java
+ payload = new byte[dataLength];
+ }else{
+ return ERROR_STATE;
+ }
+ dumpSize = dataLength;
+ return DATA_PUMP_STATE;
+ }else{
+ return MESSAGE_1_STATE;
+ }
+
+ case MESSAGE_1_STATE:
+ messageId += ((int)(rawByte& 0xFF))<<24; //3 bytes x 8 bits
+ return MESSAGE_2_STATE;
+
+ case MESSAGE_2_STATE:
+ messageId += ((int)(rawByte& 0xFF))<<16; //2 bytes x 8 bits
+ return MESSAGE_3_STATE;
+
+ case MESSAGE_3_STATE:
+ messageId += ((int)(rawByte& 0xFF))<<8; //1 byte x 8 bits
+ return MESSAGE_4_STATE;
+
+ case MESSAGE_4_STATE:
+ messageId+=((int)rawByte) & 0xFF;
+
+ if(dataLength==0){
+ return FINISHED_STATE; //We are done if we don't have any payload
+ }
+ try{
+ payload = new byte[dataLength];
+ }catch(OutOfMemoryError oom){
+ return ERROR_STATE;
+ }
+ dumpSize = dataLength;
+ return DATA_PUMP_STATE;
+
+ case DATA_PUMP_STATE:
+ payload[dataLength-dumpSize] = rawByte;
+ dumpSize--;
+ //Do we have any more bytes to read in?
+ if(dumpSize>0){
+ return DATA_PUMP_STATE;
+ }
+ else if(dumpSize==0){
+ return FINISHED_STATE;
+ }else{
+ return ERROR_STATE;
+ }
+ case FINISHED_STATE: //We shouldn't be here...Should have been reset
+ default:
+ return ERROR_STATE;
+
+ }
+
+ }
+
+ public SdlPacket getFormedPacket(){
+ if(state==FINISHED_STATE){
+ //Log.trace(TAG, "Finished packet.");
+ return new SdlPacket(version, compression, frameType,
+ serviceType, controlFrameInfo, sessionId,
+ dataLength, messageId, payload);
+ }else{
+ return null;
+ }
+ }
+
+ public int getState() {
+ return state;
+ }
+
+ public void reset() {
+ version = 0;
+ state = START_STATE;
+ messageId = 0;
+ dataLength = 0;
+ frameType = 0x00; //Set it to null
+ payload = null;
+ }
+
+}
diff --git a/base/src/main/java/com/smartdevicelink/transport/SdlTransport.java b/base/src/main/java/com/smartdevicelink/transport/SdlTransport.java
new file mode 100644
index 000000000..27c87bcef
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/transport/SdlTransport.java
@@ -0,0 +1,122 @@
+package com.smartdevicelink.transport;
+
+import com.smartdevicelink.exception.SdlException;
+import com.smartdevicelink.protocol.SdlPacket;
+import com.smartdevicelink.trace.SdlTrace;
+import com.smartdevicelink.trace.enums.InterfaceActivityDirection;
+import com.smartdevicelink.transport.enums.TransportType;
+import com.smartdevicelink.util.DebugTool;
+
+public abstract class SdlTransport {
+ private static final String SDL_LIB_TRACE_KEY = "42baba60-eb57-11df-98cf-0800200c9a66";
+
+ private final static String FailurePropagating_Msg = "Failure propagating ";
+ private Boolean isConnected = false;
+
+ private String _sendLockObj = "lock";
+
+
+ // Get status of transport connection
+ public Boolean getIsConnected() {
+ return isConnected;
+ }
+
+ //protected SdlTransport(String endpointName, String param2, ITransportListener transportListener)
+ protected SdlTransport(ITransportListener transportListener) {
+ if (transportListener == null) {
+ throw new IllegalArgumentException("Provided transport listener interface reference is null");
+ } // end-if
+ _transportListener = transportListener;
+ } // end-method
+
+ // This method is called by the subclass to indicate that data has arrived from
+ // the transport.
+ protected void handleReceivedPacket(SdlPacket packet) {
+ try {
+ // Trace received data
+ if (packet!=null) {
+ // Send transport data to the siphon server
+ //FIXME SiphonServer.sendBytesFromSDL(receivedBytes, 0, receivedBytesLength);
+ //SdlTrace.logTransportEvent("", null, InterfaceActivityDirection.Receive, receivedBytes, receivedBytesLength, SDL_LIB_TRACE_KEY);
+
+ _transportListener.onTransportPacketReceived(packet);
+ } // end-if
+ } catch (Exception excp) {
+ DebugTool.logError(FailurePropagating_Msg + "handleBytesFromTransport: " + excp.toString(), excp);
+ handleTransportError(FailurePropagating_Msg, excp);
+ } // end-catch
+ } // end-method
+
+ // This method must be implemented by transport subclass, and is called by this
+ // base class to actually send an array of bytes out over the transport. This
+ // method is meant to only be callable within the class hierarchy.
+ protected abstract boolean sendBytesOverTransport(SdlPacket packet);
+
+ // This method is called by whomever has reference to transport to have bytes
+ // sent out over transport.
+ /* public boolean sendBytes(byte[] message) {
+ return sendBytes(message, 0, message.length);
+ }*/ // end-method
+
+ // This method is called by whomever has reference to transport to have bytes
+ // sent out over transport.
+ public boolean sendBytes(SdlPacket packet) {
+ boolean bytesWereSent = false;
+ synchronized (_sendLockObj) {
+ bytesWereSent = sendBytesOverTransport(packet);//message, offset, length);
+ } // end-lock
+ // Send transport data to the siphon server
+ //FIXME SiphonServer.sendBytesFromAPP(message, offset, length);
+
+ //FIXME SdlTrace.logTransportEvent("", null, InterfaceActivityDirection.Transmit, message, offset, length, SDL_LIB_TRACE_KEY);
+ return bytesWereSent;
+ } // end-method
+
+ private ITransportListener _transportListener = null;
+
+ // This method is called by the subclass to indicate that transport connection
+ // has been established.
+ protected void handleTransportConnected() {
+ isConnected = true;
+ try {
+ SdlTrace.logTransportEvent("Transport.connected", null, InterfaceActivityDirection.Receive, null, 0, SDL_LIB_TRACE_KEY);
+ _transportListener.onTransportConnected();
+ } catch (Exception excp) {
+ DebugTool.logError(FailurePropagating_Msg + "onTransportConnected: " + excp.toString(), excp);
+ handleTransportError(FailurePropagating_Msg + "onTransportConnected", excp);
+ } // end-catch
+ } // end-method
+
+ // This method is called by the subclass to indicate that transport disconnection
+ // has occurred.
+ protected void handleTransportDisconnected(final String info) {
+ isConnected = false;
+
+ try {
+ SdlTrace.logTransportEvent("Transport.disconnect: " + info, null, InterfaceActivityDirection.Transmit, null, 0, SDL_LIB_TRACE_KEY);
+ _transportListener.onTransportDisconnected(info);
+ } catch (Exception excp) {
+ DebugTool.logError(FailurePropagating_Msg + "onTransportDisconnected: " + excp.toString(), excp);
+ } // end-catch
+ } // end-method
+
+ // This method is called by the subclass to indicate a transport error has occurred.
+ protected void handleTransportError(final String message, final Exception ex) {
+ isConnected = false;
+ _transportListener.onTransportError(message, ex);
+ }
+
+ public abstract void openConnection() throws SdlException;
+ public abstract void disconnect();
+
+ /**
+ * Abstract method which should be implemented by subclasses in order to return actual type of the transport.
+ *
+ * @return One of {@link TransportType} enumeration values.
+ *
+ * @see TransportType
+ */
+ public abstract TransportType getTransportType();
+
+ public abstract String getBroadcastComment();
+} // end-class
diff --git a/base/src/main/java/com/smartdevicelink/transport/SiphonServer.java b/base/src/main/java/com/smartdevicelink/transport/SiphonServer.java
new file mode 100644
index 000000000..ab8a8a7bd
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/transport/SiphonServer.java
@@ -0,0 +1,384 @@
+package com.smartdevicelink.transport;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.BindException;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+import com.smartdevicelink.util.*;
+
+public class SiphonServer {
+ // Prohibit use of no-arg ctor
+ private SiphonServer() {}
+
+ enum SiphonDataType {
+ fromSdl,
+ fromApp,
+ appLog,
+ formattedTrace,
+ baselineTimeStamp,
+ traceSettings
+ }
+
+ // Boolean to enable/disable the siphon
+ private static Boolean m_siphonEnabled = false;
+
+ // Boolean to determine if the siphon has been initialized
+ private static Boolean m_siphonInitialized = false;
+ private static Boolean m_foundOpenSocket = false;
+ private static Socket m_siphonSocket = null;
+ private static Object m_siphonLock = new Object();
+ private static ServerSocket m_listeningSocket = null;
+ private static short m_listenPort = -1;
+ private static OutputStream m_siphonSocketOutputStream = null;
+ private static SiphonServerThread m_siphonClientThread = null;
+
+ // Initial timestamp in MS
+ private static long m_startTimeStamp = 0;
+
+ // SDL Trace Message Version
+ private static byte m_sdlTraceMsgVersionNumber = 1;
+
+ // Max number of ports to attempt a connection on
+ private final static Integer MAX_NUMBER_OF_PORT_ATTEMPTS = 20;
+
+ // Starting port for future port attempts
+ private final static short FIRST_PORT_TO_ATTEMPT_CONNECTION = 7474;
+
+ // Boolean to determine if formatted trace is being sent
+ private static Boolean m_sendingFormattedTrace = false;
+
+ public static short enableSiphonServer() {
+ m_siphonEnabled = true;
+ SiphonServer.init();
+ return m_listenPort;
+ }
+
+ public static Boolean getSiphonEnabledStatus() {
+ return m_siphonEnabled;
+ }
+
+ public static short disableSiphonServer() {
+ if (!m_siphonEnabled) {
+ m_listenPort = -1;
+ } else {
+ m_siphonEnabled = false;
+ }
+
+ m_siphonInitialized = false;
+
+ try {
+ SiphonServer.closeServer();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return m_listenPort;
+ }
+
+ public static boolean init() {
+ // Only initialize if the siphon has not been initialized previously
+
+ // Check here to be lean. If true, no need to sdlhronize
+ if (m_siphonInitialized) {
+ return true;
+ }
+
+ synchronized (m_siphonLock) {
+ // To prevent a race condition, re-check m_siphonInitialized inside of sdlhronize block
+ if (!m_siphonInitialized) {
+ if (m_siphonClientThread == null) {
+ // Set current time stamp
+ m_startTimeStamp = System.currentTimeMillis();
+
+ // Start Siphon Thread
+ m_siphonClientThread = new SiphonServerThread();
+ m_siphonClientThread.setName("Siphon");
+ m_siphonClientThread.setDaemon(true);
+ m_foundOpenSocket = m_siphonClientThread.findOpenSocket(FIRST_PORT_TO_ATTEMPT_CONNECTION);
+ m_siphonClientThread.start();
+
+ m_siphonInitialized = true;
+ } // end-if
+ } // end-lock
+ }
+
+ return m_siphonInitialized;
+ } // end-method
+
+ public static void closeServer() throws IOException {
+
+ if (m_siphonClientThread != null) {
+ m_siphonClientThread.halt();
+ m_siphonClientThread = null;
+ }
+
+ if (m_listeningSocket != null) {
+ m_listeningSocket.close();
+ m_listeningSocket = null;
+ }
+
+ if (m_siphonSocket != null) {
+ m_siphonSocket.close();
+ m_siphonSocket = null;
+ }
+
+ if (m_siphonSocketOutputStream != null) {
+ m_siphonSocketOutputStream.close();
+ m_siphonSocketOutputStream = null;
+ }
+ }
+
+ public static Boolean sendBytesFromAPP(byte[] msgBytes, int offset, int length) {
+
+ if (m_sendingFormattedTrace) {
+ return false;
+ }
+
+ return sendSiphonData(SiphonDataType.fromApp, msgBytes, offset, length);
+ } // end-method
+
+ public static Boolean sendBytesFromSDL(byte[] msgBytes, int offset, int length) {
+
+ if (m_sendingFormattedTrace) {
+ return false;
+ }
+
+ return sendSiphonData(SiphonDataType.fromSdl, msgBytes, offset, length);
+ } // end-method
+
+ public static Boolean sendSiphonLogData(String message) {
+
+ if (m_sendingFormattedTrace) {
+ return false;
+ }
+
+ if (message == null || message.length() == 0) {
+ return false;
+ }
+
+ byte messageBytes[] = null;
+ int messageLength = 0;
+
+ try {
+ messageBytes = message.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ return false;
+ }
+
+ messageLength = messageBytes.length;
+ return sendSiphonData(SiphonDataType.appLog, messageBytes, 0, messageLength);
+
+ }
+
+ public static Boolean sendFormattedTraceMessage(String message) {
+
+ if (message == null || message.length() == 0) {
+ return false;
+ }
+
+ byte messageBytes[] = null;
+ int messageLength = 0;
+
+ try {
+ messageBytes = message.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ return false;
+ }
+
+ messageLength = messageBytes.length;
+ if (sendSiphonData(SiphonDataType.formattedTrace, messageBytes, 0, messageLength)) {
+ m_sendingFormattedTrace = true;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private static Boolean sendSiphonData(SiphonDataType direction, byte[] msgBytes, int offset, int length) {
+ byte siphonDataTypeIndicator = 0x00;
+
+ long currentDateTime = System.currentTimeMillis();
+ Integer deltaTimeMills = null;
+
+ deltaTimeMills = (int)(currentDateTime - m_startTimeStamp);
+
+ switch(direction) {
+ case fromSdl:
+ siphonDataTypeIndicator = 0x00;
+ break;
+ case fromApp:
+ siphonDataTypeIndicator = 0x01;
+ break;
+ case appLog:
+ siphonDataTypeIndicator = 0x02;
+ break;
+ case formattedTrace:
+ siphonDataTypeIndicator = 0x03;
+ break;
+ case baselineTimeStamp:
+ siphonDataTypeIndicator = 0x04;
+ break;
+ case traceSettings:
+ siphonDataTypeIndicator = 0x05;
+ break;
+ default:
+ siphonDataTypeIndicator = 0x00;
+ break;
+ }
+
+ // Set high bit to indicate new format
+ siphonDataTypeIndicator = (byte)((byte)0x80 | siphonDataTypeIndicator);
+
+ return sendDataToSiphonSocket(siphonDataTypeIndicator, deltaTimeMills, msgBytes, offset, length);
+ }
+
+ private synchronized static Boolean sendDataToSiphonSocket(byte directionIndicator, Integer timeStamp,
+ byte[] msgBytes, int offset, int length) {
+ if (!m_siphonEnabled) {
+ return false;
+ }
+
+ if (msgBytes == null || length == 0) {
+ return false;
+ }
+
+ OutputStream siphonOutputStream = null;
+
+ synchronized (m_siphonLock) {
+ siphonOutputStream = m_siphonSocketOutputStream;
+ } // end-lock
+
+ if (siphonOutputStream == null) {
+ return false;
+ }
+
+ try {
+ // blobSize = length(of message) + 1(size of direction indicator)
+ // + 1 (size of msgVersionNumber) + 4 (size of timeStamp)
+ int blobSize = length + 1 + 1 + 4;
+
+ siphonOutputStream.write(BitConverter.intToByteArray(blobSize));
+ siphonOutputStream.write(new byte[] {directionIndicator});
+ siphonOutputStream.write(new byte[] {m_sdlTraceMsgVersionNumber});
+ siphonOutputStream.write(intToByteArray(timeStamp));
+ siphonOutputStream.write(msgBytes, offset, length);
+ } catch (Exception ex) {
+ return false;
+ } // end-catch
+
+ return true;
+ } // end-method
+
+ private static class SiphonServerThread extends Thread {
+
+ private Boolean isHalted = false;
+ short listenPort;
+
+ public void halt() {
+ isHalted = true;
+ }
+
+ private boolean findOpenSocket(short port) {
+ // Accept incoming sihpon connection from trace utility.
+ Boolean foundOpenPort = false;
+ listenPort = port;
+
+ // Listen to accept incoming connection from SDL
+ while (!foundOpenPort) {
+ try {
+ m_listeningSocket = new ServerSocket(listenPort);
+ foundOpenPort = true;
+ m_listenPort = listenPort;
+ } catch (BindException ex) {
+ listenPort++;
+ if(listenPort > port + MAX_NUMBER_OF_PORT_ATTEMPTS) {
+ return false;
+ }
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
+ return foundOpenPort;
+ }
+
+ private void startServerOnPort() throws IOException {
+ Socket newSocket = null;
+
+ // Wait for a connection
+ newSocket = m_listeningSocket.accept();
+
+ // If isHalted after accept() delay, return
+ if (isHalted) {
+ return;
+ }
+
+ synchronized (m_siphonLock) {
+ // Reset siphonSocketOutputStream
+ if (m_siphonSocketOutputStream != null) {
+ try {
+ m_siphonSocketOutputStream.close();
+ } catch (IOException e) {
+ // Do nothing
+ }
+ m_siphonSocketOutputStream = null;
+ }
+
+ // Reset siphonSocket
+ if (m_siphonSocket != null) {
+ try {
+ m_siphonSocket.close();
+ } catch (IOException e) {
+ // Do nothing
+ }
+ m_siphonSocket = null;
+ }
+
+ // Store the new socket
+ m_siphonSocket = newSocket;
+
+ // Set Socket Options
+ m_siphonSocket.setKeepAlive(true);
+
+ // Get the output stream of the connection
+ m_siphonSocketOutputStream = m_siphonSocket.getOutputStream();
+
+ // Output version number to the Siphon upon connection (version number prepending to logInfo)
+ DebugTool.logInfo("Siphon connected.");
+ } // end-lock
+ } // end-method
+
+ @Override
+ public void run() {
+ try {
+ if (m_foundOpenSocket){
+ while (!isHalted) {
+ startServerOnPort();
+ }
+ }
+ } catch (Exception ex) {
+ // Do nothing
+ } finally {
+ if (m_listeningSocket != null) {
+ try {
+ m_listeningSocket.close();
+ } catch (IOException e) {
+ // Do nothing
+ }
+ m_listeningSocket = null;
+ }
+ }
+ }
+ }
+
+ private static final byte[] intToByteArray(int value) {
+ return new byte[] {
+ (byte)(value >>> 24),
+ (byte)(value >>> 16),
+ (byte)(value >>> 8),
+ (byte)value};
+ }
+} // end-class \ No newline at end of file
diff --git a/base/src/main/java/com/smartdevicelink/transport/TransportConstants.java b/base/src/main/java/com/smartdevicelink/transport/TransportConstants.java
new file mode 100644
index 000000000..a66651502
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/transport/TransportConstants.java
@@ -0,0 +1,263 @@
+package com.smartdevicelink.transport;
+
+
+/**
+ * These constants are shared between the router service and the SDL base service.
+ * They are defined as strings/actions/values that both of them can understand.
+ * Attempting to use standard HTTP error codes as definitions.
+ * @author Joey Grover
+ *
+ */
+public class TransportConstants {
+ public static final String START_ROUTER_SERVICE_ACTION ="sdl.router.startservice";
+ public static final String ROUTER_SERVICE_ACTION = "com.smartdevicelink.router.service";
+ public static final String FOREGROUND_EXTRA = "foreground";
+
+ public static final String BIND_LOCATION_PACKAGE_NAME_EXTRA = "BIND_LOCATION_PACKAGE_NAME_EXTRA";
+ public static final String BIND_LOCATION_CLASS_NAME_EXTRA = "BIND_LOCATION_CLASS_NAME_EXTRA";
+
+ public static final String ALT_TRANSPORT_RECEIVER = "com.sdl.android.alttransport";
+ public static final String ALT_TRANSPORT_CONNECTION_STATUS_EXTRA = "connection_status";
+ public static final int ALT_TRANSPORT_DISCONNECTED = 0;
+ public static final int ALT_TRANSPORT_CONNECTED = 1;
+ public static final String ALT_TRANSPORT_READ = "read";//Read from the alt transport, goes to the app
+ public static final String ALT_TRANSPORT_WRITE = "write";//Write to the alt transport, comes from the app
+ public static final String ALT_TRANSPORT_ADDRESS_EXTRA = "altTransportAddress";
+
+ public static final String START_ROUTER_SERVICE_SDL_ENABLED_EXTRA = "sdl_enabled";
+ public static final String START_ROUTER_SERVICE_SDL_ENABLED_APP_PACKAGE = "package_name";
+ public static final String START_ROUTER_SERVICE_SDL_ENABLED_CMP_NAME = "component_name";
+ public static final String START_ROUTER_SERVICE_TRANSPORT_CONNECTED = "transport_connected"; //Extra for the transport that just connected
+ public static final String START_ROUTER_SERVICE_SDL_ENABLED_PING = "ping";
+ @Deprecated
+ public static final String FORCE_TRANSPORT_CONNECTED = "force_connect"; //This is legacy, do not refactor this.
+ public static final String ROUTER_SERVICE_VALIDATED = "router_service_validated";
+
+ @Deprecated
+ public static final String REPLY_TO_INTENT_EXTRA = "ReplyAddress";
+ public static final String CONNECT_AS_CLIENT_BOOLEAN_EXTRA = "connectAsClient";
+ public static final String PACKAGE_NAME_STRING = "package.name";
+ public static final String APP_ID_EXTRA = "app.id";//Sent as a Long. This is no longer used
+ public static final String APP_ID_EXTRA_STRING = "app.id.string";
+ public static final String ROUTER_MESSAGING_VERSION = "router.messaging.version";
+
+ public static final String SESSION_ID_EXTRA = "session.id";
+
+ public static final String ENABLE_LEGACY_MODE_EXTRA = "ENABLE_LEGACY_MODE_EXTRA";
+
+ @Deprecated
+ public static final String HARDWARE_DISCONNECTED = "hardware.disconect";
+ public static final String TRANSPORT_DISCONNECTED = "transport.disconect";
+ public static final String HARDWARE_CONNECTED = "hardware.connected";
+ public static final String CURRENT_HARDWARE_CONNECTED = "current.hardware.connected";
+
+ public static final String SEND_PACKET_TO_APP_LOCATION_EXTRA_NAME = "senderintent";
+ public static final String SEND_PACKET_TO_ROUTER_LOCATION_EXTRA_NAME = "routerintent";
+
+
+ public static final String BIND_REQUEST_TYPE_CLIENT = "BIND_REQUEST_TYPE_CLIENT";
+ public static final String BIND_REQUEST_TYPE_ALT_TRANSPORT = "BIND_REQUEST_TYPE_ALT_TRANSPORT";
+ public static final String BIND_REQUEST_TYPE_STATUS = "BIND_REQUEST_TYPE_STATUS";
+ public static final String BIND_REQUEST_TYPE_USB_PROVIDER = "BIND_REQUEST_TYPE_USB_PROVIDER";
+
+
+ public static final String PING_ROUTER_SERVICE_EXTRA = "ping.router.service";
+
+ public static final String SDL_NOTIFICATION_CHANNEL_ID = "sdl_notification_channel";
+ public static final String SDL_NOTIFICATION_CHANNEL_NAME = "SmartDeviceLink";
+
+
+
+
+ /**
+ * This class houses all important router service versions
+ */
+ public class RouterServiceVersions{
+ /**
+ * This version of the router service is when app IDs went from Longs to Strings
+ */
+ public static final int APPID_STRING = 4;
+ }
+
+
+ /*
+ * Alt transport
+ *
+ */
+
+ /**
+ * This will be the response when a hardware connect event comes through from an alt transport.
+ * This is because it only makes sense to register an alt transport when a connection is established with that
+ * transport, not waiting for one.
+ */
+ public static final int ROUTER_REGISTER_ALT_TRANSPORT_RESPONSE = 0x02;
+ public static final int ROUTER_REGISTER_ALT_TRANSPORT_RESPONSE_SUCESS = 0x00;
+ /**
+ * There is already another alt transport connected, so we are unable to register this one
+ */
+ public static final int ROUTER_REGISTER_ALT_TRANSPORT_ALREADY_CONNECTED = 0x01;
+
+ /**
+ * This means the router service is shutting down for some reason. Most likely
+ */
+ public static final int ROUTER_SHUTTING_DOWN_NOTIFICATION = 0x0F;
+
+ /**
+ * There is a newer service to start up, so this one is shutting down
+ */
+ public static final int ROUTER_SHUTTING_DOWN_REASON_NEWER_SERVICE = 0x00;
+
+ /*
+ * Router to Client binding service
+ *
+ */
+
+ //WHATS
+ /**
+ * Command to the service to register a client, receiving callbacks
+ * from the service. The Message's replyTo field must be a Messenger of
+ * the client where callbacks should be sent.
+ */
+ public static final int ROUTER_REGISTER_CLIENT = 0x01;
+ /**
+ * This response message will contain if the registration request was successful or not. If not, the reason will be
+ * great or equal to 1 and be descriptive of why it was denied.
+ */
+ public static final int ROUTER_REGISTER_CLIENT_RESPONSE = 0x02;
+ //Response arguments
+ public static final int REGISTRATION_RESPONSE_SUCESS = 0x00;
+ public static final int REGISTRATION_RESPONSE_DENIED_AUTHENTICATION_FAILED = 0x01;
+ public static final int REGISTRATION_RESPONSE_DENIED_NO_CONNECTION = 0x02;
+ public static final int REGISTRATION_RESPONSE_DENIED_APP_ID_NOT_INCLUDED = 0x03;
+ public static final int REGISTRATION_RESPONSE_DENIED_LEGACY_MODE_ENABLED = 0x04;
+ public static final int REGISTRATION_RESPONSE_DENIED_UNKNOWN = 0xFF;
+
+ /**
+ * Command to the service to unregister a client, to stop receiving callbacks
+ * from the service. The Message's replyTo field must be a Messenger of
+ * the client as previously given with MSG_REGISTER_CLIENT. Also include the app id as arg1.
+ */
+ public static final int ROUTER_UNREGISTER_CLIENT = 0x03;
+ public static final int ROUTER_UNREGISTER_CLIENT_RESPONSE = 0x04;
+ //Response arguments
+ public static final int UNREGISTRATION_RESPONSE_SUCESS = 0x00;
+ public static final int UNREGISTRATION_RESPONSE_FAILED_APP_ID_NOT_FOUND = 0x01;
+
+
+ /**
+ * what message type to notify apps of a hardware connection event. The connection event will be placed in the bundle
+ * attached to the message
+ */
+ public static final int HARDWARE_CONNECTION_EVENT = 0x05;
+ public static final int HARDWARE_CONNECTION_EVENT_CONNECTED = 0x10;
+ public static final int HARDWARE_CONNECTION_EVENT_DISCONNECTED = 0x30;
+
+
+ public static final int ROUTER_REQUEST_BT_CLIENT_CONNECT = 0x10;
+ public static final int ROUTER_REQUEST_BT_CLIENT_CONNECT_RESPONSE = 0x11;
+
+ /**
+ * This provides the app with an ability to request another session within the router service.
+ * A replyTo must be provided or else there won't be a response
+ */
+ public static final int ROUTER_REQUEST_NEW_SESSION = 0x12;
+ //Request arguments
+ //See TRANSPORT_TYPE & TRANSPORT_ADDRESS
+
+
+ public static final int ROUTER_REQUEST_NEW_SESSION_RESPONSE = 0x13;
+ //Response arguments
+ public static final int ROUTER_REQUEST_NEW_SESSION_RESPONSE_SUCESS = 0x00;
+ public static final int ROUTER_REQUEST_NEW_SESSION_RESPONSE_FAILED_APP_NOT_FOUND = 0x01;
+ public static final int ROUTER_REQUEST_NEW_SESSION_RESPONSE_FAILED_APP_ID_NOT_INCL = 0x02;
+
+ /**
+ * This provides the app with an ability to request another session within the router service.
+ * A replyTo must be provided or else there won't be a response
+ */
+ public static final int ROUTER_REMOVE_SESSION = 0x14;
+ public static final int ROUTER_REMOVE_SESSION_RESPONSE = 0x15;
+ //Response arguments
+ public static final int ROUTER_REMOVE_SESSION_RESPONSE_SUCESS = 0x00;
+ public static final int ROUTER_REMOVE_SESSION_RESPONSE_FAILED_APP_NOT_FOUND = 0x01;
+ public static final int ROUTER_REMOVE_SESSION_RESPONSE_FAILED_APP_ID_NOT_INCL = 0x02;
+ public static final int ROUTER_REMOVE_SESSION_RESPONSE_FAILED_SESSION_NOT_FOUND = 0x03;
+ public static final int ROUTER_REMOVE_SESSION_RESPONSE_FAILED_SESSION_ID_NOT_INCL = 0x04;
+ /**
+ * Command to have router service to send a packet
+ */
+ public static final int ROUTER_SEND_PACKET = 0x20;
+
+ //response
+ /**
+ * Router has received a packet and sent it to the client
+ */
+ public static final int ROUTER_RECEIVED_PACKET = 0x26;
+ //response
+
+ /**
+ * Command to tell router service details of secondary transport
+ */
+ public static final int ROUTER_REQUEST_SECONDARY_TRANSPORT_CONNECTION = 0x30;
+
+ //BUNDLE EXTRAS
+
+ public static final String FORMED_PACKET_EXTRA_NAME = "packet";
+
+ public static final String BYTES_TO_SEND_EXTRA_NAME = "bytes";
+ public static final String BYTES_TO_SEND_EXTRA_OFFSET = "offset";
+ public static final String BYTES_TO_SEND_EXTRA_COUNT = "count";
+ public static final String BYTES_TO_SEND_FLAGS = "flags";
+
+ public static final String PACKET_PRIORITY_COEFFICIENT = "priority_coefficient";
+
+ public static final String TRANSPORT_TYPE = "transport_type";
+ public static final String TRANSPORT_ADDRESS = "transport_address";
+
+ public static final int BYTES_TO_SEND_FLAG_NONE = 0x00;
+ public static final int BYTES_TO_SEND_FLAG_SDL_PACKET_INCLUDED = 0x01;
+ public static final int BYTES_TO_SEND_FLAG_LARGE_PACKET_START = 0x02;
+ public static final int BYTES_TO_SEND_FLAG_LARGE_PACKET_CONT = 0x04;
+ public static final int BYTES_TO_SEND_FLAG_LARGE_PACKET_END = 0x08;
+
+ public static final String CONNECTED_DEVICE_STRING_EXTRA_NAME = "devicestring";
+
+ public static final int PACKET_SENDING_ERROR_NOT_REGISTERED_APP = 0x00;
+ public static final int PACKET_SENDING_ERROR_NOT_CONNECTED = 0x01;
+ public static final int PACKET_SENDING_ERROR_UKNOWN = 0xFF;
+
+ public static final String ROUTER_SERVICE_VERSION = "router_service_version";
+
+ /**
+ * Status binder
+ */
+
+ public static final int ROUTER_STATUS_CONNECTED_STATE_REQUEST = 0x01;
+ public static final int ROUTER_STATUS_CONNECTED_STATE_RESPONSE = 0x02;
+ /**
+ * This flag when used to check router status will trigger the router service in sending out a ping that if it is connected to a device
+ */
+ public static final int ROUTER_STATUS_FLAG_TRIGGER_PING = 0x02;
+
+
+ /**
+ * Usb Transfer binder
+ */
+
+ public static final int USB_CONNECTED_WITH_DEVICE = 0x55;
+ public static final int ROUTER_USB_ACC_RECEIVED = 0x56;
+
+
+ /**
+ * Multiple-transports related constants
+ *
+ */
+ public static final String IAP_BLUETOOTH = "IAP_BLUETOOTH";
+ public static final String IAP_USB = "IAP_USB";
+ public static final String IAP_USB_HOST_MODE = "TCP_WIFI";
+ public static final String IAP_CARPLAY = "IAP_CARPLAY";
+ public static final String SPP_BLUETOOTH = "SPP_BLUETOOTH";
+ public static final String AOA_USB = "AOA_USB";
+ public static final String TCP_WIFI = "TCP_WIFI";
+
+}
diff --git a/base/src/main/java/com/smartdevicelink/transport/utl/TransportRecord.java b/base/src/main/java/com/smartdevicelink/transport/utl/TransportRecord.java
new file mode 100644
index 000000000..bcfc2e373
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/transport/utl/TransportRecord.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2018 Livio, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of the Livio Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.smartdevicelink.transport.utl;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.smartdevicelink.transport.enums.TransportType;
+
+public class TransportRecord implements Parcelable{
+
+ private TransportType type;
+ private String address;
+
+ public TransportRecord(TransportType transportType, String address){
+ this.type = transportType;
+ this.address = address;
+ }
+
+ public TransportType getType() {
+ return type;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if(obj == null) {
+ return false;
+ }
+
+ if (obj instanceof TransportRecord) {
+ TransportRecord record = (TransportRecord) obj;
+ return record.type != null && record.type.equals(type) //Transport type is the same
+ && ((record.address == null && address == null) //Both addresses are null
+ || (record.address != null && record.address.equals(address))); //Or they match
+ }
+
+ return super.equals(obj);
+ }
+
+ @Override
+ public String toString(){
+ StringBuilder builder = new StringBuilder();
+ builder.append("Transport Type: ");
+ builder.append(type.name());
+ builder.append(" Address: ");
+ builder.append(address);
+ return builder.toString();
+ }
+
+ public TransportRecord(Parcel p){
+ if (p.readInt() == 1) { //We should have a transport type attached
+ String transportName = p.readString();
+ if(transportName != null){
+ this.type = TransportType.valueOf(transportName);
+ }
+ }
+
+ if (p.readInt() == 1) { //We should have a transport address attached
+ address = p.readString();
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(type!=null? 1 : 0);
+ if(type != null){
+ dest.writeString(type.name());
+ }
+
+ dest.writeInt(address !=null? 1 : 0);
+ if(address != null){
+ dest.writeString(address);
+ }
+ }
+
+ public static final Parcelable.Creator<TransportRecord> CREATOR = new Parcelable.Creator<TransportRecord>() {
+ public TransportRecord createFromParcel(Parcel in) {
+ return new TransportRecord(in);
+ }
+
+ @Override
+ public TransportRecord[] newArray(int size) {
+ return new TransportRecord[size];
+ }
+
+ };
+}
diff --git a/base/src/main/java/com/smartdevicelink/util/BitConverter.java b/base/src/main/java/com/smartdevicelink/util/BitConverter.java
new file mode 100644
index 000000000..a681a75a8
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/util/BitConverter.java
@@ -0,0 +1,116 @@
+package com.smartdevicelink.util;
+
+public class BitConverter {
+ /**
+ * @param bytes byte array that will be converted to hex
+ * @return the String containing converted hex values or null if byte array is null
+ */
+ public static String bytesToHex(byte [] bytes) {
+ if (bytes == null) { return null; }
+ return bytesToHex(bytes, 0, bytes.length);
+ } // end-method
+
+ /**
+ * @param bytes byte array that will be converted to hex
+ * @param offset int representing the offset to begin conversion at
+ * @param length int representing number of bytes in array to convert
+ * @return the String containing converted hex values or null if byte array is null
+ */
+ public static String bytesToHex(byte[] bytes, int offset, int length) {
+ if (bytes == null) { return null; }
+ final char[] HexDigits = new char[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+ byte b;
+ char[] hexChars = new char[2 * length];
+ //StringBuffer sb = new StringBuffer();
+ int upperBound = Math.min(bytes.length, (offset + length));
+ int baidx = 0;
+ int sidx = 0;
+ for (baidx = offset; baidx < upperBound; baidx++) {
+ // Get the byte from the array
+ b = bytes[baidx];
+ // Use nibbles as index into hex digit array (left nibble, then right)
+ hexChars[sidx++] = HexDigits[(b & 0xf0) >> 4];
+ hexChars[sidx++] = HexDigits[(b & 0x0f)];
+ } // end-for
+ return new String(hexChars);
+ } // end-method
+
+ /**
+ * @param hexString the String containing converted hex values
+ * @return byte array converted from input String or null if String is null
+ */
+ public static byte [] hexToBytes(String hexString) {
+ if (hexString == null) { return null; }
+ if (hexString.length() % 2 != 0) {
+ hexString = "0" + hexString;
+ }
+ byte [] theBytes = new byte[hexString.length() / 2];
+ for (int i = 0; i < hexString.length(); i += 2) {
+ String byteString = hexString.substring(i, i + 2);
+ byte theByte = (byte)Integer.parseInt(byteString, 16);
+ theBytes[i/2] = theByte;
+ }
+ return theBytes;
+ } // end-method
+
+ public static final byte[] intToByteArray(int value) {
+ return new byte[] {
+ (byte)(value >>> 24),
+ (byte)(value >>> 16),
+ (byte)(value >>> 8),
+ (byte)value};
+ }
+
+ /**
+ * @param sizeBuf byte array that will be converted to int
+ * @return int converted from byte array or -1 if byte array is null
+ */
+ public static int intFromByteArray(byte[] sizeBuf, int offset) {
+ if (sizeBuf == null) { return -1; }
+ int ret = 0;
+ for (int i = offset; i < offset + 4; i++) {
+ ret <<= 8;
+ ret |= 0xFF & sizeBuf[i];
+ }
+ return ret;
+ }
+
+ public static final byte[] shortToByteArray(short value) {
+ return new byte[] {
+ (byte)(value >>> 8),
+ (byte)value};
+ }
+
+ /**
+ * @param sizeBuf byte array that will be converted to short
+ * @return short converted from byte array or -1 if byte array is null
+ */
+ public static short shortFromByteArray(byte[] sizeBuf, int offset) {
+ if (sizeBuf == null) { return -1; }
+ short ret = 0;
+ for (int i = offset; i < offset + 2; i++) {
+ ret <<= 8;
+ ret |= 0xFF & sizeBuf[i];
+ }
+ return ret;
+ }
+
+ /**
+ * Converts the byte array into a string of hex values.
+ * @param bytes byte array that will be converted to hex
+ * @param end EXCLUSIVE so if it it receives 10 it will print 0-9
+ * @return the String containing converted hex values or null if byte array is null
+ */
+ public static String bytesToHex(byte[] bytes,int end){
+ if (bytes == null) { return null; }
+ if(bytes.length<end){
+ end = bytes.length;
+ }
+ StringBuilder sb = new StringBuilder();
+ for(int i=0;i<end;i++){
+ sb.append(" ");
+ sb.append(String.format("%02X ", bytes[i]));
+ }
+ return sb.toString();
+ }
+}
diff --git a/base/src/main/java/com/smartdevicelink/util/ByteEnumer.java b/base/src/main/java/com/smartdevicelink/util/ByteEnumer.java
new file mode 100644
index 000000000..0b67d9992
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/util/ByteEnumer.java
@@ -0,0 +1,60 @@
+package com.smartdevicelink.util;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+public abstract class ByteEnumer {
+
+ protected ByteEnumer(byte value, String name) {
+ this.value = value;
+ this.name = name;
+ }
+
+ private byte value;
+ private String name;
+
+ public byte getValue() { return value; }
+ public String getName() { return name; }
+
+ public boolean equals(ByteEnumer other) {
+ return name == other.getName();
+ }
+
+ public boolean eq(ByteEnumer other) {
+ return equals(other);
+ }
+
+ public byte value() {
+ return value;
+ }
+
+ public static ByteEnumer get(Vector<?> theList, byte value) {
+ Enumeration<?> enumer = theList.elements();
+ while (enumer.hasMoreElements()) {
+ try {
+ ByteEnumer current = (ByteEnumer)enumer.nextElement();
+ if (current.getValue() == value) {
+ return current;
+ }
+ } catch (ClassCastException e) {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ public static ByteEnumer get(Vector<?> theList, String name) {
+ Enumeration<?> enumer = theList.elements();
+ while (enumer.hasMoreElements()) {
+ try {
+ ByteEnumer current = (ByteEnumer)enumer.nextElement();
+ if (current.getName().equals(name)) {
+ return current;
+ }
+ } catch (ClassCastException e) {
+ return null;
+ }
+ }
+ return null;
+ }
+} \ No newline at end of file
diff --git a/base/src/main/java/com/smartdevicelink/util/CorrelationIdGenerator.java b/base/src/main/java/com/smartdevicelink/util/CorrelationIdGenerator.java
new file mode 100644
index 000000000..18ff93622
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/util/CorrelationIdGenerator.java
@@ -0,0 +1,25 @@
+package com.smartdevicelink.util;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class CorrelationIdGenerator {
+
+ private static final int CORRELATION_ID_START = 0;
+
+ private static final AtomicInteger sNextCorrelationId = new AtomicInteger(CORRELATION_ID_START);
+
+ public static int generateId() {
+ for (;;) {
+ final int result = sNextCorrelationId.get();
+ // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
+ int newValue = result + 1;
+
+ if (newValue > 0x00FFFFFF){
+ newValue = CORRELATION_ID_START; // Roll over to 0.
+ }
+ if (sNextCorrelationId.compareAndSet(result, newValue)) {
+ return result;
+ }
+ }
+ }
+}
diff --git a/base/src/main/java/com/smartdevicelink/util/IConsole.java b/base/src/main/java/com/smartdevicelink/util/IConsole.java
new file mode 100644
index 000000000..8d6d4a0f1
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/util/IConsole.java
@@ -0,0 +1,10 @@
+package com.smartdevicelink.util;
+
+
+public interface IConsole {
+ void logInfo(String msg);
+ void logError(String msg);
+ void logError(String msg, Throwable ex);
+ void logRPCSend(String rpcMsg);
+ void logRPCReceive(String rpcMsg);
+}
diff --git a/base/src/main/java/com/smartdevicelink/util/SdlDataTypeConverter.java b/base/src/main/java/com/smartdevicelink/util/SdlDataTypeConverter.java
new file mode 100644
index 000000000..0b47a59cd
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/util/SdlDataTypeConverter.java
@@ -0,0 +1,63 @@
+package com.smartdevicelink.util;
+
+/**
+ * This is a utility class to aid in handling values stored in the RPC classes.
+ */
+public class SdlDataTypeConverter {
+
+ /**
+ * Converts values that are retrieved from an RPC parameters Hashtable as an
+ * Object into the standard number value of the mobile API, Double.
+ *
+ * @param originalValue The value retrieved from an RPC parameters Hashtable.
+ * @return The Double representation of an integer or double value stored in
+ * the Object, or null if the value could not be converted.
+ */
+ public static Double objectToDouble(Object originalValue) {
+
+ if (originalValue == null) {
+ return null;
+ }
+
+ Double result = null;
+
+ // Uses reflection to determine if the object is a valid type.
+ if (originalValue instanceof Integer) {
+ result = ((Integer) originalValue).doubleValue();
+ } else if (originalValue instanceof Float){
+ result = ((Float) originalValue).doubleValue();
+ } else if (originalValue instanceof Double){
+ result = (Double) originalValue;
+ }
+
+ return result;
+ }
+
+ /**
+ * Converts values that are retrieved from an RPC parameters Hashtable as an
+ * Object into the standard number value of the mobile API, Float.
+ *
+ * @param originalValue The value retrieved from an RPC parameters Hashtable.
+ * @return The Float representation of an integer or float value stored in
+ * the Object, or null if the value could not be converted.
+ */
+ public static Float objectToFloat(Object originalValue) {
+
+ if (originalValue == null) {
+ return null;
+ }
+
+ Float result = null;
+
+ // Uses reflection to determine if the object is a valid type.
+ if (originalValue instanceof Integer) {
+ result = ((Integer) originalValue).floatValue();
+ } else if (originalValue instanceof Double){
+ result = ((Double) originalValue).floatValue();
+ } else if (originalValue instanceof Float){
+ result = (Float) originalValue;
+ }
+
+ return result;
+ }
+}
diff --git a/base/src/main/java/com/smartdevicelink/util/Version.java b/base/src/main/java/com/smartdevicelink/util/Version.java
new file mode 100644
index 000000000..78eac8db4
--- /dev/null
+++ b/base/src/main/java/com/smartdevicelink/util/Version.java
@@ -0,0 +1,75 @@
+package com.smartdevicelink.util;
+
+
+public class Version {
+
+ final int major,minor,patch;
+
+ public Version(){
+ major = 0;
+ minor = 0;
+ patch = 0;
+ }
+
+ public Version(int major, int minor, int patch){
+ this.major = major;
+ this.minor = minor;
+ this.patch = patch;
+ }
+
+ public Version(String versionString){
+ String[] versions = versionString.split("\\.");
+ if(versions.length!=3){
+ throw new IllegalArgumentException("Incorrect version string format");
+ }
+ major = Integer.valueOf(versions[0]);
+ minor = Integer.valueOf(versions[1]);
+ patch = Integer.valueOf(versions[2]);
+
+ }
+
+ public int getMajor() {
+ return major;
+ }
+
+ public int getMinor() {
+ return minor;
+ }
+
+ public int getPatch() {
+ return patch;
+ }
+
+ /**
+ * Method to test if this instance of Version is newer than the supplied one.
+ * @param version the version to check against
+ * @return 1 if this instance is newer, -1 if supplied version is newer, and 0 if they are equal
+ */
+ public int isNewerThan(Version version){
+ if(this.major > version.major){
+ return 1;
+ }else if(this.major == version.major){
+ if(this.minor > version.minor){
+ return 1;
+ } else if(this.minor == version.minor){
+ if(this.patch > version.patch){
+ return 1;
+ }else if(this.patch == version.patch){
+ return 0;
+ }
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append(major);
+ builder.append(".");
+ builder.append(minor);
+ builder.append(".");
+ builder.append(patch);
+ return builder.toString();
+ }
+}