/*******************************************************************************
* Copyright 2013-2016 alladin-IT GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package at.alladin.rmbt.client.helper;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TimeZone;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import at.alladin.rmbt.client.Ping;
import at.alladin.rmbt.client.RMBTTestParameter;
import at.alladin.rmbt.client.SpeedItem;
import at.alladin.rmbt.client.TotalTestResult;
import at.alladin.rmbt.client.ndt.UiServicesAdapter;
import at.alladin.rmbt.client.v2.task.TaskDesc;
import at.alladin.rmbt.client.v2.task.service.TestMeasurement;
import at.alladin.rmbt.client.v2.task.service.TestMeasurement.TrafficDirection;
import at.alladin.rmbt.util.model.shared.exception.ErrorStatus;
public class ControlServerConnection
{
// url to make request
private URL hostUrl;
private boolean testEncryption;
private String testToken = "";
private String testId = "";
private String testUuid = "";
private long testTime = 0;
private String testHost = "";
private int testPort = 0;
private String remoteIp = "";
private String serverName;
private String provider;
private int testDuration = 0;
private int testNumThreads = 0;
private int testNumPings = 0;
private String clientUUID = "";
private URL resultURL;
private URL resultQoSURI;
private String errorMsg = null;
private boolean hasError = false;
private Set<ErrorStatus> lastErrorList;
public TaskDesc udpTaskDesc;
public TaskDesc dnsTaskDesc;
public TaskDesc ntpTaskDesc;
public TaskDesc httpTaskDesc;
public TaskDesc tcpTaskDesc;
private JSONObject lastTestResult;
public List<TaskDesc> v2TaskDesc;
private long startTimeMillis = 0;
private long startTimeNs = 0;
private static URL getUrl(final boolean encryption, final String host, final String pathPrefix, final int port,
final String path)
{
try
{
final String protocol = encryption ? "https" : "http";
final int defaultPort = encryption ? 443 : 80;
final String totalPath = (pathPrefix != null ? pathPrefix : "") + Config.RMBT_CONTROL_PATH + path;
if (defaultPort == port)
return new URL(protocol, host, totalPath);
else
return new URL(protocol, host, port, totalPath);
}
catch (final MalformedURLException e)
{
return null;
}
}
/**
* requests the parameters for the v2 tests
* @param host
* @param pathPrefix
* @param port
* @param encryption
* @param geoInfo
* @param uuid
* @param clientType
* @param clientName
* @param clientVersion
* @param additionalValues
* @return
*/
public String requestQoSTestParameters(final String host, final String pathPrefix, final int port,
final boolean encryption, final ArrayList<String> geoInfo, final String uuid, final String clientType,
final String clientName, final String clientVersion, final JSONObject additionalValues)
{
resetErrors();
clientUUID = uuid;
hostUrl = getUrl(encryption, host, pathPrefix, port, Config.RMBT_CONTROL_V2_TESTS);
System.out.println("Connection to " + hostUrl);
final JSONObject regData = new JSONObject();
try
{
regData.put("uuid", uuid);
regData.put("client", clientName);
regData.put("version", Config.RMBT_VERSION_NUMBER);
regData.put("type", clientType);
regData.put("softwareVersion", clientVersion);
regData.put("softwareRevision", RevisionHelper.getVerboseRevision());
regData.put("language", Locale.getDefault().getLanguage());
regData.put("timezone", TimeZone.getDefault().getID());
regData.put("time", System.currentTimeMillis());
if (geoInfo != null)
{
final JSONObject locData = new JSONObject();
locData.put("time", geoInfo.get(0));
locData.put("lat", geoInfo.get(1));
locData.put("long", geoInfo.get(2));
locData.put("accuracy", geoInfo.get(3));
locData.put("altitude", geoInfo.get(4));
locData.put("bearing", geoInfo.get(5));
locData.put("speed", geoInfo.get(6));
locData.put("provider", geoInfo.get(7));
regData.accumulate("location", locData);
}
addToJSONObject(regData, additionalValues);
}
catch (final JSONException e1)
{
hasError = true;
errorMsg = "Error gernerating request";
// e1.printStackTrace();
}
// getting JSON string from URL
final JSONObject response = JSONParser.sendJSONToUrl(hostUrl, regData);
if (response != null)
try
{
final JSONArray errorList = response.getJSONArray("error");
checkHasErrors(response);
// System.out.println(response.toString(4));
if (errorList.length() == 0)
{
int testPort = 5233;
Map<String, Object> testParams = null;
testParams = JSONParser.toMap(response.getJSONObject("objectives"));
v2TaskDesc = new ArrayList<TaskDesc>();
for (Entry<String, Object> e : testParams.entrySet()) {
List<HashMap<String, Object>> paramList = (List<HashMap<String, Object>>) e.getValue();
for (HashMap<String, Object> params : paramList) {
TaskDesc taskDesc = new TaskDesc(testHost, testPort, encryption, testToken, 0, 1, 0, System.nanoTime(), params, e.getKey());
v2TaskDesc.add(taskDesc);
}
}
}
else
{
hasError = true;
for (int i = 0; i < errorList.length(); i++)
{
if (i > 0)
errorMsg += "\n";
errorMsg += errorList.getString(i);
}
}
// }
}
catch (final JSONException e)
{
hasError = true;
errorMsg = "Error parsing server response";
e.printStackTrace();
}
else
{
hasError = true;
errorMsg = "No response";
}
return errorMsg;
}
private void resetErrors() {
lastErrorList = null;
}
private boolean checkHasErrors(JSONObject response) throws JSONException {
final JSONArray errorList = response.getJSONArray("error");
final JSONArray errorFlags = response.optJSONArray("error_flags");
if (errorFlags != null && errorFlags.length() > 0) {
lastErrorList = new HashSet<ErrorStatus>();
for (int i = 0; i < errorFlags.length(); i++) {
lastErrorList.add(ErrorStatus.valueOf(errorFlags.getString(i)));
}
}
return errorList.length() > 0;
}
public String requestNewTestConnection(final String host, final String pathPrefix, final int port,
final boolean encryption, final ArrayList<String> geoInfo, final String uuid, final String clientType,
final String clientName, final String clientVersion, final JSONObject additionalValues)
{
resetErrors();
String errorMsg = null;
// url to make request to
clientUUID = uuid;
hostUrl = getUrl(encryption, host, pathPrefix, port, Config.RMBT_CONTROL_MAIN_URL);
System.out.println("Connection to " + hostUrl);
final JSONObject regData = new JSONObject();
try
{
regData.put("uuid", uuid);
regData.put("client", clientName);
regData.put("version", Config.RMBT_VERSION_NUMBER);
regData.put("type", clientType);
regData.put("softwareVersion", clientVersion);
regData.put("softwareRevision", RevisionHelper.getVerboseRevision());
regData.put("language", Locale.getDefault().getLanguage());
regData.put("timezone", TimeZone.getDefault().getID());
startTimeMillis = System.currentTimeMillis();
regData.put("time", startTimeMillis);
startTimeNs = System.nanoTime();
if (geoInfo != null)
{
final JSONObject locData = new JSONObject();
locData.put("time", geoInfo.get(0));
locData.put("lat", geoInfo.get(1));
locData.put("long", geoInfo.get(2));
locData.put("accuracy", geoInfo.get(3));
locData.put("altitude", geoInfo.get(4));
locData.put("bearing", geoInfo.get(5));
locData.put("speed", geoInfo.get(6));
locData.put("provider", geoInfo.get(7));
regData.accumulate("location", locData);
}
addToJSONObject(regData, additionalValues);
}
catch (final JSONException e1)
{
errorMsg = "Error gernerating request";
// e1.printStackTrace();
}
// getting JSON string from URL
final JSONObject response = JSONParser.sendJSONToUrl(hostUrl, regData);
if (response != null)
try
{
final JSONArray errorList = response.getJSONArray("error");
// System.out.println(response.toString(4));
checkHasErrors(response);
if (errorList.length() == 0)
{
clientUUID = response.optString("uuid", clientUUID);
testToken = response.getString("test_token");
testId = response.getString("test_id");
testUuid = response.getString("test_uuid");
testTime = System.currentTimeMillis() + 1000 * response.getLong("test_wait");
testHost = response.getString("test_server_address");
testPort = response.getInt("test_server_port");
testEncryption = response.getBoolean("test_server_encryption");
serverName = response.optString("test_server_name", null);
provider = response.optString("provider", null);
testDuration = response.getInt("test_duration");
testNumThreads = response.getInt("test_numthreads");
testNumPings = response.optInt("test_numpings", 10); // pings default to 10
remoteIp = response.getString("client_remote_ip");
resultURL = new URL(response.getString("result_url"));
resultQoSURI = new URL(response.getString("result_qos_url"));
}
else
{
errorMsg = "";
for (int i = 0; i < errorList.length(); i++)
{
if (i > 0)
errorMsg += "\n";
errorMsg += errorList.getString(i);
}
}
// }
}
catch (final JSONException e)
{
errorMsg = "Error parsing server response";
e.printStackTrace();
}
catch (final MalformedURLException e)
{
errorMsg = "Error parsing server response";
e.printStackTrace();
}
else
errorMsg = "No response";
return errorMsg;
}
public String sendTestResult(TotalTestResult result, JSONObject additionalValues)
{
String errorMsg = null;
lastTestResult = null;
if (resultURL != null)
{
final JSONObject testData = new JSONObject();
try
{
testData.put("client_uuid", clientUUID);
testData.put("client_name", Config.RMBT_CLIENT_NAME);
testData.put("client_version", Config.RMBT_VERSION_NUMBER);
testData.put("client_language", Locale.getDefault().getLanguage());
testData.put("time", System.currentTimeMillis());
testData.put("test_token", testToken);
testData.put("test_port_remote", result.port_remote);
testData.put("test_bytes_download", result.bytes_download);
testData.put("test_bytes_upload", result.bytes_upload);
testData.put("test_total_bytes_download", result.totalDownBytes);
testData.put("test_total_bytes_upload", result.totalUpBytes);
testData.put("test_encryption", result.encryption);
testData.put("test_ip_local", result.ip_local.getHostAddress());
testData.put("test_ip_server", result.ip_server.getHostAddress());
testData.put("test_nsec_download", result.nsec_download);
testData.put("test_nsec_upload", result.nsec_upload);
testData.put("test_num_threads", result.num_threads);
testData.put("test_speed_download", (long) Math.floor(result.speed_download + 0.5d));
testData.put("test_speed_upload", (long) Math.floor(result.speed_upload + 0.5d));
testData.put("test_ping_shortest", result.ping_shortest);
//dz todo - add interface values
// total bytes on interface
testData.put("test_if_bytes_download", result.getTotalTrafficMeasurement(TrafficDirection.RX));
testData.put("test_if_bytes_upload", result.getTotalTrafficMeasurement(TrafficDirection.TX));
// bytes during download test
testData.put("testdl_if_bytes_download", result.getTrafficByTestPart(TestStatus.DOWN, TrafficDirection.RX));
testData.put("testdl_if_bytes_upload", result.getTrafficByTestPart(TestStatus.DOWN, TrafficDirection.TX));
// bytes during upload test
testData.put("testul_if_bytes_download", result.getTrafficByTestPart(TestStatus.UP, TrafficDirection.RX));
testData.put("testul_if_bytes_upload", result.getTrafficByTestPart(TestStatus.UP, TrafficDirection.TX));
//relative timestamps:
TestMeasurement dlMeasurement = result.getTestMeasurementByTestPart(TestStatus.DOWN);
if (dlMeasurement != null) {
testData.put("time_dl_ns", dlMeasurement.getTimeStampStart() - startTimeNs);
}
TestMeasurement ulMeasurement = result.getTestMeasurementByTestPart(TestStatus.UP);
if (ulMeasurement != null) {
testData.put("time_ul_ns", ulMeasurement.getTimeStampStart() - startTimeNs);
}
final JSONArray pingData = new JSONArray();
if (result.pings != null && !result.pings.isEmpty())
{
for (final Ping ping : result.pings)
{
final JSONObject pingItem = new JSONObject();
pingItem.put("value", ping.client);
pingItem.put("value_server", ping.server);
pingItem.put("time_ns", ping.timeNs - startTimeNs);
pingData.put(pingItem);
}
}
testData.put("pings", pingData);
JSONArray speedDetail = new JSONArray();
if (result.speedItems != null)
{
for (SpeedItem item : result.speedItems) {
speedDetail.put(item.toJSON());
}
}
testData.put("speed_detail", speedDetail);
addToJSONObject(testData, additionalValues);
// System.out.println(testData.toString(4));
}
catch (final JSONException e1)
{
errorMsg = "Error gernerating request";
e1.printStackTrace();
}
// getting JSON string from URL
final JSONObject response = JSONParser.sendJSONToUrl(resultURL, testData);
if (response != null)
try
{
final JSONArray errorList = response.getJSONArray("error");
// System.out.println(response.toString(4));
if (errorList.length() == 0)
{
lastTestResult = testData;
// System.out.println("All is fine");
}
else
{
for (int i = 0; i < errorList.length(); i++)
{
if (i > 0)
errorMsg += "\n";
errorMsg += errorList.getString(i);
}
}
// }
}
catch (final JSONException e)
{
errorMsg = "Error parsing server response";
e.printStackTrace();
}
}
else
errorMsg = "No URL to send the Data to.";
return errorMsg;
}
/**
*
* @param result
* @param qosTestResult
* @return
*/
public String sendQoSResult(final TotalTestResult result, final JSONArray qosTestResult)
{
String errorMsg = null;
System.out.println("sending qos results to " + resultQoSURI);
if (resultQoSURI != null)
{
final JSONObject testData = new JSONObject();
try
{
testData.put("client_uuid", clientUUID);
testData.put("client_name", Config.RMBT_CLIENT_NAME);
testData.put("client_version", Config.RMBT_VERSION_NUMBER);
testData.put("client_language", Locale.getDefault().getLanguage());
testData.put("time", System.currentTimeMillis());
testData.put("test_token", testToken);
testData.put("qos_result", qosTestResult);
}
catch (final JSONException e1)
{
errorMsg = "Error gernerating request";
e1.printStackTrace();
}
// getting JSON string from URL
final JSONObject response = JSONParser.sendJSONToUrl(resultQoSURI, testData);
if (response != null)
try
{
final JSONArray errorList = response.getJSONArray("error");
// System.out.println(response.toString(4));
if (errorList.length() == 0)
{
// System.out.println("All is fine");
}
else
{
for (int i = 0; i < errorList.length(); i++)
{
if (i > 0)
errorMsg += "\n";
errorMsg += errorList.getString(i);
}
}
// }
}
catch (final JSONException e)
{
errorMsg = "Error parsing server response";
e.printStackTrace();
}
}
else
errorMsg = "No URL to send the Data to.";
return errorMsg;
}
public void sendNDTResult(final String host, final String pathPrefix, final int port, final boolean encryption,
final String clientUUID, final UiServicesAdapter data, final String testUuid)
{
hostUrl = getUrl(encryption, host, pathPrefix, port, Config.RMBT_CONTROL_MAIN_URL);
this.clientUUID = clientUUID;
sendNDTResult(data, testUuid);
}
public void sendNDTResult(final UiServicesAdapter data, final String testUuid)
{
final JSONObject testData = new JSONObject();
try
{
testData.put("client_uuid", clientUUID);
testData.put("client_language", Locale.getDefault().getLanguage());
if (testUuid != null)
testData.put("test_uuid", testUuid);
else
testData.put("test_uuid", this.testUuid);
testData.put("s2cspd", data.s2cspd);
testData.put("c2sspd", data.c2sspd);
testData.put("avgrtt", data.avgrtt);
testData.put("main", data.sbMain.toString());
testData.put("stat", data.sbStat.toString());
testData.put("diag", data.sbDiag.toString());
testData.put("time_ns", data.getStartTimeNs() - startTimeNs);
testData.put("time_end_ns", data.getStopTimeNs() - startTimeNs);
JSONParser.sendJSONToUrl(hostUrl.toURI().resolve(Config.RMBT_CONTROL_NDT_RESULT_URL).toURL(), testData);
System.out.println(testData);
}
catch (final JSONException e)
{
e.printStackTrace();
}
catch (MalformedURLException e)
{
e.printStackTrace();
}
catch (URISyntaxException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void addToJSONObject(final JSONObject data, final JSONObject additionalValues) throws JSONException
{
if (additionalValues != null && additionalValues.length() > 0)
{
final JSONArray attr = additionalValues.names();
for (int i = 0; i < attr.length(); i++)
data.put(attr.getString(i), additionalValues.get(attr.getString(i)));
}
}
public String getRemoteIp()
{
return remoteIp;
}
public String getClientUUID()
{
return clientUUID;
}
public String getServerName()
{
return serverName;
}
public String getProvider()
{
return provider;
}
public long getTestTime()
{
return testTime;
}
/**
* this time stamp is only a relative timestamp (see: {@link System#nanoTime()})
* @return
*/
public long getStartTimeNs() {
return startTimeNs;
}
/**
* this is the starting (= timestamp of the test request) UNIX timestamp (see: {@link System#currentTimeMillis()})
* @return
*/
public long getStartTimeMillis() {
return startTimeMillis;
}
public String getTestId()
{
return testId;
}
public String getTestUuid()
{
return testUuid;
}
public JSONObject getLastTestResult() {
return lastTestResult;
}
public RMBTTestParameter getTestParameter(RMBTTestParameter overrideParams)
{
String host = testHost;
int port = testPort;
boolean encryption = testEncryption;
int duration = testDuration;
int numThreads = testNumThreads;
int numPings = testNumPings;
if (overrideParams != null)
{
if (overrideParams.getHost() != null && overrideParams.getPort() > 0)
{
host = overrideParams.getHost();
encryption = overrideParams.isEncryption();
port = overrideParams.getPort();
}
if (overrideParams.getDuration() > 0)
duration = overrideParams.getDuration();
if (overrideParams.getNumThreads() > 0)
numThreads = overrideParams.getNumThreads();
}
return new RMBTTestParameter(host, port, encryption, testToken, duration, numThreads, numPings, testTime);
}
public Set<ErrorStatus> getLastErrorList() {
return lastErrorList;
}
}