App freezes on connection loss, no debugging tools available - c#

I have a bit of a problem as I have developed a C# Xamarin app for Android, which is a client, and in parallel, a server in another language. They interact with each other via TCP/IP sockets.
The Android app is, broadly speaking a geo localized app. Now, because of the nature of mobile network, I have implemented a way to detect if there is a connection to the server, and if not, automatically reconnect. When an operation on a socket fails, the app is directly put in offline mode.
During this time, everything is supposed to work: the main activity is a map that follows the user.
If I make the server crash, it indeed works as expected: it tries to reconnect every time once in a while and during this time the map is "updated" (the angle changes depending on bearing, etc), a "no connection" button appears, and when the server is back online, it reconnects.
But when I have no more network or set my phone in plane mode, it freezes.
There is no exception. I've put breakpoints everywhere, to no effect. I have no idea what is going on at all.
On top of that, it seems that the Android system itself is freezing and I have no real idea, to be honest, how android does the things my app asks it to perform, and what would cause this freeze. I mostly need to either reboot my phone or wait very long times. The bearings aren't updated, the map doesn't move like it does when the server crashes.
I have tried making my socket timeout. I've tried to use other properties of the socket to determine if it's disconnected in this way. I've put try catch blocks around every use of the socket, forcing the disconnection whenever an operation fails.
It's not really possible to show entire activities as I have multiple thousands of lines on this project. I can however show how I determine connection status, and how I connect/reconnect my socket.
How I check connection status:
public bool checkConnectionStatus()
{
bool part1 = true;
try
{
part1 = sock.Poll(1000, SelectMode.SelectRead);
}
catch
{
connected = false;
return false;
}
bool part2 = (sock.Available == 0);
if (part1 && part2)
{
connected = false;
return false;
}
else
{
connected = true;
return true;
}
}
What is called to start the socket for the first time, but also whenever it's disconnected and I want it to reconnect:
public void socketStartup()
{
socketStartupLocked = true;
ip = IPAddress.Parse(ipstring);
ipe = new IPEndPoint(ip, port);
try
{
sock = new Socket(AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, ProtocolType.Tcp)
{
};
}
catch
{
connected = false;
socketStartupLocked = false;
return;
}
try
{
sock.Connect(ipe);
connected = true;
}
catch
{
connected = false;
socketStartupLocked = false;
return;
}
socketStartupLocked = false;
}
I expect my app to behave when there's no network exactly as it does when the server is down.

You should probably only check the server/socket connection after checking your device network connectivity.
For reference on how to do it:
https://github.com/xamarin/docs-archive/tree/master/Recipes/android/networking/detect-network-connection
And remember to add the following permission to your manifest:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Related

Connecting .Net Service to IBM WebSphere `MQRC_CONNECTION_BROKEN` error

We have a .NET framework 4.5.2 service running that connects to a WebSphere MQ Server (v7.5.0.9). Our service needs to connect to a Queue and put a message. It doesn’t need to receive anything after putting the message. We have this set up in a Test and Production environment. We've had this running for a while without any issues. Now we are facing an error only in the Production environments. The same code works fine in the Test environment. But Production is showing very inconstant results and we are unable to recreate the issue anywhere else.
The only way we are currently able to get it working is by restarting the .NET service multiple times until the service is able to connect to all Queue Managers. Every time we restart the service we get a different result. We may start the service and it would not be able to connect to any of the Queue Managers and then we restart again and 2 of the Queue Managers are able to connect. Once the connection has been made it is stable, the service will be able to put messages in any of the Queues without it ever disconnecting.
Some of the things we have tried
Before this issue, we were using the SYSTEM.DEF.SVRCONN channel to connect to the Queue Managers but we have changed that to use a "Server Connection" channel we have created in each Queue Manager. We can see the new channels are in an Active state but only if it is able to make the initial connection.
Originally we were connecting to a Queue Manager, putting a message, and closing the Queue but we were leaving the Queue Manager open. We have tried to Close and Disconnect the Queue Managers after every message but that seemed to make things worse.
The .Net service and Websphere are on the same box but we have tried disabling the windows firewall on the server in case there was something blocking it. That didn’t seem to make a difference either.
My background is in .NET so I'm not very familiar with the WebSphere UI and even less with the CLI. Any ideas on places to look or commands to run to get any insight on what is going on would be helpful.
The only error we get in WebSphere is "CompCode: 2, Reason: 2009" but in the service we are catching the exception, it says "Error Message: MQRC_CONNECTION_BROKEN"
Below is the code used to connect and send a message. We are using the amqmdnet.dll
try
{
properties = new Hashtable();
properties.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED);
properties.Add(MQC.HOST_NAME_PROPERTY, hostName);
properties.Add(MQC.PORT_PROPERTY, port);
properties.Add(MQC.CHANNEL_PROPERTY, channelName);
if (!QueueManagers.ContainsKey(queueManagerName))
{
queueManager = new MQQueueManager(queueManagerName, properties);
QueueManagers[queueManagerName] = queueManager;
}
else
{
queueManager = QueueManagers[queueManagerName];
if (!queueManager.IsConnected)
{
queueManager = new MQQueueManager(queueManagerName, properties);
QueueManagers[queueManagerName] = queueManager;
}
}
queue = queueManager.AccessQueue(queueName, MQC.MQOO_OUTPUT + MQC.MQOO_FAIL_IF_QUIESCING);
message = new MQMessage();
message.ClearMessage();
message.Format = MQC.MQFMT_STRING;
message.Encoding = MQC.MQENC_NATIVE;
message.CorrelationId = MQC.MQCI_NONE;
message.CharacterSet = MQC.MQCCSI_Q_MGR;
message.WriteString(messageString);
queue.Put(message);
}
catch (Exception ex)
{
sentToMQServer = false;
QueueManagers.TryRemove(queueManagerName, out var mgr);
queueManager?.Close();
queueManager?.Disconnect();
if (retry)
SendToMQServer(remoteClient, Message, false);
}
finally
{
message = null;
//QueueManagers.TryRemove(queueManagerName, out var mgr);
if (properties != null)
{
properties.Clear();
properties = null;
}
if (queue != null)
{
queue.Close();
queue = null;
}
//queueManager.Close();
//queueManager.Disconnect();
}

Determine broken connection in TCP server

I wrote a tcp server, each time a client connection accepted, the socket instance returned by Accept or EndAccept which is called handler and many other information gathered in object called TcpClientConnection, I need to determine whether a connection is connected or not at some specific interval times, the Socket.Connected property is not reliable and according to the documentation i should use the Poll method with SelectRead option to do it.
with a test scenario i unplug the client cable, and wait for broken alarm which is built upon the handler.Poll(1, SelectMode.SelectRead), it should return true but never it happened.
This is a fundamentally caused by the way the TCP and IP protocols work. The only way to detect if a connection is disconnected is to send some data over the connection. The underlying TCP protocol will cause acknowledgements to be sent from the receiver back to the sender thereby allowing a broken connection to be detected.
These articles provide some more information
Do I need to heartbeat to keep a TCP connection open?
http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html
According to the documentation of Socket.Poll:
This method cannot detect certain kinds of connection problems, such as a broken network cable, or that the remote host was shut down ungracefully. You must attempt to send or receive data to detect these kinds of errors.
In another words - Poll is useful for checking if some data arrived and are available to your local OS networking stack.
If you'd need to detect the connection issues you need to call blocking read (e.g. Socket.Receive)
You can also build a simple initialization miniprotocol to exchange some agreed 'hello' back and forth message.
Here is a simplified example how you can do it:
private bool VerifyConnection(Socket socket)
{
byte[] b = new byte[1];
try
{
if (socket.Receive(b, 0, 1, SocketFlags.None) == 0)
throw new SocketException(System.Convert.ToInt32(SocketError.ConnectionReset));
socket.NoDelay = true;
socket.Send(new byte[1] { SocketHelper.HelloByte });
socket.NoDelay = false;
}
catch (Exception e)
{
this._logger.LogException(LogLevel.Fatal, e, "Attempt to connect (from: [{0}]), but encountered error during reading initialization message", socket.RemoteEndPoint);
socket.TryCloseSocket(this._logger);
return false;
}
if (b[0] != SocketHelper.HelloByte)
{
this._logger.Log(LogLevel.Fatal,
"Attempt to connect (from: [{0}]), but incorrect initialization byte sent: [{1}], Ignoring the attempt",
socket.RemoteEndPoint, b[0]);
socket.TryCloseSocket(this._logger);
return false;
}
return true;
}

How to prevent Client from crashing while the server is not running?

I'm new to c# and trying to set up a server client connection for some test purpose.
Currently I have this snippet letting my client app crashing when it trys to connect while the server isn't running. It seems to me the crash is happening in the client.Connect line, letting me no chance to prevent this, as it didn't return form the method when the crash happens.
Also looking on MSDN didn't give me some usefull info.
so would I have to make some preperation?
because just checking a return value isn't possible as the crash happens inside the method.
Or is there a way I had to check before for I run the connect mehtod for connectability?
Int32 port = 4999;
Byte[] teststring;
GameConfiguration objGameConfClient = new GameConfiguration();
TcpClient client = new TcpClient();
client.Connect("XXX.XXX.XXX.XXX", port);
if (client == null)
{
return;
}
http://msdn.microsoft.com/de-de/library/system.net.sockets.tcpclient%28v=vs.110%29.aspx
The MSDN example apears to me also not handling this crash, is it?
try
{
client.Connect("XXX.XXX.XXX.XXX", port);
}
catch(Exception e)
{
//XXX
}

TCPClient & Sockets failing to connect to the Server

I have a very strange problem with my connection to a server on a TCPListener/TCPClient basis. At some point during testing I am unable to connect to my server-application anymore, every try it times out. Netstats on both sides show, that my application listens on the right port, and the client is trying to connect to the right ip and port, but it does not advance further than "SYN_SENT". The server just displays "LISTENING" all the time. All I can do is restart my PC, which temporarily fixes this problem. But after some connections, it starts all over again.
Up to now I tested TCPClient and Sockets class to connect to the server but both show this behaviour, what is not surprising, as TCPClient is a wrapper around the Sockets Class afaik.
Firewall is checked on both sides, things like Remote Desktop work perfectly fine, and is not blocking the Connection of my Application. There are no connections left to close or something, already cheked everything I know (maybe not that much ;) )
So whats the problem?
Edit:
A Method that needs to connect to my Server:
public int GetSomeDataFromServer(string blargh)
{
int ret;
try
{
using(ConnectionTCPStream ctp = new ConnectionTCPStream())
{
if(ctp.EstSecConnWithServ())
{
ret = CKSHandler(ctp, blargh);
}
else
{ ret = (int)ErrFlags.ServerDeniedConnection; }
}
return ret;
}
catch(Exception)
{
InternalError = ErrFlags.ServerUnreachable;
return (int)ErrFlags.ServerUnreachable;
}
}
The Constructor of my Class that is dealing with the Connections:
public ConnectionTCPStream()
{
Client = new TcpClient("VeryImportantAdress", 49778); //it fails right here!
rsaCrypt = new RSACH() { RSAForeignPubKey = "An 8192-Bit long RSA Public key." };
AESPASS = AESThenHMAC.CreatePassword(200);
}
Sounds like you are using up all your connections or some other resource.
What do you see when you do a netstat -an ? Do you see a bunch of open ports?
There an Article Here that could possibly help you here
Some other resource may be killing you, might be worth having an SA fire up a resource monitor to check the health of the host when you run into this situation.
If there's no errors being thrown, it makes your life that much harder. The problem typically happens when you don't cleanly clean up your socket disconnects.
The answer is the firewall which changed its mind every now and then. I couldn't test that before because i had no access to it. Now i have changed settings while i had this blockade and it worked fine again. So the answer is: Always have access to the firewall and don't forget to check it.

Determining if .NET socket is currently connected bug?

I'm trying to find out whether a Socket is currently connected - according to the MSDN docs for Socket.Connected - I should do the following:
// This is how you can determine whether a socket is still connected.
bool blockingState = client.Blocking;
try
{
byte [] tmp = new byte[1];
client.Blocking = false;
client.Send(tmp, 0, 0);
Console.WriteLine("Connected!");
}
catch (SocketException e)
{
// 10035 == WSAEWOULDBLOCK
if (e.NativeErrorCode.Equals(10035))
Console.WriteLine("Still Connected, but the Send would block");
else
{
Console.WriteLine("Disconnected: error code {0}!", e.NativeErrorCode);
}
}
finally
{
client.Blocking = blockingState;
}
Console.WriteLine("Connected: {0}", client.Connected);
I've tested this works by connecting the socket to a remote server running on Windows and killing the remote server and it works fine.
However, if I do the same with a remote Server running on Unix (in this case MAC OS X) then the code does not work - the client.Send(tmp, 0, 0) call completes without throwing an exception and prints "Connected: true".
I'm guessing this has something to do with the fact that the other side of the connection has closed so the send may still work but a receive would fail - can I do a zero-byte Receive or something to see if the socket is closed?
Yes, you can.
Calling Send only really checks if the local socket is open. Calling Receive will check the other end too.
Maybe you can sniff with Wireshark the traffic and see if there are any difference if the dying server side is a windows or unix system.
Maybe the dying windows system is able to send a tcp close while the unix system can't. That would explain the difference (but maybe not help your actual problem).
btw, if you would use a udp connection you could never determine if the other site is living, due to the fact this would be a send & forget communication.

Categories