Android - checking if data connection is actually working - android

I am currently having a one special use case that I am quite confused how to solve.
We have been checking for internet connection with ConnectivityService that has those ConnectivityType.Wifi / ConnectivityType.Mobile with a property if it is connected / connecting. That is all good until you run into following case:
You have data enabled on your phone.
Data connection is connected.
However you don't pay for your data bill so you can't make any data transfers.
(make sure your wifi is turned off while trying this)
I thought that I would simply check as following:
private static bool CanReachServer()
{
var uri = new Uri(Platform.ApiServerUrl); // replace with https://www.google.com if you like
try
{
using (HttpClient httpClient = new HttpClient())
{
httpClient.Timeout = TimeSpan.FromMilliseconds(5000);
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, uri);
var task = httpClient.SendAsync(httpRequestMessage);
task.Wait();
if (task.Result.IsSuccessStatusCode)
return true;
else
return false;
}
}
catch (Exception ex)
{
Util.Log(string.Format("{0} - {1}", ex.Message, ex.StackTrace));
return false;
}
}
But this comes with a result of a successful status 200 - which makes me really confused as I clearly can't access anything data oriented on my phone.

I suggest you to check connection by attempting to open a socket to a known host - if the connection is successful - you can be sure that you have network access, else you can check the Exception and handle it to show error connection.
public bool ActiveInternetConnectivity() {
try {
// connect to google on port 80, the HTTP port
var socket = new Java.Net.Socket("www.google.com", 80);
// the above would have thrown exception if failed, so we are good
socket.Close();
return true;
} catch (Exception ex) {
// check logcat to see why it failed, you could then catch and handle each exception independently ( time out, host unknown, end of stream, etc.. )
System.Diagnostics.Debug.WriteLine(ex);
// the connection has failed, return false
return false;
}
It's just an idea, codes are not fully tested.

Ended up implementing following solution that seem to be working quite reliably. You can also enforce reachability on the method.
public static NetworkState GetNetworkState(this Context context, bool testReachability = false)
{
var result = NetworkState.NoNetwork;
var connMgr = (ConnectivityManager)context.GetSystemService(Context.ConnectivityService);
var activeNetwork = connMgr.ActiveNetworkInfo;
if (activeNetwork == null || !activeNetwork.IsConnectedOrConnecting)
{
connMgr.Dispose();
return NetworkState.NoNetwork;
}
if (activeNetwork.Type == ConnectivityType.Wifi && activeNetwork.IsConnected)
{
if (testReachability)
{
if (CanReachServer())
result = NetworkState.WiFi;
}
else
{
result = NetworkState.WiFi;
}
}
else if (activeNetwork.Type == ConnectivityType.Mobile && activeNetwork.IsConnected)
{
if (testReachability)
{
if (CanReachServer())
result = NetworkState.Mobile;
}
else
{
result = NetworkState.Mobile;
}
}
activeNetwork.Dispose();
connMgr.Dispose();
return result;
}
private static bool CanReachServer()
{
var uri = new Uri(Platform.ApiServerUrl).GetLeftPart(UriPartial.Authority);
var task = Task.Factory.StartNew(() =>
{
try
{
using (URL url = new URL(uri))
{
using (HttpURLConnection urlc = (HttpURLConnection)url.OpenConnection())
{
urlc.SetRequestProperty("User-Agent", "Android Application");
urlc.SetRequestProperty("Connection", "close");
urlc.ConnectTimeout = 6000;
urlc.ReadTimeout = 10000;
urlc.Connect();
bool result = urlc.ResponseCode == HttpStatus.Ok;
urlc.Disconnect();
return result;
}
}
}
catch (Exception ex)
{
Util.Log(string.Format("{0} - {1}", ex.Message, ex.StackTrace));
return false;
}
});
task.Wait();
return task.Result;
}
}

Related

Xamarin Form Android Bluetooth Service discovery failed

I have an app written in Xamarin Form that connects to a Bluetooth device (not LE).
The code for Bluetooth is written in a DepencedyService.
Some users (minus of 0.1 % ) have said that they get this message : "OS/Service discovery failed"
The function that displays the message is:
public bool OpenSocket(string xxxDevice)
{
bool rVal = false;
try
{
device = (from bd in adapter.BondedDevices
where bd.Address == xxxDevice
select bd).FirstOrDefault();
if (device == null)
return false;
_socket = device.CreateRfcommSocketToServiceRecord(UUID.FromString("00001101-0000-1000-8000-00805f9b34fb"));
_socket.Connect();
rVal = true;
}
catch (System.Exception ex)
{
MessagingCenter.Send<BTCode, string>(this, "Bluetooth", "OS/" + ex.Message);
}
return rVal;
}
Can anyone tell me how to fix this?

GCDAsyncSocket : android host can't get data written by iOS client

I am developing an iOs app which required to send and received message from Android Host app.
Android host app create Wifi Hotpot programatically, iOS device will join it from setting.
First, I tried with Apple's NSOutputStream class to write to host. But no luck.
Now, I am running ConnectionTest example of GCDAsyncSocket. But android host can't read data written by iOS client.
CODE TO ESTABLISH CONNECTION
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
dispatch_queue_t mainQueue = dispatch_get_main_queue();
asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:mainQueue];
NSString *host = HOST;
uint16_t port = PORT;
DDLogInfo(#"Connecting to \"%#\" on port %hu...", host, port);
self.viewController.label.text = #"Connecting...";
NSError *error = nil;
if (![asyncSocket connectToHost:host onPort:port error:&error])
{
DDLogError(#"Error connecting: %#", error);
self.viewController.label.text = #"Oops";
}
// Add the view controller's view to the window and display.
[self.window addSubview:self.viewController.view];
[self.window makeKeyAndVisible];
return YES;
}
CODE TO WRITE DATA WHEN CONNECTION IS ESTABLISHED
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
DDLogInfo(#"socket:%p didConnectToHost:%# port:%hu", sock, host, port);
self.viewController.label.text = #"Connected";
NSString *requestStr = #"girsh:";
NSMutableData *requestData = [[NSMutableData alloc] initWithData:[requestStr dataUsingEncoding:NSUTF8StringEncoding]];
[requestData appendData:[GCDAsyncSocket CRLFData]];
[sock writeData:requestData withTimeout:1 tag:1];
}
***** ANDROID CODE ********
private void startHotspot() {
//////////////////
if (wifiManager.isWifiEnabled()) {
wifiManager.setWifiEnabled(false);
}
Method[] wmMethods = wifiManager.getClass().getDeclaredMethods();
boolean methodFound = false;
for (Method method : wmMethods) {
if (method.getName().equals("setWifiApEnabled")) {
methodFound = true;
Calendar calendar = Calendar.getInstance();
WifiConfiguration netConfig = new WifiConfiguration();
netConfig.SSID = "AISTT" + "What_Next" + calendar.get(Calendar.MINUTE) + "." + calendar.get(Calendar.SECOND);
netConfig.preSharedKey = "DataAnywhere";//getString(R.string.password); //// Password
netConfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
netConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
try {
boolean apstatus = (Boolean) method.invoke(wifiManager, netConfig, true);
for (Method isWifiApEnabledmethod : wmMethods) {
if (isWifiApEnabledmethod.getName().equals("isWifiApEnabled")) {
while (!(Boolean) isWifiApEnabledmethod.invoke(wifiManager)) {
}
for (Method method1 : wmMethods) {
if (method1.getName().equals("getWifiApState")) {
int apstate;
apstate = (Integer) method1.invoke(wifiManager);
Log.i(this.getClass().toString(), "Apstate ::: " + apstate);
}
}
}
}
if (apstatus) {
Log.d("Splash Activity", "Access Point created");
} else {
Log.d("Splash Activity", "Access Point creation failed");
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
if (!methodFound) {
Log.d("Splash Activity",
"cannot configure an access point");
}
///////////////////
}
I've seen a couple of mistakes in your code.
First part is this:
dispatch_queue_t mainQueue = dispatch_get_main_queue();
asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:mainQueue];
You are running the connection in the main queue, which is not a good way. Because in some way, you might block the main thread. Or other operations going in the main thread will block you.
What I will do is, I will put the connection in a thread other than the main.
_asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
Second part is this:
[sock writeData:requestData withTimeout:1 tag:1];
You just set the timeout to 1. That's too short, at least set it to 30, or just set it to -1(What I would normally do), for no timeout. Because there might be a case that the write was not successful then the connection will not rewrite the data again because the timeout is reached.
You can also check if the write is successful or not through this callback:
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
If everything is OK in your iOS part. Then I suggest you check the coding on Android part.

Trying to verify person specific url then bring up login screen in Android

I'm trying to make an application where the person connects to their specific website and can then access the data from it. The first page asks them to put in the url. I then parse this and need to verify the url's existence so I can move them to the login screen. How do I go about doing this? I'm trying HttpURLConnections but I'm not having much luck. Thoughts?
Try the below code :
try {
int status = 0;
try {
HttpURLConnection httpConnection = (HttpURLConnection) new URL(
"http://www.google.com").openConnection();
httpConnection.setRequestMethod("HEAD");
Log.e("StatusCode",httpConnection.getResponseCode());
if ((httpConnection.getResponseCode() == 200)||(httpConnection.getResponseCode() == 302)) {
status = 1;
}
} catch (Exception ex) {}
if (status == 1) {
Log.e("WebSite","Found");
} else {
Log.e("WebSite","NotFound");
}
} catch (Exception ex1) {
Log.e("Error",ex1.getMessage().toString());
}

Android VpnService to capture packets won't capture packets

I been searching for my answer for a couple of hours now and I can't figure it out. Please help.
What I want to do is to use the VpnService in Android to grab network packets like the application tPacketCapture
I started by using the ToyVpn sample code from google and modifying it so I don't send the data to a server. However, I'm not sure if this is correct.
My configure method uses the wlan ip address for binder.addAddress() before calling establish(). I am using a nexus 7 and I used "adb shell netcfg | grep wlan0" to get the address:
wlan0 UP 192.168.0.6/24 0x00001043 10:bf:48:bf:5f:9d
And add it in my method:
private void configure() throws Exception {
// If the old interface has exactly the same parameters, use it!
if (mInterface != null) {
Log.i(TAG, "Using the previous interface");
return;
}
// Configure a builder while parsing the parameters.
Builder builder = new Builder();
builder.setMtu(1500);
builder.addAddress("192.168.0.6", 24);
try {
mInterface.close();
} catch (Exception e) {
// ignore
}
mInterface = builder.establish();
}
After calling this, I call the run method which I modified to pass a String instead of a InetSocketAddress and this is not important because I am not using it anywhere:
private void run(String run) throws Exception {
configure();
FileInputStream in = new FileInputStream(mInterface.getFileDescriptor());
// Allocate the buffer for a single packet.
ByteBuffer packet = ByteBuffer.allocate(32767);
// We use a timer to determine the status of the tunnel. It
// works on both sides. A positive value means sending, and
// any other means receiving. We start with receiving.
int timer = 0;
// We keep forwarding packets till something goes wrong.
while (true) {
// Assume that we did not make any progress in this iteration.
boolean idle = true;
// Read the outgoing packet from the input stream.
int length = in.read(packet.array());
if (length > 0) {
Log.i(TAG,"************new packet");
while (packet.hasRemaining()) {
Log.i(TAG,""+packet.get());
//System.out.print((char) packet.get());
}
// Write the outgoing packet to the tunnel.
packet.limit(length);
// tunnel.write(packet);
packet.clear();
// There might be more outgoing packets.
idle = false;
// If we were receiving, switch to sending.
if (timer < 1) {
timer = 1;
}
}
}
}
When I do adb logcat, nothing is happening. Am I going about this correctly? I feel like I am missing something.
Thank you!
EDIT:
From the logs I see the following lines:
I/ActivityManager( 460): START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.example.android.toyvpn/.ToyVpnClient} from pid 10247
I/ActivityManager( 460): Start proc com.example.android.toyvpn for activity com.example.android.toyvpn/.ToyVpnClient: pid=10287 uid=10122 gids={50122, 3003, 1028}
I/ActivityManager( 460): Displayed com.example.android.toyvpn/.ToyVpnClient: +1s144ms
I/Vpn ( 460): Switched from [Legacy VPN] to com.example.android.toyvpn
D/Vpn ( 460): setting state=IDLE, reason=prepare
I/ToyVpnService(10287): running vpnService
D/Vpn ( 460): setting state=CONNECTING, reason=establish
D/VpnJni ( 460): Address added on tun0: 192.168.0.6/24
I/Vpn ( 460): Established by com.example.android.toyvpn.ToyVpnService on tun0
W/ContextImpl( 460): Calling a method in the system process without a qualified user: android.app.ContextImpl.bindService:1406 com.android.server.connectivity.Vpn.establish:289 com.android.server.ConnectivityService.establishVpn:3263 android.net.IConnectivityManager$Stub.onTransact:504 android.os.Binder.execTransact:351
D/Vpn ( 460): setting state=AUTHENTICATING, reason=establish
So it seems to be connecting.
Full source:
public class ToyVpnService extends VpnService implements Handler.Callback, Runnable {
private static final String TAG = "ToyVpnService";
private Handler mHandler;
private Thread mThread;
private ParcelFileDescriptor mInterface;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// The handler is only used to show messages.
if (mHandler == null) {
mHandler = new Handler(this);
}
// Stop the previous session by interrupting the thread.
if (mThread != null) {
mThread.interrupt();
}
// Start a new session by creating a new thread.
mThread = new Thread(this, "ToyVpnThread");
mThread.start();
return START_STICKY;
}
#Override
public void onDestroy() {
if (mThread != null) {
mThread.interrupt();
}
}
#Override
public boolean handleMessage(Message message) {
if (message != null) {
Toast.makeText(this, message.what, Toast.LENGTH_SHORT).show();
}
return true;
}
#Override
public synchronized void run() {
Log.i(TAG,"running vpnService");
try {
runVpnConnection();
} catch (Exception e) {
e.printStackTrace();
//Log.e(TAG, "Got " + e.toString());
} finally {
try {
mInterface.close();
} catch (Exception e) {
// ignore
}
mInterface = null;
mHandler.sendEmptyMessage(R.string.disconnected);
Log.i(TAG, "Exiting");
}
}
private boolean runVpnConnection() throws Exception {
configure();
FileInputStream in = new FileInputStream(mInterface.getFileDescriptor());
// Allocate the buffer for a single packet.
ByteBuffer packet = ByteBuffer.allocate(32767);
// We keep forwarding packets till something goes wrong.
while (true) {
// Assume that we did not make any progress in this iteration.
boolean idle = true;
// Read the outgoing packet from the input stream.
int length = in.read(packet.array());
if (length > 0) {
Log.i(TAG,"************new packet");
System.exit(-1);
while (packet.hasRemaining()) {
Log.i(TAG,""+packet.get());
//System.out.print((char) packet.get());
}
packet.limit(length);
// tunnel.write(packet);
packet.clear();
// There might be more outgoing packets.
idle = false;
}
Thread.sleep(50);
}
}
public String getLocalIpAddress()
{
try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
InetAddress inetAddress = enumIpAddr.nextElement();
Log.i(TAG,"****** INET ADDRESS ******");
Log.i(TAG,"address: "+inetAddress.getHostAddress());
Log.i(TAG,"hostname: "+inetAddress.getHostName());
Log.i(TAG,"address.toString(): "+inetAddress.getHostAddress().toString());
if (!inetAddress.isLoopbackAddress()) {
//IPAddresses.setText(inetAddress.getHostAddress().toString());
Log.i(TAG,"IS NOT LOOPBACK ADDRESS: "+inetAddress.getHostAddress().toString());
return inetAddress.getHostAddress().toString();
} else{
Log.i(TAG,"It is a loopback address");
}
}
}
} catch (SocketException ex) {
String LOG_TAG = null;
Log.e(LOG_TAG, ex.toString());
}
return null;
}
private void configure() throws Exception {
// If the old interface has exactly the same parameters, use it!
if (mInterface != null) {
Log.i(TAG, "Using the previous interface");
return;
}
// Configure a builder while parsing the parameters.
Builder builder = new Builder();
builder.setMtu(1500);
builder.addAddress("192.168.0.6", 24);
try {
mInterface.close();
} catch (Exception e) {
// ignore
}
mInterface = builder.establish();
}
}
Ok, it was not easy at all but I figured out how to capture packets. Since I am not extremely familiar with networking (but this new job is requesting that I am) I had difficulty with setting everything correctly. Basically after setting the right route in the VpnService.builder I got to receiving packets correctly.
So:
builder.addAddress("192.168.0.6", 24); // was wrong, you need to put an internal IP (10.0.2.0 for example)
and
builder.addRoute("0.0.0.0", 0); // needs to be this.
you don't need to set up a DnsServer through builder.addDnsServer() to make it work. Hope this helps anyone!
My configure method uses the wlan ip address for binder.addAddress() before >calling establish(). I am using a nexus 7 and I used "adb shell netcfg | grep >wlan0" to get the address:
wlan0 UP 192.168.0.6/24 0x00001043 10:bf:48:bf:5f:9d
I have wrote a simple script in python to show you netcfg graphically from adb.
It is updating every second.
https://github.com/ilanben/graphical_netcfg
Enjoy :)

Getting WiFi proxy settings in Android

I am trying to read WIFI proxy settings
Proxy host
Proxy port
Proxy user (authentication)
Proxy password (authentication)
from devices in android versions 2.X.X – 4.X.X without any success.
Calling:
String proxy = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.HTTP_PROXY);
Always returns null.
I've also added to my android manifest:
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
still it returns null.
Also tried:
android.net.Proxy. getHost(Context ctx) – which is deprecated – returns the IP
android.net.Proxy. getPortt(Context ctx) – which is deprecated – returns always -1.
Java calls:
System.getProperty("http.proxyHost");
System.getProperty("http.proxyCall");
Also returns null.
Is there a working code which retrieves all these settings or at least partially from devices in all android versions?
I found this project: Android Proxy Library
Which provides backward compatible ways of querying Proxy settings as well as setting them for WebViews on older versions of Android.
// Grab Proxy settings in a backwards compatible manner
ProxyConfiguration proxyConfig = ProxySettings.getCurrentHttpProxyConfiguration( context );
// Set Proxy for WebViews on older versions of Android
ProxyUtils.setWebViewProxy( getActivity().getApplicationContext() );
However, there is something you need to understand about Proxy Settings set on a WiFi AP. Since WiFi specific Proxy Settings were not implemented in Android proper until 3.1, all pre-3.1 devices that expose that functionality are using some sort of custom hack. They don't work in any sort of standard way. So libraries like this won't be able to grab any proxy set from one of those hacks.
There is however a System Wide Proxy in pre-3.1 that this sort of library WILL grab. Of course Android saw fit not to provide any official way to modify this setting. But there are apps on the Play Store that will allow you to do it, this is the one I'm using: Proxy Settings and it works well, setting the System Proxy and allowing you to grab it either via this library, or even simpler methods like querying the JVM proxy settings.
I ended up not using the APL and instead went with a much simpler implementation:
private static final boolean IS_ICS_OR_LATER = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
...
String proxyAddress;
int proxyPort;
if( IS_ICS_OR_LATER )
{
proxyAddress = System.getProperty( "http.proxyHost" );
String portStr = System.getProperty( "http.proxyPort" );
proxyPort = Integer.parseInt( ( portStr != null ? portStr : "-1" ) );
}
else
{
proxyAddress = android.net.Proxy.getHost( context );
proxyPort = android.net.Proxy.getPort( context );
}
This is what I'm using:
public static String[] getUserProxy(Context context)
{
Method method = null;
try
{
method = ConnectivityManager.class.getMethod("getProxy");
}
catch (NoSuchMethodException e)
{
// Normal situation for pre-ICS devices
return null;
}
catch (Exception e)
{
return null;
}
try
{
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Object pp = method.invoke(connectivityManager);
if (pp == null)
return null;
return getUserProxy(pp);
}
catch (Exception e)
{
return null;
}
}
private static String[] getUserProxy(Object pp) throws Exception
{
String[] userProxy = new String[3];
String className = "android.net.ProxyProperties";
Class<?> c = Class.forName(className);
Method method;
method = c.getMethod("getHost");
userProxy[0] = (String) method.invoke(pp);
method = c.getMethod("getPort");
userProxy[1] = String.valueOf((Integer) method.invoke(pp));
method = c.getMethod("getExclusionList");
userProxy[2] = (String) method.invoke(pp);
if (userProxy[0] != null)
return userProxy;
else
return null;
}
Following is code snippet to retrieve proxy details
public static String getProxyDetails(Context context) {
String proxyAddress = new String();
try {
if (IsPreIcs()) {
proxyAddress = android.net.Proxy.getHost(context);
if (proxyAddress == null || proxyAddress.equals("")) {
return proxyAddress;
}
proxyAddress += ":" + android.net.Proxy.getPort(context);
} else {
proxyAddress = System.getProperty("http.proxyHost");
proxyAddress += ":" + System.getProperty("http.proxyPort");
}
} catch (Exception ex) {
//ignore
}
return proxyAddress;
}
It'll return enmpty if some exception or no proxy detected;
private fun getUserProxy(context: Context): Data {
return try {
val declaredField = WifiConfiguration::class.java.getDeclaredField("mIpConfiguration")
declaredField.isAccessible = true
val data =
(context.applicationContext.getSystemService(Context.WIFI_SERVICE) as? WifiManager)
?.configuredNetworks
?.asSequence()
?.mapNotNull {
try {
declaredField.get(it)
} catch (e: Exception) {
e.printStackTrace()
null
}
}
?.mapNotNull {
try {
(it.javaClass.getDeclaredField("httpProxy").get(it) as? ProxyInfo)
} catch (e: Exception) {
e.printStackTrace()
null
}
}
?.find { !it.host.isNullOrEmpty() }
?.let { Data(it.host ?: "", it.port.toString()) }
?: Data()
declaredField.isAccessible = false
return data
} catch (e: Exception) {
e.printStackTrace()
Data()
}
}
data class Data(
val host: String = "",
val port: String = ""
)

Categories

Resources