Parallel.Foreach do not finish stream - c#

For load testing purposes I need to simulate multiple users trying to login to a system at the same time. I have code written by another developer that can send a login request to the system. With an ok login it will also return other information in xml.
I've tried using Parallel.ForEach, but dont have any real experience with parallel programming:
Parallel.ForEach(clientList, client =>
{
RunTest(client);
});
public void RunTest(object data)
{
if (!(data is IGprsClient))
{
return;
}
_noRunningTests += 1;
IGprsClient gprsClient = data as IGprsClient;
DateTime startTime = DateTime.Now;
Log(gprsClient.Id, "Test started.");
bool result = gprsClient.StartTest(20000);
DateTime endTime = DateTime.Now;
TimeSpan diff = endTime - startTime;
if (result == false)
{
Log(gprsClient.Id, "Test failed.");
}
Log(gprsClient.Id, "Test took {0}ms. ", (int)diff.TotalMilliseconds);
_noRunningTests -= 1;
}
override public bool StartTest(int timeout)
{
_testStarted = true;
try
{
LogDebug("Trying to connect.");
_client = new TcpClient(ipAddress, port);
LogDebug("Connected.");
bool result = false;
//Todo: insert testcase into client
switch (TestCaseName)
{
case "LoginTEST":
var testCase = new LoginTEST(this);
result = testCase.Execute(user, pwd, phoneNum);
break;
default:
Log("Unknown test case: " + TestCaseName);
break;
}
_client.Close();
return result;
}
catch (Exception ex)
{
if (_client != null)
_client.Close();
Log(ex.Message);
return false;
}
}
Which in turn will send the request and read the response.
public bool Execute(string user, string pwd, string phoneNum)
{
SendDataListRequest(userId);
string requiredDataResponse = Client.ReadMsg();
return true;
}
Run test will send a request and reads the message like so:
public string ReadMsg()
{
int msgLength = -1;
var stream = _client.GetStream();
while (_testStarted)
{
int b = stream.ReadByte();
if (b == -1)
{
return "";
}
else if (b == 0x02 || msgLength == -1)
{
while (b != 0x02 && _testStarted)
{
b = stream.ReadByte(); // Finds the start token
if (b == -1)
{
return "";
}
}
msgLength = 0; // Starts collecting data
}
else if (b == 0x03)
{
byte[] encryptedMsg = Convert.FromBase64String(
Encoding.UTF8.GetString(byteBuffer, 0, msgLength));
byte[] decryptedMsg = SttCipher.DecryptMessage(encryptedMsg);
MemoryStream ms = new MemoryStream(decryptedMsg);
GZipStream gZipStream = new GZipStream(ms, CompressionMode.Decompress, true);
var bufLen = ReadAllBytesFromStream(gZipStream, decompressedBuffer);
gZipStream.Close();
string completeMsg = Encoding.UTF8.GetString(decompressedBuffer, 0, bufLen);
if (completeMsg.Length < 500)
LogDebug("Received XML-data:\n{0}", completeMsg);
else
LogDebug("Received XML-data: {0} bytes\n{1}...", completeMsg.Length, completeMsg.Substring(0, 500));
return completeMsg;
}
else
{
if (byteBuffer.Length <= msgLength)
{
throw new Exception("XML message too long!");
}
byteBuffer[msgLength] = (byte)b;
msgLength++;
}
}
return "";
}
Running one client is fine and will wait for the response. The issue is with several clients, the responses gets cut off. Leaving me with unclosed xml in the response.But I cant't figure out why. Does anyone have a reasonable explanation and/or a solution or a better way of doing it?

Related

Trying to update a ListView in a WinForm App from Task C#

I am having problems updating a ListView on C# WinForm. The application is a test harness which connects to a TCP Server and receives a data stream. The test harness will then be used to create multiple connections to the server to do load testing. Each task is started using the following command where the number of task is entered on the form:
for (int i = 0; i < noTasks; i++)
{
bool saveAudio = noTasksCheckedListBox.GetItemCheckState(i) == CheckState.Checked; // true : false;
taskArray[i] = Task.Run(() => SendMessage((initId + i).ToString(), saveAudio, audioServerIP));
}
The SendMessage function creates the TCP client connection and creates a AsyncCallBack to process the incoming stream.
void SendMessage(string id, bool saveWav, string serverIP)
{
TcpClient tcpclientAudio = new TcpClient();
string message = "GET /msg?id=" + id + "&type=0 HTTP/1.1\r\n";
NetworkObject audioObj = new NetworkObject
{
tcp = tcpclientAudio,
ConnectionType = FileType.Audio,
URL = message
};
if (saveWav)
{
tcpclientAudio.BeginConnect(IPAddress.Parse(serverIP), 8008, new AsyncCallback(CallBackConnectMethod01), audioObj);
}
else
{
tcpclientAudio.BeginConnect(IPAddress.Parse(serverIP), 8008, new AsyncCallback(CallBackConnectMethod02), audioObj);
}
}
The only difference between the CallBackConnctMethod is that 02 save the data to a file.
void CallBackConnectMethod02(IAsyncResult result)
{
NetworkObject obj = (NetworkObject)result.AsyncState;
TcpClient tcp = obj.tcp;
NetworkStream ns = tcp.GetStream();
startedProcessCount++;
int thisTask = startedProcessCount;
byte[] buffer = new byte[2048];
string message = obj.URL;
byte[] request = Encoding.ASCII.GetBytes(message);
ns.Write(request, 0, request.Length);
ns.Read(buffer, 0, 1000);
RefreshTable(thisTask, "Incoming", null);
......
}
When debugging the app goes to the RefreshTable function a disappears when it goes in to the delegate section.
private void RefreshTable(int taskNo, string status, string misc)
{
if (this.tasksListView.InvokeRequired)
{
this.Invoke((MethodInvoker) delegate {
DateTime nowDateTime = DateTime.Now;
string now = nowDateTime.Year.ToString("D4") + nowDateTime.Month.ToString("D2") + nowDateTime.Day.ToString("D2") + "-" + nowDateTime.Hour.ToString("D2") + nowDateTime.Minute.ToString("D2") + nowDateTime.Second.ToString("D2");
string taskId = "Task-" + taskNo.ToString("D3");
if (status == "Incoming")
{
ListViewItem taskLVI = tasksListView.Items.Add(taskId);
taskLVI.SubItems.Add(now);
taskLVI.SubItems.Add(" ");
taskLVI.SubItems.Add(" ");
if (string.IsNullOrEmpty(misc))
taskLVI.SubItems.Add(" ");
else
taskLVI.SubItems.Add(misc);
taskLVI.SubItems.Add(" ");
}
else
{
switch (status)
{
case "Lost":
case "Completed":
case "Exception":
ListViewItem listViewItem = null;
for (int i = 0; i < tasksListView.Items.Count; i++)
{
if (tasksListView.Items[i].SubItems[0].Text == taskId)
{
listViewItem = tasksListView.Items[i];
break;
}
}
if (listViewItem != null)
ToListViewItem(listViewItem, status, misc, now);
break;
default:
break;
}
}
tasksListView.Refresh();
});
}
}

Windows 10 UWP VpnPlugin Connection Failures

I am developing a UWP VPN Plugin. In later stage it should handle OpenVPN. In the first stage I am trying to understand the VpnPlugin to get it work in the simplest possible way. For testing I am using Android's ToyVpn test Server on a Debian VM (https://android.googlesource.com/platform/development/+/master/samples/ToyVpn/server/linux). Unfortunately the VpnPlugin is poor and lousy documented, no Guideline - no Nothing. The Github examples are useless and not working either, even https://github.com/ysc3839/UWPToyVpn gives only Rough orientation. I was able to successfully do the Handshake with the Server who responds with a Parameter chain. When it Comes to start the Connection, an exception is thrown that the device is not connected. I am running out of Options and any help would greatly appreciated.
public sealed class ToyVpnPlugin : IVpnPlugIn
{
DatagramSocket _datagramSocket;
public async void Connect(VpnChannel channel)
{
//string parameters = default;
string serverPort = "8000";
string secret = "test";
_datagramSocket = new DatagramSocket();
_datagramSocket.MessageReceived += (s, e) =>
{
DataReader dataReader = e.GetDataReader();
if (dataReader.UnconsumedBufferLength > 0 && dataReader.ReadByte() == 0)
{
var parameters = dataReader.ReadString(dataReader.UnconsumedBufferLength);
ConfigureAndConnect(channel, parameters);
}
};
var serverHostName = channel.Configuration.ServerHostNameList[0];
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.LoadXml(channel.Configuration.CustomField);
var firstChild = xmlDocument.FirstChild;
if (firstChild.Name.Equals("ToyVpnConfig"))
{
foreach (XmlNode childNode in firstChild.ChildNodes)
{
if (childNode.Name.Equals("ServerPort")) serverPort = childNode.InnerText;
else if (childNode.Name.Equals("Secret")) secret = childNode.InnerText;
}
}
await _datagramSocket.ConnectAsync(serverHostName, serverPort);
await HandShake(_datagramSocket, secret);
}
public void Disconnect(VpnChannel channel)
{
channel.Stop();
}
public void GetKeepAlivePayload(VpnChannel channel, out VpnPacketBuffer keepAlivePacket)
{
keepAlivePacket = null;
}
public void Encapsulate(VpnChannel channel, VpnPacketBufferList packets, VpnPacketBufferList encapulatedPackets)
{
while (packets.Size > 0)
{
VpnPacketBuffer vpnPacketBuffer = packets.RemoveAtBegin();
var buffer = vpnPacketBuffer.Buffer;
VpnPacketBufferStatus vpnPacketBufferStatus = vpnPacketBuffer.Status;
encapulatedPackets.Append(vpnPacketBuffer);
}
}
public void Decapsulate(VpnChannel channel, VpnPacketBuffer encapBuffer, VpnPacketBufferList decapsulatedPackets, VpnPacketBufferList controlPacketsToSend)
{
while (encapBuffer != null)
{
decapsulatedPackets.Append(encapBuffer);
}
}
async Task HandShake(DatagramSocket datagramSocket, string secret)
{
for (int i = 0; i < 3; i++)
{
var dataWriter = new DataWriter(datagramSocket.OutputStream)
{
UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8
};
dataWriter.WriteByte(0);
dataWriter.WriteString(secret);
await dataWriter.StoreAsync();
dataWriter.DetachStream();
}
}
void ConfigureAndConnect(VpnChannel vpnChannel, string parameters)
{
parameters = parameters.TrimEnd();
uint mtu = 1500;
List<HostName> ipv4InclusionHostNames = new List<HostName>();
List<HostName> dnsServerHostNames = new List<HostName>();
VpnRouteAssignment vpnRouteAssignment = new VpnRouteAssignment();
var ipv4InclusionRoutes = vpnRouteAssignment.Ipv4InclusionRoutes;
foreach (var parameter in parameters.Split(null))
{
var fields = parameter.Split(",");
try
{
switch (fields[0])
{
case "m":
mtu = uint.Parse(fields[1]);
break;
case "a":
ipv4InclusionHostNames.Add(new HostName(fields[1]));
break;
case "r":
ipv4InclusionRoutes.Add(new VpnRoute(new HostName(fields[1]), (byte)uint.Parse(fields[2])));
break;
case "d":
dnsServerHostNames.Add(new HostName(fields[1]));
break;
case "s":
//TODO "SearchDomain"
break;
default:
break;
}
}
catch (Exception)
{
throw;
}
}
VpnDomainNameAssignment vpnDomainNameAssignment = new VpnDomainNameAssignment();
vpnDomainNameAssignment.DomainNameList.Add(new VpnDomainNameInfo(".", VpnDomainNameType.Suffix, dnsServerHostNames, null));
try
{
vpnChannel.AssociateTransport(_datagramSocket, null);
vpnChannel.StartExistingTransports(ipv4InclusionHostNames, null, null, vpnRouteAssignment, vpnDomainNameAssignment, mtu, 65535, false);
}
catch (Exception e)
{
vpnChannel.TerminateConnection(e.Message);
}
}
}
This appears to be unconfirmed working, any better idea or suggestions are greatly appreciated as I figured this out by more or less "fishing"...:
namespace Background
{
public enum HandshakeState { Waiting, Received, Canceled };
public sealed class SecurepointVpnPlugin : IVpnPlugIn
{
DatagramSocket _datagramSocket;
HandshakeState _handshakeState;
public void Connect(VpnChannel channel)
{
string serverPort = "8000";
string secret = "test";
string parameters = null;
_datagramSocket = new DatagramSocket();
channel.AssociateTransport(_datagramSocket, null);
_datagramSocket.MessageReceived += (s, e) =>
{
DataReader dataReader = e.GetDataReader();
if (dataReader.UnconsumedBufferLength > 0 && dataReader.ReadByte() == 0)
{
parameters = dataReader.ReadString(dataReader.UnconsumedBufferLength);
_handshakeState = HandshakeState.Received;
}
};
var serverHostName = channel.Configuration.ServerHostNameList[0];
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.LoadXml(channel.Configuration.CustomField);
var firstChild = xmlDocument.FirstChild;
if (firstChild.Name.Equals("ToyVpnConfig"))
{
foreach (XmlNode childNode in firstChild.ChildNodes)
{
if (childNode.Name.Equals("ServerPort")) serverPort = childNode.InnerText;
else if (childNode.Name.Equals("Secret")) secret = childNode.InnerText;
}
}
_datagramSocket.ConnectAsync(serverHostName, serverPort).AsTask().GetAwaiter().GetResult();
_handshakeState = HandshakeState.Waiting;
HandShake(_datagramSocket, secret).AsTask().GetAwaiter().GetResult();
if (_handshakeState == HandshakeState.Received) ConfigureAndConnect(channel, parameters);
else channel.Stop();
}
public void Disconnect(VpnChannel channel)
{
channel.Stop();
}
public void GetKeepAlivePayload(VpnChannel channel, out VpnPacketBuffer keepAlivePacket)
{
keepAlivePacket = null;
}
public void Encapsulate(VpnChannel channel, VpnPacketBufferList packets, VpnPacketBufferList encapulatedPackets)
{
while (packets.Size > 0) encapulatedPackets.Append(packets.RemoveAtBegin());
}
public void Decapsulate(VpnChannel channel, VpnPacketBuffer encapBuffer, VpnPacketBufferList decapsulatedPackets, VpnPacketBufferList controlPacketsToSend)
{
decapsulatedPackets.Append(encapBuffer);
}
IAsyncAction HandShake(DatagramSocket datagramSocket, string secret)
{
return Task.Run(async () =>
{
for (int i = 0; i < 3; i++)
{
var dataWriter = new DataWriter(datagramSocket.OutputStream)
{
UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8
};
dataWriter.WriteByte(0);
dataWriter.WriteString(secret);
await dataWriter.StoreAsync();
dataWriter.DetachStream();
}
for (int i = 0; i < 50; i++)
{
await Task.Delay(100);
switch (_handshakeState)
{
case HandshakeState.Waiting:
break;
case HandshakeState.Received:
return;
case HandshakeState.Canceled:
throw new OperationCanceledException();
default:
break;
}
}
}).AsAsyncAction();
}
void ConfigureAndConnect(VpnChannel vpnChannel, string parameters)
{
parameters = parameters.TrimEnd();
uint mtuSize = 68;
var assignedClientIPv4list = new List<HostName>();
var dnsServerList = new List<HostName>();
VpnRouteAssignment assignedRoutes = new VpnRouteAssignment();
VpnDomainNameAssignment assignedDomainName = new VpnDomainNameAssignment();
var ipv4InclusionRoutes = assignedRoutes.Ipv4InclusionRoutes;
foreach (var parameter in parameters.Split(null))
{
var fields = parameter.Split(",");
switch (fields[0])
{
case "m":
mtuSize = uint.Parse(fields[1]);
break;
case "a":
assignedClientIPv4list.Add(new HostName(fields[1]));
break;
case "r":
ipv4InclusionRoutes.Add(new VpnRoute(new HostName(fields[1]), (byte)(int.Parse(fields[2]))));
break;
case "d":
dnsServerList.Add(new HostName(fields[1]));
break;
default:
break;
}
}
assignedRoutes.Ipv4InclusionRoutes = ipv4InclusionRoutes;
assignedDomainName.DomainNameList.Add(new VpnDomainNameInfo(".", VpnDomainNameType.Suffix, dnsServerList, null));
try
{
vpnChannel.StartExistingTransports(assignedClientIPv4list, null, null, assignedRoutes, assignedDomainName, mtuSize, mtuSize + 18, false);
}
catch (Exception e)
{
vpnChannel.TerminateConnection(e.Message);
}
}
}
}

How to detect edited or deleted messages on telegram TLSharp

I am trying to detect which message is edited or deleted on a subscribed channel on telegram with TLSharp library in c#.
1- in a while(true) loop I am getting latest updates.
2- when I delete or edit a message for test, I receive TLUpdateChannelTooLong only.
3- then I use client.GetHistoryAsync function to get channel messages, and check their EditDate.
But I don't know how much should I go deep in history and I can not find deleted message with this code easily.
Is there any solution to find deleted/edited messages easy and safe?
Part of my code:
state = await client.SendRequestAsync<TLState>(new TLRequestGetState());
while (true)
{
await Task.Delay(1000);
var req = new TLRequestGetDifference() { Date = state.Date, Pts = state.Pts, Qts = state.Qts };
TLDifference diff = null;
try
{
diff = await client.SendRequestAsync<TLAbsDifference>(req) as TLDifference;
}
catch (Exception ex)
{
HandleThisException(ex);
}
//--
if (diff != null)
{
state = await client.SendRequestAsync<TLState>(new TLRequestGetState());
foreach (var upd in diff.OtherUpdates.OfType<TLUpdateNewChannelMessage>())
{
var tm = (upd.Message as TLMessage);
if (tm == null) { continue; } // ?
var textMessage = tm.Message;
if (tm.Media != null)
{
if (tm.Media.GetType().ToString() == "TeleSharp.TL.TLMessageMediaPhoto")
{
var tLMessageMediaPhoto = (tm.Media as TLMessageMediaPhoto);
textMessage = tLMessageMediaPhoto.Caption;
}
}
try
{
var from = (tm.ToId as TLPeerChannel).ChannelId;
long replyTo = tm.ReplyToMsgId == null ? 0 : (long)tm.ReplyToMsgId;
await AnalyzeNewMessage( ... );
}
catch (Exception exParsing)
{
HandleThisException(exParsing);
}
}
// Checking Edited/Deleted Messages
foreach(var upLong in diff.OtherUpdates.OfType<TLUpdateChannelTooLong>())
{
TLChannel theChat = null;
foreach(var chat in diff.Chats.OfType<TLChannel>())
{
if(chat.Id == upLong.ChannelId) { theChat = chat; break; }
}
if (theChat != null)
{
var x = await client.GetHistoryAsync(
new TLInputPeerChannel { ChannelId = theChat.Id, AccessHash = (long)theChat.AccessHash },
0,-1,2
); // checking only 2 last messages!
var ChMsgs = x as TLChannelMessages;
foreach (var msg in ChMsgs.Messages.OfType<TLMessage>())
{
if(msg.EditDate != null)
{
var txt = msg.Message;
if (msg.Media != null)
{
if (msg.Media.GetType().ToString() == "TeleSharp.TL.TLMessageMediaPhoto")
{
txt = (msg.Media as TLMessageMediaPhoto).Caption;
}
}
await AnalyzeEditedMessage( ... );
}
}
}
}
}
}

Write to USB PORT C# using LibUsbDotNet C# USB Library

I want to write some data to a USB port and receive an answer from it.
I actually used the same
string cmdLine = "#00WD3000C82B*\r";
and sent it to the same machine with the SerialPort object and by using rs235 port.
its do well.. and I got the right answer
using these methods:
omronAX.WriteAction("3000", 200.ToString("0000"));
public void WriteAction(string DM_address, string Data)
{
write_action(DM_address, Data);
}
private void write_action(string DM_address, string Data)
{
GotData = "";
Puredata = "";
EndCode = "";
try
{
int ErCd = Write_2_port("WD", DM_address, Data);
if (ErCd != 0) { return; }
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private int Write_2_port(string cod_cmd, string Addr, string Data2write)
{
DReady = false;
out_data = "";
end_c = "";
char cr = Convert.ToChar(13);
string cmd = "", Dat1 = "", Dat2 = "";
Mess = "";
Dat2 = Data2write;
if (Addr.Trim().Length > 0)
{
try
{
Dat1 = String.Format("{0:0000}", Convert.ToInt16(Addr));
}
catch (FormatException ex)
{
Mess = ex.Message;
return 1;
}
catch (OverflowException ex1)
{
Mess = ex1.Message;
return 3;
}
}
int.TryParse(Dat2, out int hex);
string hexValue = hex.ToString("X");
cmd = "#" + BakN + cod_cmd + Dat1 + hexValue ;
string send2port = cmd + Checksm(cmd) + "*" + cr;
SentCommand = send2port;
try
{
// if (Sport.IsOpen == false) { Sport.Open(); }
locking = true;
Sport.WriteTimeout = 5000;
Sport.WriteLine(send2port);
int i = 0;
while (locking)
{
if (i++ == 500)
{
throw new TimeoutException("יתכן שיש בעיות תקשורת עם המערכת.");
}
Thread.Sleep(10);
}
// T:System.ArgumentNullException:
// The str parameter is null.
//
// T:System.InvalidOperationException:
// The specified port is not open.
//
// T:System.TimeoutException:
// The System.IO.Ports.SerialPort.WriteLine(System.String) method could not write
// to the stream.
}
catch (TimeoutException ex)
{
Mess = ex.Message;
throw ex;
}
catch (Exception ex)
{
Mess = ex.Message;
return 2;
}
return 0;
}
for the next code, I try using USB port and write to it the same line...
But I got nothing when I read the answer back and I got (bytesRead = 0)
in my bytesWritten, I got 15...
using System;
using System.Text;
using System.Text.RegularExpressions;
using LibUsbDotNet;
using LibUsbDotNet.Main;
namespace Examples
{
internal class ReadWrite
{
public static UsbDevice MyUsbDevice;
#region SET YOUR USB Vendor and Product ID!
public static UsbDeviceFinder MyUsbFinder = new UsbDeviceFinder(0x0590,0x005B);
#endregion
public static void Main(string[] args)
{
ErrorCode ec = ErrorCode.None;
try
{
// Find and open the USB device.
MyUsbDevice = UsbDevice.OpenUsbDevice(MyUsbFinder);
// If the device is open and ready
if (MyUsbDevice == null) throw new Exception("Device Not Found.");
// If this is a "whole" usb device (libusb-win32, linux libusb)
// it will have an IUsbDevice interface. If not (WinUSB) the
// variable will be null indicating this is an interface of a
// device.
IUsbDevice wholeUsbDevice = MyUsbDevice as IUsbDevice;
if (!ReferenceEquals(wholeUsbDevice, null))
{
// This is a "whole" USB device. Before it can be used,
// the desired configuration and interface must be selected.
// Select config #1
wholeUsbDevice.SetConfiguration(1);
// Claim interface #0.
wholeUsbDevice.ClaimInterface(0);
}
// open read endpoint 1.
UsbEndpointReader reader = MyUsbDevice.OpenEndpointReader(ReadEndpointID.Ep01);
// open write endpoint 1.
UsbEndpointWriter writer = MyUsbDevice.OpenEndpointWriter(WriteEndpointID.Ep01);
// Remove the exepath/startup filename text from the begining of the CommandLine.
//string cmdLine = Regex.Replace(Environment.CommandLine, "^\".+?\"^.*? |^.*? ", "", RegexOptions.Singleline);
string cmdLine = "#00WD3000A11*\r";
if (!String.IsNullOrEmpty(cmdLine))
{
int bytesWritten;
ec = writer.Write(Encoding.Default.GetBytes(cmdLine), 20000000, out bytesWritten);
if (ec != ErrorCode.None) throw new Exception(UsbDevice.LastErrorString);
byte[] readBuffer = new byte[1024];
while (ec == ErrorCode.None)
{
int bytesRead;
// If the device hasn't sent data in the last 100 milliseconds,
// a timeout error (ec = IoTimedOut) will occur.
ec = reader.Read(readBuffer, 100, out bytesRead);
if (bytesRead == 0) throw new Exception("No more bytes!");
// Write that output to the console.
Console.Write(Encoding.Default.GetString(readBuffer, 0, bytesRead));
}
Console.WriteLine("\r\nDone!\r\n");
}
else
throw new Exception("Nothing to do.");
}
catch (Exception ex)
{
Console.WriteLine();
Console.WriteLine((ec != ErrorCode.None ? ec + ":" : String.Empty) + ex.Message);
}
finally
{
if (MyUsbDevice != null)
{
if (MyUsbDevice.IsOpen)
{
// If this is a "whole" usb device (libusb-win32, linux libusb-1.0)
// it exposes an IUsbDevice interface. If not (WinUSB) the
// 'wholeUsbDevice' variable will be null indicating this is
// an interface of a device; it does not require or support
// configuration and interface selection.
IUsbDevice wholeUsbDevice = MyUsbDevice as IUsbDevice;
if (!ReferenceEquals(wholeUsbDevice, null))
{
// Release interface #0.
wholeUsbDevice.ReleaseInterface(0);
}
MyUsbDevice.Close();
}
MyUsbDevice = null;
// Free usb resources
UsbDevice.Exit();
}
// Wait for user input.
Console.ReadKey();
}
}
}
}
I have no idea and I am doing wrong, thanks.
I recommend using Usb.Net (https://github.com/MelbourneDeveloper/Device.Net) instead of LibUsb. The problem with LibUsb is that is just wraps WinUSB calls. So, you are deploying an extra C dll (LibUsb) that just points to an existing Windows C DLL. LibUsb is good if you want to keep the code cross platform with Linux, but otherwise, there's not much point.
Here is sample WinUsb code (https://github.com/MelbourneDeveloper/Device.Net/blob/master/src/Usb.Net/Windows/WindowsUsbDevice.cs)
public override Task InitializeAsync()
{
Dispose();
int errorCode;
if (string.IsNullOrEmpty(DeviceId))
{
throw new WindowsException($"{nameof(DeviceDefinition)} must be specified before {nameof(InitializeAsync)} can be called.");
}
_DeviceHandle = APICalls.CreateFile(DeviceId, (APICalls.GenericWrite | APICalls.GenericRead), APICalls.FileShareRead | APICalls.FileShareWrite, IntPtr.Zero, APICalls.OpenExisting, APICalls.FileAttributeNormal | APICalls.FileFlagOverlapped, IntPtr.Zero);
if (_DeviceHandle.IsInvalid)
{
//TODO: is error code useful here?
errorCode = Marshal.GetLastWin32Error();
if (errorCode > 0) throw new Exception($"Device handle no good. Error code: {errorCode}");
}
var isSuccess = WinUsbApiCalls.WinUsb_Initialize(_DeviceHandle, out var defaultInterfaceHandle);
HandleError(isSuccess, "Couldn't initialize device");
var bufferLength = (uint)Marshal.SizeOf(typeof(USB_DEVICE_DESCRIPTOR));
isSuccess = WinUsbApiCalls.WinUsb_GetDescriptor(defaultInterfaceHandle, WinUsbApiCalls.DEFAULT_DESCRIPTOR_TYPE, 0, 0, out _UsbDeviceDescriptor, bufferLength, out var lengthTransferred);
HandleError(isSuccess, "Couldn't get device descriptor");
byte i = 0;
//Get the first (default) interface
var defaultInterface = GetInterface(defaultInterfaceHandle);
_UsbInterfaces.Add(defaultInterface);
while (true)
{
isSuccess = WinUsbApiCalls.WinUsb_GetAssociatedInterface(defaultInterfaceHandle, i, out var interfacePointer);
if (!isSuccess)
{
errorCode = Marshal.GetLastWin32Error();
if (errorCode == APICalls.ERROR_NO_MORE_ITEMS) break;
throw new Exception($"Could not enumerate interfaces for device {DeviceId}. Error code: { errorCode}");
}
var associatedInterface = GetInterface(interfacePointer);
_UsbInterfaces.Add(associatedInterface);
i++;
}
IsInitialized = true;
RaiseConnected();
return Task.CompletedTask;
}
However, I did submit this sample to LibUsbDotNet and it's now the accepted Read/Write sample there (https://github.com/LibUsbDotNet/LibUsbDotNet/blob/master/src/Examples/Read.Write/ReadWrite.cs):
public static void Main(string[] args)
{
using (var context = new UsbContext())
{
context.SetDebugLevel(LogLevel.Info);
//Get a list of all connected devices
var usbDeviceCollection = context.List();
//Narrow down the device by vendor and pid
var selectedDevice = usbDeviceCollection.FirstOrDefault(d => d.ProductId == ProductId && d.VendorId == VendorId);
//Open the device
selectedDevice.Open();
//Get the first config number of the interface
selectedDevice.ClaimInterface(selectedDevice.Configs[0].Interfaces[0].Number);
//Open up the endpoints
var writeEndpoint = selectedDevice.OpenEndpointWriter(WriteEndpointID.Ep01);
var readEnpoint = selectedDevice.OpenEndpointReader(ReadEndpointID.Ep01);
//Create a buffer with some data in it
var buffer = new byte[64];
buffer[0] = 0x3f;
buffer[1] = 0x23;
buffer[2] = 0x23;
//Write three bytes
writeEndpoint.Write(buffer, 3000, out var bytesWritten);
var readBuffer = new byte[64];
//Read some data
readEnpoint.Read(readBuffer, 3000, out var readBytes);
}
}
I had an issue getting my device to connect with another library because I was using upper case for alphabetic characters in the VID/PID. Have you tried using lower case ("0x005b" instead of "0x005B")?

Downloading file parts using HttpWebRequest C#

I am trying to download a 100GB file using HttpWebRequest. The download will be split into parts depending on a preset part size. Below is the code I use to download the file:
private static void AddRangeHeaderHack(WebHeaderCollection headers, long start, long end)
{
// Original workaround by Eric Cadwell, code taken from
// https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=93714
Type type = headers.GetType();
System.Reflection.MethodInfo setAddVerified = type.GetMethod("SetAddVerified",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.FlattenHierarchy
);
string rangeHeaderValue = String.Format("bytes={0}-{1}", start, end);
if (setAddVerified != null)
setAddVerified.Invoke(headers, new object[] { "Range", rangeHeaderValue });
}
private ulong GetRemoteFileSize(string URI)
{
ulong size = 0;
HttpWebRequest req = null;
try
{
req = (HttpWebRequest)WebRequest.Create(URI);
using (var res = (HttpWebResponse)req.GetResponse())
{
size = (ulong)res.ContentLength;
res.Close();
}
}
catch (Exception ex)
{
}
if (req != null)
{
try
{
req.Abort();
req = null;
}
catch (Exception)
{
}
}
return size;
}
private int DownloadFromLink(string sSource, string sDestination)
{
int nRetryCount = 0;
int nMaxRetry = 5;
var lastProgress = DateTime.Now;
ulong offset = 0;
var bRetrying = false;
var bResumable = false;
var fileSize = GetRemoteFileSize(sSource);
if (fileSize > 0)
bResumable = true;
while (true)
{
HttpWebRequest webRequest = null;
try
{
try
{
bRetrying = false;
do
{
try
{
if (bDownloadAbort)
{
return -1;
}
webRequest = (HttpWebRequest)WebRequest.Create(sSource);
webRequest.Timeout = 3600000;
if (offset > 0)
{
AddRangeHeaderHack(webRequest.Headers, (long)offset, (long)fileSize);
}
// Retrieve the response from the server
using (var webResponse = (HttpWebResponse)webRequest.GetResponse())
{
var acceptRanges = String.Compare(webResponse.Headers["Accept-Ranges"], "bytes", true) == 0;
// Open the URL for download
using (var streamResponse = webResponse.GetResponseStream())
{
if (streamResponse != null)
{
// Create a new file stream where we will be saving the data (local drive)
using (var streamLocal = new FileStream(sDestination, offset>0?FileMode.Append:FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
{
// It will store the current number of bytes we retrieved from the server
int bytesSize = 0;
// A buffer for storing and writing the data retrieved from the server
byte[] downBuffer = new byte[/*16384*/ 1024 * 1024];
bool binitialtry = true;
int nRetries = 0;
if (offset > 0)
{
streamLocal.Seek((long)offset, SeekOrigin.Begin);
}
// Loop through the buffer until the buffer is empty
while ((bytesSize = streamResponse.Read(downBuffer, 0, downBuffer.Length)) > 0
|| (File.Exists(sDestination) && (offset < (ulong)fileSize) && nRetries < 5 && bResumable))
{
if (binitialtry && bytesSize == 0)
{
binitialtry = false;
}
if (!binitialtry && bytesSize == 0)
{
nRetries++;
bRetrying = nRetries<5;
break;
}
if (bDownloadAbort)
{
try { streamLocal.Close(); }
catch { }
return;
}
try
{
// Write the data from the buffer to the local hard drive
streamLocal.Write(downBuffer, 0, bytesSize);
offset += (ulong)bytesSize;
}
catch (IOException ex)
{
if (streamResponse != null)
streamResponse.Close();
if (streamLocal != null)
streamLocal.Close();
if (webRequest != null)
webRequest.Abort();
return -1;
}
Interlocked.Add(ref actualDownloaded, bytesSize);
}
// When the above code has ended, close the streams
if (streamResponse != null)
streamResponse.Close();
if (streamLocal != null)
try { streamLocal.Close(); }
catch { }
if (webRequest != null)
webRequest.Abort();
if (webRequest != null)
wcDownload.Dispose();
streamLocal.Close();
}
streamResponse.Close();
}
}
webResponse.Close();
}
if(!bRetrying)
break;
}
catch (IOException ex)
{
if (webRequest != null)
webRequest.Abort();
if (wcDownload != null)
wcDownload.Dispose();
if (nRetryCount <= nMaxRetry)
{
Thread.Sleep(10000);
nRetryCount++;
bRetrying = true;
}
else
{
break;
}
}
catch (UnauthorizedAccessException ex)
{
if (webRequest != null)
webRequest.Abort();
break;
}
catch (WebException ex)
{
if (webRequest != null)
webRequest.Abort();
if (wcDownload != null)
wcDownload.Dispose();
if (nRetryCount <= nMaxRetry)
{
Thread.Sleep(10000);
nRetryCount++;
bRetrying = true;
}
else
{
break;
}
}
finally
{
}
} while (bRetrying);
}
catch (Exception ex)
{
break;
}
}
catch
{
break;
}
if(!bRetrying)
break;
}
}
If I try to download the file in 1 part, with out adding the range header, the code runs smoothly and the file downloads normally. When I add a range header, say from 10GB to 15GB or frankly any value, the code reaches streamResponse.Read and hangs there for several minutes then it throws an exception:
Unable to read data from the transport connection: An existing
connection was forcibly closed by the remote host
When the code retries the connection after the exception, the download resumes normally and the client is able to read data from the stream.
Can someone help me determine why such thing is happening?
Just to clear the matter about the server, the file is currently hosted on an Amazon S3 server, and the download is done from a generated direct link.
It could be a server setting, according to http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.1.4
Clients that use persistent connections SHOULD limit the number of simultaneous connections that they maintain to a given server. A single-user client SHOULD NOT maintain more than 2 connections with any server or proxy. A proxy SHOULD use up to 2*N connections to another server or proxy, where N is the number of simultaneously active users. These guidelines are intended to improve HTTP response times and avoid congestion.
Try FDM, and see if it has a problem. http://www.freedownloadmanager.org/
I don’t know how to download a file in parts using HttpWebRequest, but I found this example online to build an own implementation. The article is about the HttpClient in C#. There is also complete code and project you can find in the download section of this page.
The Problem is that not all server support partial download. So NuGet packages can be used that handle the exceptions e.g.:
https://www.nuget.org/packages/downloader
or
https://www.nuget.org/packages/Shard.DonwloadLibrary.
These Libraries will handle the chunks and convert them back into a readable file or stream.
Downloader:
var downloader = new DownloadService(new()
{
ChunkCount = 8,
});
string file = #"Your_Path\fileName.zip";
string url = #"https://file-examples.com/fileName.zip";
await downloader.DownloadFileTaskAsync(url, file);
or Download Library:
string file = "Your_Path";
string url = "https://file-examples.com/fileName.zip";
var downloader = new LoadRequest(url,new()
{
Chunks = 8,
DestinationPath= file,
});
await downloader.Task;
I hope I could help!

Categories