Keep alive code fails with new RDP client - c#

For our Secure Terminal Server project, we have a need to keep the RDP session open, that is, to prevent the remote computer from timing out and locking the session. A little background:
We have several virtual servers configured as go-between agents, with a client piece that launches a RDP session to the virtual servers, and starts an application there. That application reads connection data from a database, including the username and password for connecting on to the final destination computer.
For remote desktop sessions, we use the ActiveX control extracted from MSTSCAX.DLL (using AxImp). Because the user does not have access to the password for the remote machine, we absolutely must keep the session from timing out.
For the past several months, we have been using the following code, triggered by a Timer object, to accomplish this. That worked great, until I had to upgrade the RDP client to version 6 in order to access Server 2008 boxes (we were using version 4 or 5, not sure which). Since then, the call to SendKeys will sometimes throw an HRESULT E_FAIL error -- often enough to cause major problems.
Does anyone have an idea as to what may be causing this? Better yet, does anyone have a better way to accomplish this that may work with the newer RDP client?
Thanks,
Dave
_mstscKeyControl = (IMsRdpClientNonScriptable)_mstsc.GetOcx();
private void KeepAlive()
{
try
{
if ( null != _mstsc && 0 != _mstsc.Connected )
{
bool[] bKeyUp = new bool[ 20 ];
int[] KeyData = new int[ 20 ]; // value matches lParam parameter of WM_DOWN message
/*
* Send CAPS LOCK on followed by OFF
*
* The SendKeys routine will not allow remote data in a single call to be mixed with
* local data so this shouldn't mess up anything.
*/
KeyData[ 0 ] = (int)MapVirtualKey( 14, 0 ); // vk_capital = CAPS LOCK
bKeyUp[ 0 ] = false;
KeyData[ 1 ] = KeyData[ 0 ];
bKeyUp[ 1 ] = true;
_mstscKeyControl.SendKeys( 2, ref bKeyUp[ 0 ], ref KeyData[ 0 ] );
}
}
catch ( Exception ex )
{
MessageBox.Show( ex.Message + Environment.NewLine + ex.StackTrace );
}
}

Instead of a sendkeys, is there a way to pass some kind of mousemove instead? I suspect this would be less invasive, if you only move the mouse a few pixels. I'm not sure if RDP has some kind of mouse movement threshold, though - maybe a few pixels isn't enough for it to reset the disconnect/lock timeout.
We'll eventually have this same problem (our terminal server is currently 2003, but we'll upgrade to 2008 at some point), so I'd really be interested to know what your solution ends up being.

I have the same need to keep RDP 6 alive from the client side. Came here via google, tried sendkey and mousemove, didn't work. Turn out WM_ACTIVATE do the trick.
Here's my basic AutoHotkey script segment:
SetTimer, RemoteMachine_Tick, 60000
RemoteMachine_Tick:
IfWinNotActive, remote01 - Remote Desktop
SendMessage, 0x006, 1, 0, , remote01 - Remote Desktop;
WM_ACTIVATE(0x006) WA_ACTIVE(1)
return

Have you tried managing Group Policies to configure Terminal Services and keep the session active?

Related

Biometrics device ping becoming failed after sometime

I have ZKTeco Biometrics device which is connected with a C# windows application using This tutorial (C# ZKTeco Biometric Device Getting Started).
It is working fine but after sometime, my application becoming failed to ping the device. As below code suggested, I am trying to ping the device after every 25 seconds.
private void TimerCheckPingAndCloseAttendanceForm() {
timerCheckPingAndCloseAttendanceForm = new Timer();
timerCheckPingAndCloseAttendanceForm.Tick += new EventHandler(CheckPingAndCloseAttendanceForm);
timerCheckPingAndCloseAttendanceForm.Interval = 25000;//25 seconds.
timerCheckPingAndCloseAttendanceForm.Start();
}
private void CheckPingAndCloseAttendanceForm(object sender, EventArgs e) {
string ipAddress = tbxDeviceIP.Text.Trim();
if (UniversalStatic.PingTheDevice(ipAddress) == false) {
//CloseAttendaceListForm();
IsDeviceConnected = false;
string infoString = "Application started on " + applicationStartDateTime.ToString() + " and ping failed on " + DateTime.Now.ToString() + " then, app closed while device ip is "+ ipAddress;
File.AppendAllText("ConnectionLog.txt", infoString + Environment.NewLine);
Application.Exit();
//timerCheckPingAndCloseAttendanceForm.Tick -= new EventHandler(CheckPingAndCloseAttendanceForm);
}
}
And when I am trying to ping the command from cmd the device show destination host is unreachable. But whenever I restart the device, the ping working fine. I don't know where is the problem? Either the network problem or its coding issue?
Note: I am doing a ping on regular time interval, because on Disconnected Event is not working. I am assuming ping failed meaning is the device has disconnected with the application.
First of all : Thank you for going through my article
You are doing it the wrong way.
Trying to ping the device after every 25 seconds is unnecessary.
The only job of the UniversalStatic.PingTheDevice method is to check if the device is presumably active, the first time you connect with the device.
If you want to check the status of the device i.e IsDeviceConnected, All you need to do is register to the device OnDisConnected event provided by the SDK.
It seems the code here at line number 57 has already done the OnDisConnected event registration for you.
All you need to do now is set your IsDeviceConnected to false when the objCZKEM_OnDisConnected method in the ZkemClient.cs class is called upon by the device itself.
Sample snippet :
In the ZkemClient.cs class file, between line number 81-84
void objCZKEM_OnDisConnected()
{
IsDeviceConnected = false; // <-- Add this line
}
Now, Every time you try to make a call to the device, All you need to do is check for the value of your IsDeviceConnected.
Not having the actual code and the hardware setup, this answer is a bit of a shot in the dark, but here goes …
Since it works initially, this is not a hardware configuration or network configuration issue. Yet it says that after a while the destination (reader) becomes unavailable. This is probably not a network keepalive issue because you are pinging every 25 sec. Looking at the code that you referenced, it shows opening a connection and hooking up callbacks, and making a call to a hardware feature.
My guess would be maybe you are opening the connection each ping and not closing the connection, then after a number of attempts the hardware jams because there are too many open connections. Just a guess. If this is the problem then to fix it, either close the connection or, better, keep the connection open and re-use it.
Alternative possibility would be that the router(s) between your code and the device are detecting too many pings and blocking the connection as a possible DOS attack. If this is the problem then to fix it, configure the router to allow the traffic.
This sounds like the device misbehaving. The error "destination host is unreachable" corresponds to an ICMP packet, same type of packet as ping but different job, being sent by your router saying "I have no idea which device has that IP". This normally happens when the device stop responding to ARP, which basically asks "who has this IP?" and expects a machine to respond "I have it" with its MAC address. The router constantly refreshes its ARP table, forgetting old values.
So when you boot the device it is 'happy', responding to ARP and responding to pings; however, something happens and it at least stops responding to ARP (probably something more wrong with it). Depending on its architecture it could be loaded down doing other stuff and unable to respond, or it could just be locked up.
Try slowing down other actions to the device (if your polling it for information other than ping, do it slower) and also see if you can get status from the device via another output (does it have a uart?).
OPTION 1
Since that restarting the device fixes your problem for a period of time, check that the IP that you are using is not in use on another device/computer/element_of_the_network.
ZKTeco devices come with the IP 192.168.1.201 configured by default. Configure a different static IP and avoid using DHCP (it´s well known that using DHCP in ZKTeco devices isn´t a good choice since they don´t refresh automatically the IP after rebooting the system or any network change).
Make sure that the IP is not in use and that nobody else will use it.
OPTION 2
Another thing that It may be the cause of your problem, is that you are using zkemkeeper in a different part of your application (or into a different application) and you are not closing the oppened connections properly... That may be blocking all network activity from the device. To close the connection just make sure that you call this sdk method after performing all the necessary actions:
sdk.Disconnect();
It looks like a code issue. While investigating UniversalStatic.PingTheDevice(ipAddress), its found that its calling System.Net.NetworkInformation.Ping.Send setting DontFragment = true. Reference: https://github.com/zaagan/BioMetrix/blob/master/BioMetrixCore/Utilities/UniversalStatic.cs#LC51. The timeout for the ping is set to 120 milli seconds. This tries to send 32 bytes of data to the given IP.
Following is the snippet taken from https://learn.microsoft.com/en-us/dotnet/api/system.net.networkinformation.ping.send?view=netframework-4.7.2 would answer the root-cause of your issue
If the DontFragment property is true and the total packet size exceeds the maximum packet size that can be transmitted by one of the routing nodes between the local and remote computers, the ICMP echo request fails. When this happens, the Status is set to PacketTooBig.
So when you restart your device, possibly, the data travelling on the network gets lost. Hence it started working till the packets reaching its limit.
Few suggestions:
Try calling System.Net.NetworkInformation.Ping.Dispose in PingTheDevice before returns
Increase the timeout from 120 milliseconds to seconds.
Increase the timerCheckPingAndCloseAttendanceForm.Interval to 1 min.
Check the return code of the System.Net.NetworkInformation.Ping.Send and find the associated failure meaning
Please share your findings if the above suggestions do not help you finding the root-cause.
you try this code for ping the device,
try
{
IPAddress ipAddress = IPAddress.Parse(ipAdd);
Ping pingSender = new Ping();
PingOptions options = new PingOptions();
options.DontFragment = true;
// Create a buffer of 32 bytes of data to be transmitted.
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
int timeout = 120;
PingReply reply = pingSender.Send(ipAddress, timeout, buffer, options);
if (reply.Status == IPStatus.Success)
return true;
else
{
return false;
}
}
catch (Exception)
{
return false;
}
Thanks.

Windows process launch fails silently - can't launch Bluetooth settings in certain scenario

Even though there are command-line commands to start (most of?) the various Control Panel screens in Windows 10, a specific scenario seems to fail:
If the machine starts with Bluetooth turned off (not disabled), running the command which should open the Bluetooth settings screen, simply does nothing. The command could be either ms-settings:bluetooth, bthprops.cpl or ms-settings:Bluetooth.
I've also tried to directly launch the Bluetooth Devices screen (using the command %windir%\explorer.exe shell:::{28803F59-3A75-4058-995F-4EE5503B023C} as described here), but clicking on the "Bluetooth settings" in this window does nothing as well.
The only way to get directly to the Bluetooth settings screen without going through the main Control Panel window and without turning on Bluetooth first, is by right clicking on the relevant tile in Windows Action Center:
Although this seems like a bug on the operating system level, I was wondering if there's any way to know when the launch fails from within C# code. So I've tried using the following code:
try
{
var process = new Process();
process.StartInfo.FileName = "control";
process.StartInfo.Arguments = "bthprops.cpl";
process.Exited += (s, e) =>
{
if (process.ExitCode != 0)
{
TurnOnBt();
}
};
var res = process.Start();
if (!res)
{
TurnOnBt();
}
}
catch (System.Exception ex)
{
int test = 6; // just for breakpoint
}
Problem is, no exception was ever thrown, and most of the time the Process.Exit event was never called.
Further more, calling Windows.Devices.Radios.Radio.GetRadiosAsync() returns an empty list!
Currently the only solution I've found is to manually turn on Bluetooth - it wouldn't change the Process.Start/Exit behavior, but it does allow to successfully lunch the command to directly open Bluetooth Settings window, and to get the list of the machine's Bluetooth/Radio devices. Still, when turning off Bluetooth and restarting the machine, same problem would happen all over again.
Any ideas for a code-based workaround?
note - all this based only on my debugging research, nothing from this is documented
i look how BT-settings window is open via Action Center (win8.1, win 10):
the IApplicationActivationManager interface created and called ActivateApplication method with:
appUserModelId = L"windows.immersivecontrolpanel_cw5n1h2txyewy!microsoft.windows.immersivecontrolpanel"
arguments = L"page=SettingsPagePCSystemBluetooth"
code on c++ can be look like:
if (0 <= CoInitialize(0))
{
IApplicationActivationManager* pAppAct;
if (0 <= CoCreateInstance(__uuidof(ApplicationActivationManager), 0, CLSCTX_ALL, IID_PPV_ARGS(&pAppAct)))
{
ULONG dwProcessId;
pAppAct->ActivateApplication(
L"windows.immersivecontrolpanel_cw5n1h2txyewy!microsoft.windows.immersivecontrolpanel",
L"page=SettingsPagePCSystemBluetooth",
AO_NONE ,
&dwProcessId);
pAppAct->Release();
}
CoUninitialize();
}
the processId (if all ok) reference to "X:\Windows\ImmersiveControlPanel\SystemSettings.exe" -ServerName:microsoft.windows.immersivecontrolpanel
for c# - look IApplicationActivationManager::ActivateApplication in C#?
the "windows.immersivecontrolpanel_cw5n1h2txyewy!microsoft.windows.immersivecontrolpanel" and "page=SettingsPagePCSystemBluetooth" strings not documented anywhere and I not sure are it is "persist" - but currently it used to open manage Bluetooth page in system settings. as is.
in case we run control.exe bthprops.cpl - the process ( control.exe ) launched without any error - as result you and not got any errors when you call this code.
then control.exe bthprops.cpl exec new process rundll32.exe Shell32.dll,Control_RunDLL bthprops.cpl, and exit
the rundll32.dll call Control_RunDLLW(HWND_DESKTOP, (HINSTANCE)&__ImageBase, L"bthprops.cpl", SW_SHOWDEFAULT);
we can and direct call void WINAPI Control_RunDLLW(HWND hwndParent, HINSTANCE hInst, PCWSTR cplName, int nCmdShow ); this api exported from shell32.dll
internally Control_RunDLLW load "bthprops.cpl" (3-rd argument - cplName), find CPlApplet entry point, and send CPL_INIT message. the bthprops.cpl on this message check are bthserv is running via OpenService(L"BTHSERV", ) + QueryServiceStatus (in function BthpIsbluetoothServiceRunning) and if "BTHSERV" not running - it return zero (fail code)

Creating a push or background service that checks remote server

General idea of what I need:
I am porting an Android app to iOS (Using Xamarin, but I can translate to C# from objective C easily enough) that relies heavily on the AlarmManager to do background checks on an HTML page on a website that I don't own. AlarmManager is essentially a task scheduler for Android. The user would set the frequency to whatever they desired.
What I've tried:
Background fetching:
app.SetMinimumBackgroundFetchInterval(240);
UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert, (approved, err) =>
{
// Handle approval
});
UNUserNotificationCenter.Current.Delegate = new WEBSITEFUNCTIONS.UserNotificationCenterDelegate();
return base.FinishedLaunching(app, options);
public override void PerformFetch(UIApplication application, Action<UIBackgroundFetchResult> completionHandler)
{
System.Diagnostics.Debug.WriteLine("interval");
WEBSITEFUNCTIONS kf = new WEBSITEFUNCTIONS();
kf.doCheck();
completionHandler(UIBackgroundFetchResult.NewData);
}
Perform Fetch is just straight up NEVER called. I need some consistency (being one minute off is no big deal... but several hours will not do). I let it run and it just straight up never worked. I've read lots on how PerformFetch works, and I don't think it'll give me the critical response time that the user needs.
UserNotifications:
New to iOS 10, is the ability to have repeating notifications. However this repeats the same notification.
var trigger = UNTimeIntervalNotificationTrigger.CreateTrigger(60, true);
var requestID = "sampleRequest";
var request = UNNotificationRequest.FromIdentifier(requestID, content, trigger);
UNUserNotificationCenter.Current.AddNotificationRequest(request, (err) =>
{
if (err != null)
{
// Do something with error...
}
});
Push Alerts:
My own server
I could setup a server that does the checking and then sends a message to the Firebase Cloud Messaging to send a message to the user about the new items. I have approximately 500 active users on the Android version, if they check 5 different pages every 5 minutes, at 90 kbs a check, that's about half a gig of bandwidth an hour.
So the cons are:
Excessive bandwidth usage will make my home internet
a lot slower
I will need to secure it myself
Power outages can sometimes last for days, leaving end users out of the loop
Their server could boot off my machine at any given
moment, I could get a new IP address from my ISP if that happened... assuming they allow that
Using my shared hosting, setup a cronjob every 15 minutes
I can setup a cronjob to do an alert every 15 minutes. It's not the fastest, but way better than relying on the first option (as it just straight up never gets called)
Once again, I'm at the mercy that their server doesn't kick me off. The app completely breaks if they do this.
Shared hosting might cut me off for putting too much strain on their servers (Hostgator claims unlimited bandwidth, I'm not sure if they'd like me doing that)

Randomly strange behaviour when using select() with timeout on Windows

I'm using a tool to communicate with a gameserver. To establish the connection with the gameserver I'm sending a login packet and then go on from there. I also used a tool, that does the same, but which is written by someone else in C# with a pre-made library. This app has some issues with stackoverflow exceptions after using it for hours and porting it linux isn't much fun aswell, therefore I decided to write my own application from scratch in C++.
My script pretty much looks like this:
while (!connected) {
if (connectCounter == 0)
std::cout << "Trying to connect..." << std::flush;
else
std::cout << "." << std::flush; // add point
connectCounter++;
int selectSize = 0;
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
fd_set fds;
FD_ZERO(&fds);
FD_SET(mysocket, &fds);
selectSize = select(mysocket + 1, &fds, 0, 0, &timeout);
if (selectSize == 1) {
// we might now be logged in, check routines
connected = true;
}
}
Now there's a "bug" randomly happening to me in both applications, the one written by someone else in C# and in my own one. I should probably mention that I've never had this behaviour before, but sinced I formatted my computer I saw this issue happpening for the first time.
Issue: Gameserver was offline for some hours, computer was probably freshly booted. Gameserver is still down and I start the application. Now it tries to login but won't have success as the gameserver is still offline. Now it writes "Trying to connect". Because of the timeout settings it should wait 5 seconds and then add 1 point after every unsuccessful try. Instead it fires point after point without waiting for the timeout. This happens in both application, the C# app written by someone else and in my own application. In both applications it only happens randomly and not every time I'm starting the application. As I mentioned I've never experienced this issues before formatting my computer. I also ported this application to my linux server and didn't not experience that behaviour on linux. A friend of mine also uses both applications and never reported that kind of issue to me.
This is so strange to me and I can't figure out the reason for it. From what I get this can't really be code related because it happens in two totally different applications and from what I can tell only since I reinstalled Windows.
EDIT 1: Now I found something interesting, I added the following code on windows and linux:
selectSize = select(mysocket + 1, &fds, 0, 0, &timeout);
std::cout << selectSize << std::cout;
Interesting thing is that on Windows my console will now output: Trying to connect...0.1.0.1.0.1.0.1
Restarted the application and it outputs Trying to connect...0.0.0.0.0.1
On linux it always returns Trying to connect...0.0.0.0.0, never ever with a false positive.
Still only happening on windows. Don't even know what approach the guy from the C# application used but there it's the same problem happening randomly after reinstalling windows.
EDIT 2: I guess I found the problem.
Before the timeout settings and select() I'm doing a sendto() with my login packet. I guess for whatever reason there is something incoming in return, so that selectSize might change to 1 in some cases. Is it possible that this is causing the issue on Windows, while its working on linux?
Quoting from "the" POSIX specification (a copy of it online):
A descriptor shall be considered ready for reading when a call to an input function with O_NONBLOCK clear would not block, whether or not the function would transfer data successfully. (The function might return data, an end-of-file indication, or an error other than one indicating that it is blocked, and in each of these cases the descriptor shall be considered ready for reading.)
So I'd say in order to fix your code you must additionally check whether file descriptors that are "ready for reading" don't have any error or eof indication.
To check if the socket is connected, you should check it for writability, not readability. Change
selectSize = select(mysocket + 1, &fds, 0, 0, &timeout);
to
selectSize = select(mysocket + 1, 0, &fds, 0, &timeout);
Okay, so it seems that I finally found at least a partial answer to my initial question, why linux gives me a working result while windows breaks my application. From what I have read on windows platforms select() returns WSAECONNECTRESET instead of blocking or timeout, see: WinSock Recvfrom() now returns WSAECONNRESET instead of blocking or timing out
So this seems to be the reason why the application is working perfectly fine (for my purposes) on linux, where select() still seems to return a timeout while Windows returns that error and breaks my application to a certain extent.
Solution:
So I finally found a fix. Special thanks to the guy who reminded me to use Wireshark. At first I tought the select() giving back 1 when it should be 0 after sending the login packet to gameserver while it's offline is totally random but in fact I found out that from time to time I get a "ICMP port unreachable", this caused select() to return 1 instead of 0 (see the link above) Obviously I only want select() to return 1 when an actual login reponse is coming from the sever. On linux this works out of the box and doesn't cause any problems.
For Windows I found a simple fix by adding this code before the select() function:
#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR, 12)
DWORD lpcbBytesReturned = 0;
BOOL lpvInBuffer = FALSE;
WSAIoctl(mysocket, SIO_UDP_CONNRESET, &lpvInBuffer, sizeof(lpvInBuffer), NULL, 0, &lpcbBytesReturned, NULL, NULL);

After using the InternetConnect() API in wininet how can I tell if I'm still connected?

I use the InternetConnect() method from the WinINet APIs. I connect to my FTP server just fine with no issues. After I connect, I wait about 1 min and the server disconnects me because of no activity as expected. I then try to send a file but I'm not connected.
Is there a way to "check" the FTP connection to see if I'm still connected? Or is there some type of way for me to attach an event to tell me when I get disconnected?
I haven't used wininet for FTP, and I use the classes, not the global functions directly. But I suspect that CFtpConnection behaves the same way as CHttpConnection in this respect. Anyway, you might learn something from what I have discovered about the latter.
CHttpConnection seems to be a high and abstract level of connection. When I started out I expected its member functions to throw exceptions once the server closed the underlying socket (for timeout). I now know better or at least believe otherwise. NORMAL closing of the socket does NOT cause exceptions to be thrown at this high level of classy wininet. You might suspect as much from inspecting the wininet error codes: There is no code corresponding to the server having closed the connection.
I experimented with this and found: The server closing the socket (for timeout) is considered normal and does not cause an exception to be thrown. You can go ahead and use CHttpConnection without worrying about this. It will simply reconnect if needed without alerting you. So once you have called GetHttpConnection and got your CHttpConnection object, it will normally last forever!
The exceptions that might be thrown, ERROR_INTERNET_CONNECTION_ABORTED and ERROR_INTERNET_CONNECTION_RESET, are caused by abnormal conditions, f.ex. a proxy server crashing or somebody accidentally pulling the power plug to your modem. The server closing the socket for timeout is considered NORMAL and is transparent to the user of wininet classes.
So the tentative conclusion is that you don't have to worry about the connection being closed by the server. If that happens, CHttpConnection will reconnect backstage and you won't be bothered. You can pretend that the connection always stays open - it seems so to the user of wininet classes.
Consider the following experiment. A connection is opened and then a request is sent once a minute. The function returns once an exception is thrown. But if not, then it loops forever. I tried it on two different web sites: An exception is NEVER thrown! Despite a whole minute of inactivity between requests.
int httpclient::test(string host)
{
int flags = INTERNET_FLAG_RELOAD;
int port = INTERNET_DEFAULT_HTTP_PORT;
CHttpConnection *connection = session.GetHttpConnection(host.cstring(),flags,port);
int secs = 0;
while (true)
{
CHttpFile *fil;
try
{
fil = connection->OpenRequest(CHttpConnection::HTTP_VERB_HEAD, "index.htm",
0,1,0, "HTTP/1.1", flags);
}
catch (CInternetException *exc)
{
connection->Close();
int feil = exc->m_dwError;
exc->Delete();
return -feil;
}
fil->AddRequestHeaders("Connection: Keep-Alive");
try
{
fil->SendRequest();
}
catch (CInternetException *exc)
{
connection->Close();
int feil = exc->m_dwError;
exc->Delete();
return feil;
}
fil->Close();
Sleep(60 * 1000);
secs += 60;
printf("%u seconds passed\n", secs);
}
return 0;
}
Take all this with a grain of salt. wininet is poorly documented and all I know is what experiments have taught me.

Categories

Resources