I'm trying to respond to SNMP GET requests from SnmpB with SNMP4j 2.3.1 (running on Windows).
In "Discover" mode, SnmpB queries by broadcasting 255.255.255.255 (checked with Wireshark) and I receive a GET request with standard OID (sysDescr, sysUpTime, sysContact, sysName and sysLocation). It finds my instance with the information I coded ("My System", "Myself", ...) (note that it also works when I enter the IP address under the "IP networks" textboxes, though I don't see any traffic on Wireshark but I receive the GET request):
I did write a very simple MIB file that I imported into SnmpB. It defines a single Integer32 data that I want to retrieve using an SNMP GET request from SnmpB.
However, using the same code than for the standard sys* OID, SnmpB doesn't seem to receive that data ("Timeout" in red on the top-right):
I did try Wireshark to check network activity and I don't see anything, so I guess it takes place on localhost (which is not accessible with Wireshark on Windows)? But the traces below show it does not (peerAddress=192.168.56.1)...
Here is the MIB file (code follows):
MY-TEST-MIB DEFINITIONS ::= BEGIN
IMPORTS
enterprises, MODULE-IDENTITY, OBJECT-TYPE, Integer32
FROM SNMPv2-SMI;
myTest MODULE-IDENTITY
LAST-UPDATED "201412301216Z"
ORGANIZATION "My org"
CONTACT-INFO "Matthieu Labas"
DESCRIPTION "MIB Test"
REVISION "201412301216Z"
DESCRIPTION "Generated"
::= { enterprises 12121 }
myData OBJECT-TYPE
SYNTAX Integer32
MAX-ACCESS read-only
STATUS current
DESCRIPTION "My data for test"
::= { myTest 1 }
END
... and the code:
public class RespondGET implements CommandResponder {
public static final OID sysDescr = new OID("1.3.6.1.2.1.1.1.0");
public static final OID sysUpTime = new OID("1.3.6.1.2.1.1.3.0");
public static final OID sysContact = new OID("1.3.6.1.2.1.1.4.0");
public static final OID sysName = new OID("1.3.6.1.2.1.1.5.0");
public static final OID sysLocation = new OID("1.3.6.1.2.1.1.6.0");
public static final OID myData = new OID("1.3.6.1.4.1.12121.1.0");
private Snmp snmp;
public RespondGET() throws IOException {
MessageDispatcher dispatcher = new MessageDispatcherImpl();
dispatcher.addMessageProcessingModel(new MPv2c()); // v2c only
snmp = new Snmp(dispatcher, new DefaultUdpTransportMapping(new UdpAddress("192.168.56.1/161"), true));
snmp.addCommandResponder(this);
snmp.listen();
}
#Override
public void processPdu(CommandResponderEvent event) {
System.out.println("Received PDU "+event);
PDU pdu = event.getPDU();
switch (pdu.getType()) {
case PDU.GET:
List<VariableBinding> responses = new ArrayList<VariableBinding>(pdu.size());
for (VariableBinding v : pdu.getVariableBindings()) {
OID oid = v.getOid();
// Answer the usual SNMP requests
if (sysDescr.equals(oid)) {
responses.add(new VariableBinding(oid, new OctetString("My System description")));
} else if (sysUpTime.equals(oid)) {
responses.add(new VariableBinding(oid, new TimeTicks(ManagementFactory.getRuntimeMXBean().getUptime())));
} else if (sysContact.equals(oid)) {
responses.add(new VariableBinding(oid, new OctetString("Myself")));
} else if (sysName.equals(oid)) {
responses.add(new VariableBinding(oid, new OctetString("My System")));
} else if (sysLocation.equals(oid)) {
responses.add(new VariableBinding(oid, new OctetString("In here")));
} else if (myData.equals(oid)) { // MyData handled here
responses.add(new VariableBinding(oid, new Integer32(18)));
}
}
try {
CommunityTarget comm = new CommunityTarget(event.getPeerAddress(), new OctetString(event.getSecurityName()));
comm.setSecurityLevel(event.getSecurityLevel());
comm.setSecurityModel(event.getSecurityModel());
PDU resp = new PDU(PDU.RESPONSE, responses);
System.out.println(String.format("Sending response PDU to %s/%s: %s", event.getPeerAddress(), new String(event.getSecurityName()), resp));
snmp.send(resp, comm);
} catch (IOException e) {
System.err.println(String.format("Unable to send response PDU! (%s)", e.getMessage()));
}
event.setProcessed(true);
break;
default:
System.err.println(String.format("Unhandled PDU type %s.", PDU.getTypeString(pdu.getType())));
break;
}
}
public static void main(String[] args) throws IOException {
RespondGET rg = new RespondGET();
System.out.println("Listening...");
int n = 300; // 5 min
while (true) {
try { Thread.sleep(1000); } catch (InterruptedException e) { }
if (--n <= 0) break;
}
System.out.println("Stopping...");
rg.snmp.close();
}
}
It produces the following output when I click "discover" under SnmpB and right-click on myData in the MIB Tree and "Get" (slightly reformatted for readability):
Listening...
Received PDU CommandResponderEvent[securityModel=2, securityLevel=1, maxSizeResponsePDU=65535,
pduHandle=PduHandle[16736], stateReference=StateReference[msgID=0,pduHandle=PduHandle[16736],
securityEngineID=null,securityModel=null,securityName=public,securityLevel=1,
contextEngineID=null,contextName=null,retryMsgIDs=null], pdu=GET[requestID=16736, errorStatus=Success(0), errorIndex=0,
VBS[1.3.6.1.2.1.1.1.0 = Null; 1.3.6.1.2.1.1.3.0 = Null; 1.3.6.1.2.1.1.4.0 = Null; 1.3.6.1.2.1.1.5.0 = Null; 1.3.6.1.2.1.1.6.0 = Null]],
messageProcessingModel=1, securityName=public, processed=false, peerAddress=192.168.56.1/49561, transportMapping=org.snmp4j.transport.DefaultUdpTransportMapping#120d62b, tmStateReference=null]
Sending response PDU to 192.168.56.1/49561/public: RESPONSE[requestID=0, errorStatus=Success(0), errorIndex=0,
VBS[1.3.6.1.2.1.1.1.0 = My System description; 1.3.6.1.2.1.1.3.0 = 0:01:03.18; 1.3.6.1.2.1.1.4.0 = Myself; 1.3.6.1.2.1.1.5.0 = My System; 1.3.6.1.2.1.1.6.0 = In here]]
Received PDU CommandResponderEvent[securityModel=2, securityLevel=1, maxSizeResponsePDU=65535,
pduHandle=PduHandle[1047], stateReference=StateReference[msgID=0,pduHandle=PduHandle[1047],
securityEngineID=null,securityModel=null,securityName=public,securityLevel=1,
contextEngineID=null,contextName=null,retryMsgIDs=null], pdu=GET[requestID=1047, errorStatus=Success(0), errorIndex=0,
VBS[1.3.6.1.4.1.12121.1.0 = Null]], messageProcessingModel=1, securityName=public, processed=false, peerAddress=192.168.56.1/49560, transportMapping=org.snmp4j.transport.DefaultUdpTransportMapping#120d62b, tmStateReference=null]
Sending response PDU to 192.168.56.1/49560/public: RESPONSE[requestID=0, errorStatus=Success(0), errorIndex=0, VBS[1.3.6.1.4.1.12121.1.0 = 18]]
Stopping...
What am I missing here? Could that "just" be a network routing issue?
After setting up a VM and checking with Wireshark, it turned out I forgot to set, on the response PDU, the same request ID than the GET PDU.
It was solved by adding resp.setRequestID(pdu.getRequestID()); when building the response PDU
CommunityTarget comm = new CommunityTarget(event.getPeerAddress(), new OctetString(event.getSecurityName()));
comm.setSecurityLevel(event.getSecurityLevel());
comm.setSecurityModel(event.getSecurityModel());
PDU resp = new PDU(PDU.RESPONSE, responses);
resp.setRequestID(pdu.getRequestID()); // Forgot that!
snmp.send(resp, comm);
Thanks to #Jolta for his patience during New Year holiday and his insisting on using Wireshark for further checking. :)
Related
I try to run basic example of usage PUSH query using ksqldb java client:
public class Main {
public static String KSQLDB_SERVER_HOST = "localhost";
public static int KSQLDB_SERVER_HOST_PORT = 8088;
public static void main(String[] args) throws ExecutionException, InterruptedException {
ClientOptions options = ClientOptions.create()
.setHost(KSQLDB_SERVER_HOST)
.setPort(KSQLDB_SERVER_HOST_PORT);
Client client = Client.create(options);
client.streamQuery("SELECT * FROM users EMIT CHANGES;")
.thenAccept(streamedQueryResult -> {
System.out.println("Query has started. Query ID: " + streamedQueryResult.queryID());
RowSubscriber subscriber = new RowSubscriber();
streamedQueryResult.subscribe(subscriber);
}).exceptionally(e -> {
System.out.println("Request failed: " + e);
return null;
});
client.close();
}
}
I run Confluent env using docker-compose file:
https://github.com/confluentinc/cp-all-in-one/blob/6.0.0-post/cp-all-in-one/docker-compose.yml and create users topic with data.
But got exception inside io.netty.resolver.AddressResolverGroup class, getResolver(final EventExecutor executor) method:
Request failed: java.util.concurrent.CompletionException:
java.lang.IllegalStateException: executor not accepting a task
But all works fine when I run PULL query with synchronous usage:
StreamedQueryResult streamedQueryResult = client.streamQuery("SELECT * FROM users EMIT CHANGES;").get();
for (int i = 0; i < 10; i++) {
// Block until a new row is available
Row row = streamedQueryResult.poll();
if (row != null) {
System.out.println("Row: " + row.values());
}
}
You should not close the client connection while streaming.
Remove the client.close(); to test.
My question is, behind the scene, for element-wise Beam DoFn (ParDo), how does the Cloud Dataflow parallel workload? For example, in my ParDO, I send out one http request to an external server for one element. And I use 30 workers, each has 4vCPU.
Does that mean on each worker, there will be 4 threads at maximum?
Does that mean from each worker, only 4 http connections are necessary or can be established if I keep them alive to get the best performance?
How can I adjust the level of parallelism other than using more cores or more workers?
with my current setting (30*4vCPU worker), I can establish around 120 http connections on the http server. But both server and worker has very low resource usage. basically I want to make them work much harder by sending out more requests out per second. What should I do...
Code Snippet to illustrate my work:
public class NewCallServerDoFn extends DoFn<PreparedRequest,KV<PreparedRequest,String>> {
private static final Logger Logger = LoggerFactory.getLogger(ProcessReponseDoFn.class);
private static PoolingHttpClientConnectionManager _ConnManager = null;
private static CloseableHttpClient _HttpClient = null;
private static HttpRequestRetryHandler _RetryHandler = null;
private static String[] _MapServers = MapServerBatchBeamApplication.CONFIG.getString("mapserver.client.config.server_host").split(",");
#Setup
public void setupHttpClient(){
Logger.info("Setting up HttpClient");
//Question: the value of maxConnection below is actually 10, but with 30 worker machines, I can only see 115 TCP connections established on the server side. So this setting doesn't really take effect as I expected.....
int maxConnection = MapServerBatchBeamApplication.CONFIG.getInt("mapserver.client.config.max_connection");
int timeout = MapServerBatchBeamApplication.CONFIG.getInt("mapserver.client.config.timeout");
_ConnManager = new PoolingHttpClientConnectionManager();
for (String mapServer : _MapServers) {
HttpHost serverHost = new HttpHost(mapServer,80);
_ConnManager.setMaxPerRoute(new HttpRoute(serverHost),maxConnection);
}
// config timeout
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(timeout)
.setConnectionRequestTimeout(timeout)
.setSocketTimeout(timeout).build();
// config retry
_RetryHandler = new HttpRequestRetryHandler() {
public boolean retryRequest(
IOException exception,
int executionCount,
HttpContext context) {
Logger.info(exception.toString());
Logger.info("try request: " + executionCount);
if (executionCount >= 5) {
// Do not retry if over max retry count
return false;
}
if (exception instanceof InterruptedIOException) {
// Timeout
return false;
}
if (exception instanceof UnknownHostException) {
// Unknown host
return false;
}
if (exception instanceof ConnectTimeoutException) {
// Connection refused
return false;
}
if (exception instanceof SSLException) {
// SSL handshake exception
return false;
}
return true;
}
};
_HttpClient = HttpClients.custom()
.setConnectionManager(_ConnManager)
.setDefaultRequestConfig(requestConfig)
.setRetryHandler(_RetryHandler)
.build();
Logger.info("Setting up HttpClient is done.");
}
#Teardown
public void tearDown(){
Logger.info("Tearing down HttpClient and Connection Manager.");
try {
_HttpClient.close();
_ConnManager.close();
}catch (Exception e){
Logger.warn(e.toString());
}
Logger.info("HttpClient and Connection Manager have been teared down.");
}
#ProcessElement
public void processElement(ProcessContext c) {
PreparedRequest request = c.element();
if(request == null)
return;
String response="{\"my_error\":\"failed to get response from map server with retries\"}";
String chosenServer = _MapServers[request.getHardwareId() % _MapServers.length];
String parameter;
try {
parameter = URLEncoder.encode(request.getRequest(),"UTF-8");
} catch (UnsupportedEncodingException e) {
Logger.error(e.toString());
return;
}
StringBuilder sb = new StringBuilder().append(MapServerBatchBeamApplication.CONFIG.getString("mapserver.client.config.api_path"))
.append("?coordinates=")
.append(parameter);
HttpGet getRequest = new HttpGet(sb.toString());
HttpHost host = new HttpHost(chosenServer,80,"http");
CloseableHttpResponse httpRes;
try {
httpRes = _HttpClient.execute(host,getRequest);
HttpEntity entity = httpRes.getEntity();
if(entity != null){
try
{
response = EntityUtils.toString(entity);
}finally{
EntityUtils.consume(entity);
httpRes.close();
}
}
}catch(Exception e){
Logger.warn("failed by get response from map server with retries for " + request.getRequest());
}
c.output(KV.of(request, response));
}
}
Yes, based on this answer.
No, you can establish more connections. Based on my answer, you can use a async http client to have more concurrent requests. As this answer also describes, you need to collect the results from these asynchronous calls and output it synchronously in any #ProcessElement or #FinishBundle.
See 2.
Since your resource usage is low, it indicates that the worker spends most of its time waiting for a response. I think with the described approach above, you can utilize your resources far better and you can achieve the same performance with far less workers.
This is the code and I am recieving the error 401: Authentication Error
public class Server {
// initialize socket and input stream
private Socket socket = null;
private ServerSocket server = null;
private DataInputStream in = null;
public void tweet() throws TwitterException {
ConfigurationBuilder cb = new ConfigurationBuilder();
cb.setDaemonEnabled(true).setOAuthConsumerKey("......")
.setOAuthConsumerSecret("......")
.setOAuthAccessToken("......")
.setOAuthAccessTokenSecret(".....");
TwitterFactory tf = new TwitterFactory();
twitter4j.Twitter twitter = tf.getInstance();
List status = twitter.getHomeTimeline();
for (Status st : status) {
System.out.println(st.getUser().getName() + "---- Tweets----" + st.getText());
}
}
// constructor with port
public Server(int port) throws TwitterException {
// starts server and waits for a connection
try {
server = new ServerSocket(port);
System.out.println("Server started");
System.out.println("Waiting for a client ...");
socket = server.accept();
System.out.println("Client accepted");
// takes input from the client socket
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
String line = "";
// reads message from client until "Over" is sent
while (!line.equals("Over")) {
try {
line = in.readUTF();
System.out.println(line);
if (line.equalsIgnoreCase("Data")) {
tweet();
}
} catch (IOException i) {
System.out.println(i);
}
}
System.out.println("Closing connection");
// close connection
socket.close();
in.close();
} catch (IOException i) {
System.out.println(i);
}
}
public static void main(String args[]) throws TwitterException {
Server server = new Server(5000);
}
}
Please make sure that the tokens are valid.
Then, you could try enabling system proxies like so:
System.setProperty("java.net.useSystemProxies", "true");
Background
I have banged my head against this for a while and not made much progress. I am generating MPEG_4 / AAC files in Android and sending them by email as .mp3 files. I know they aren't actually .mp3 files, but that allows Hotmail and Gmail to play them in Preview. They don't work on iPhone though, unless they are sent as .m4a files instead which breaks the Outlook / Gmail Preview.
So I have thought of a different approach which is to attach as a .mp3 file but have an HTML link in the email body which allows the attached file to be downloaded and specifies a .m4a file name. Gmail / Outlook users can click the attachment directly whereas iPhone users can use the HTML link.
Issue
I can send an email using JavaMail with HTML in it including a link which should be pointing at the attached file to allow download of that file by the link. Clicking on the link in Gmail (Chrome on PC) gives a 404 page and iPhone just ignores my clicking on the link.
Below is the code in which I generate a multipart message and assign a CID to the attachment which I then try to access using the link in the html part. It feels like I am close, but maybe that is an illusion. I'd be massively grateful if someone could help me fix it or save me the pain if it isn't possible.
private int send_email_temp(){
Properties props = new Properties();
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.host", smtp_host_setting);
//props.put("mail.debug", "true");
props.put("mail.smtp.ssl.enable", "true");
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.port", smtp_port_setting);
session = Session.getInstance(props);
ActuallySendAsync_temp asy = new ActuallySendAsync_temp(true);
asy.execute();
return 0;
}
class ActuallySendAsync_temp extends AsyncTask<String, String, Void> {
public ActuallySendAsync_temp(boolean boo) {
// something to do before sending email
}
#Override
protected Void doInBackground(String... params) {
try {
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(username));
message.setRecipients(Message.RecipientType.TO,
InternetAddress.parse(recipient_email_address));
message.setSubject(email_subject);
Multipart multipart = new MimeMultipart();
MimeBodyPart messageBodyPart = new MimeBodyPart();
String file = mFileName;
/**/
DataSource source = new FileDataSource(file);
messageBodyPart.setDataHandler(new DataHandler(source));
/* /
File ff = new File(file);
try {
messageBodyPart.attachFile(ff);
} catch(IOException eio) {
Log.e("Message Error", "Old Macdonald");
}
/* /
messageBodyPart = new PreencodedMimeBodyPart("base64");
byte[] file_bytes = null;
File ff = new File(file);
try {
int length = (int) ff.length();
BufferedInputStream reader = new BufferedInputStream(new FileInputStream(ff));
file_bytes = new byte[length];
reader.read(file_bytes, 0, length);
reader.close();
} catch (IOException eio) {
Log.e("Message Error", "Old Macdonald");
}
messageBodyPart.setText(Base64.encodeToString(file_bytes, Base64.DEFAULT));
messageBodyPart.setHeader("Content-Transfer-Encoding", "base64");
/**/
messageBodyPart.setFileName( DEFAULT_AUDIO_FILENAME );//"AudioClip.mp3");
//messageBodyPart.setContentID("<audio_clip>");
String content_id = UUID.randomUUID().toString();
messageBodyPart.setContentID("<" + content_id + ">");
messageBodyPart.setDisposition(Part.ATTACHMENT);//INLINE);
messageBodyPart.setHeader("Content-Type", "audio/mp4");
multipart.addBodyPart(messageBodyPart);
MimeBodyPart messageBodyText = new MimeBodyPart();
//final String MY_HTML_MESSAGE = "<h1>My HTML</h1><a download=\"AudioClip.m4a\" href=\"cid:audio_clip\">iPhone Download</a>";
final String MY_HTML_MESSAGE = "<h1>My HTML</h1><a download=\"AudioClip.m4a\" href=\"cid:" + content_id + "\">iPhone Download</a>";
messageBodyText.setContent( MY_HTML_MESSAGE, "text/html");
multipart.addBodyPart(messageBodyText);
message.setContent(multipart);
Print_Message_To_Console(message);
Transport transport = session.getTransport("smtp");
transport.connect(smtp_host_setting, username, password);
transport.sendMessage(message, message.getAllRecipients());
transport.close();
} catch (MessagingException e) {
e.printStackTrace();
} finally {
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
// something to do after sending email
}
}
int Print_Message_To_Console(Message msg) {
int ret_val = 0;
int line_num = 0;
InputStream in = null;
InputStreamReader inputStreamReader = null;
BufferedReader buff_reader = null;
try {
in = msg.getInputStream();
inputStreamReader = new InputStreamReader(in);
buff_reader = new BufferedReader(inputStreamReader);
String temp = "";
while ((temp = buff_reader.readLine()) != null) {
Log.d("Message Line " + Integer.toString(line_num++), temp);
}
} catch(Exception e) {
Log.d("Message Lines", "------------ OOPS! ------------");
ret_val = 1;
} finally {
try {
if (buff_reader != null) buff_reader.close();
if (inputStreamReader != null) inputStreamReader.close();
if (in != null) in.close();
} catch(Exception e2) {
Log.d("Message Lines", "----------- OOPS! 2 -----------");
ret_val = 2;
}
}
return ret_val;
}
You need to create a multipart/related and set the main text part as the first body part.
I'm comunicationg with a email gateway. That gateway has an specific ip and port.
The requests the gateway are JSON formated and the gateway normally responds first whith an proceeding state and then with a confirmation or error state, represented also in JSON.
The code to make the requests and receive the response is:
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Collections.Generic;
using System.Threading;
using Microsoft.Win32;
public class TcpClientSample
{
public static void SendMessage(TcpClient client, string msg)
{
Console.WriteLine("REQUEST:" + msg);
NetworkStream stream = client.GetStream();
byte[] myWriteBuffer = Encoding.ASCII.GetBytes(msg);
stream.Write(myWriteBuffer, 0, myWriteBuffer.Length);
byte[] myWriteBuffer2 = Encoding.ASCII.GetBytes("\r\n");
stream.Write(myWriteBuffer2, 0, myWriteBuffer2.Length);
string gResponse = "";
BinaryReader r = new BinaryReader(stream);
int receivedMessages = 0;
while (true)
{
while (true)
{
char currentChar = r.ReadChar();
if (currentChar == '\n')
break;
else
gResponse = gResponse + currentChar;
}
if (gResponse != "")
{
Console.WriteLine("RESPONSE:" + gResponse);
receivedMessages = receivedMessages + 1;
}
if (receivedMessages == 2)
{
break;
}
}
}
public static void Main()
{
List<string> messages = new List<string>();
for (int i = 0; i < 1; i++)
{
String msg = "{ \"user\" : \"James\", \"email\" : \"james#domain.pt\" }";
messages.Add(msg);
}
TcpClient client = new TcpClient();
client.Connect("someIp", somePort);
int sentMessages = 0;
int receivedMessages = 0;
foreach (string msg in messages)
{
Thread newThread = new Thread(() =>
{
sentMessages = sentMessages + 1;
Console.WriteLine("SENT MESSAGES: " + sentMessages);
SendMessage(client, msg);
receivedMessages = receivedMessages + 1;
Console.WriteLine("RECEIVED MESSAGES: " + receivedMessages);
});
newThread.Start();
}
Console.ReadLine();
}
}
If I send few emails (up to 10) the network stream is OK.
But if I send thousands of emails I get messed chars lie
:{iyo"asn ooyes" "ncd" 0,"s_d:"4379" nme" 92729,"er_u" ,"ed_t_i" 2#" p cin_d:"921891010-11:11.725,"s" 4663175D0105E6912ADAAFFF6FDA393367" rpy:"rcein"
Why is this?
Don't worry I'm not a spammer :D
When you write a message to a TCP socket, it'll respond with the sent data. When the buffer is full, I expect it's 0, but you advance your send buffer anyway. You should advance it by the return value :)
Edit: it looks like you're using a stream abstraction which writes the internal buffer. The situation is the same. You are saying "the message has been completely sent" when the internal buffer state is not saying this, i.e. position does not equal limit. You need to keep sending until the remaining amount of buffer is 0 before moving on.
I solved this issue by having a single method just to read from the stream like this:
private TcpClient client;
private NetworkStream stream;
public void ListenFromGateway()
{
...
while (true)
{
byte[] bytes = new byte[client.ReceiveBufferSize];
//BLOCKS UNTIL AT LEAST ONE BYTE IS READ
stream.Read(bytes, 0, (int)client.ReceiveBufferSize);
//RETURNS THE DATA RECEIVED
string returndata = Encoding.UTF8.GetString(bytes);
//REMOVE THE EXCEDING CHARACTERS STARTING ON \r
string returndata = returndata.Remove(returndata.IndexOf('\r'));
...
}
Thanks for the help