I am working on C# MailClient and which is follow IMAP Protocol, but I am getting wrong response that means the response will give me some repetitive resul.
Like say first time I am sending command like this.
byte[] commandBytes = System.Text.Encoding.ASCII.GetBytes(("$ UID FETCH " + index + " (BODY[HEADER.FIELDS (SUBJECT FROM DATE)])\r\n"));
and second time I am sending like this.
byte[] commandBytes = System.Text.Encoding.ASCII.GetBytes(("$ UID FETCH " + index + " (BODYSTRUCTURE)" + "\r\n"));
so I am getting again first command result in twice or more than 2 times;
and some times it's continue giving me first result.
my Response() method is like this.
private string Response()
{
string response = string.Empty;
byte[] data = new byte[_imapClient.ReceiveBufferSize];
int ret = _imapNs.Read(data, 0, data.Length);
response = Encoding.ASCII.GetString(data,0,ret);
return response;
}
_imapClient is a object of an
private TcpClient _imapClient;
and I am taking value of _imapClient is like this.
public string GetMessageBodyStructure(int index)
{
byte[] commandBytes = System.Text.Encoding.ASCII.GetBytes(("$ UID FETCH " + index + " (BODYSTRUCTURE)" + "\r\n"));
_imapNs.Write(commandBytes, 0, commandBytes.Length);
_imapNs.Flush();
return Response();
}
Where I am wrong correct me thanks..
Do not use char array:
byte[] commandBytes = System.Text.Encoding.ASCII.GetBytes("$ UID FETCH " + index + " (BODYSTRUCTURE)" + "\r\n");
TCP is stream based and not message based.
This means that nothing guarantees that the entire message is received with the same Read. A Read may receive a half message, a complete message or two messages. You need to handle that accordingly.
3 Use return Encoding.ASCII.GetString(data, 0, ret);
4 There are several open source IMAP libraries out there. Why not use one of those since you are new to socket programming?
Related
Im currently creating a project that will run in a browser & has an c# server connected.
The Server uses an TcpListener to accept connections & receive messages, but I want the server to be able to respond to the client. This has given me a few issues.
Here is the code for my client:
private ClientWebSocket socket;
internal async Task InitAsync(string host, int port, GamePacketParser parser)
{
Logger.Info("Setting up the socket connection...");
socket = new ClientWebSocket();
await socket.ConnectAsync(new Uri($"ws://{host}:{port}/"), CancellationToken.None);
Logger.Info("Successfully established the connection.");
this.parser = parser;
buffer = new byte[GameSocketManagerStatics.BUFFER_SIZE];
Task.Run(recieve);
}
private async Task recieve()
{
Logger.Debug("Starting Reciever.....");
var result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
var packet = new byte[result.Count];
Array.Copy(buffer, packet, result.Count);
///parser.handlePacketData(packet);
Logger.Debug($"Recieved: {Encoding.UTF8.GetString(packet)}");
///Task.Run(recieve); //Start receiving again
}
public async Task SendData(byte[] data)
{
Logger.Debug("Triggerd send");
string packet = BitConverter.ToString(data);
await socket.SendAsync(new ArraySegment<byte>(data), WebSocketMessageType.Text, true, CancellationToken.None);
Logger.Info($"Sended Data: {packet}");
}
The code above simply connects to the server over a web socket. Sending packets works fine. The second the server sends data back, the client won't send any data anymore to the server. Like its stuck.
static void Main(string[] args)
{
string ip = "127.0.0.1";
int port = 30000;
var server = new TcpListener(IPAddress.Parse(ip), port);
server.Start();
Console.WriteLine("Server has started on {0}:{1}, Waiting for a connection...", ip, port);
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("A client connected.");
NetworkStream stream = client.GetStream();
if (Regex.IsMatch(s, "^GET", RegexOptions.IgnoreCase))
{
Console.WriteLine("=====Handshaking from client=====\n{0}", s);
// 1. Obtain the value of the "Sec-WebSocket-Key" request header without any leading or trailing whitespace
// 2. Concatenate it with "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" (a special GUID specified by RFC 6455)
// 3. Compute SHA-1 and Base64 hash of the new value
// 4. Write the hash back as the value of "Sec-WebSocket-Accept" response header in an HTTP response
string swk = Regex.Match(s, "Sec-WebSocket-Key: (.*)").Groups[1].Value.Trim();
string swka = swk + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
byte[] swkaSha1 = System.Security.Cryptography.SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(swka));
string swkaSha1Base64 = Convert.ToBase64String(swkaSha1);
// HTTP/1.1 defines the sequence CR LF as the end-of-line marker
byte[] response = Encoding.UTF8.GetBytes(
"HTTP/1.1 101 Switching Protocols\r\n" +
"Connection: Upgrade\r\n" +
"Upgrade: websocket\r\n" +
"Sec-WebSocket-Accept: " + swkaSha1Base64 + "\r\n\r\n");
stream.Write(response, 0, response.Length);
}
byte[] message = Encoding.UTF8.GetBytes("Connection is established");
stream.Write(message, 0, message.Length);
}
The problem is probably because it is not encoded for WebSockets, but I tried a lot of online solutions for encoding (For example: How can I send and receive WebSocket messages on the server side?) But even with those encoders, it did not seem to solve the problem.
Thanks for your help in advance. Im still new to WebSockets, so spoonfeeding is allowed.
aepot your answer is a good one, but i really wanted my server on the TCP level, I would have needed to change to much code if I wanted to use it on my official server that uses sockets.
I have been doing some more digging into WebSockets, after some searching I figured it out, I basically needed to send a header before sending the data. I did not know how to create that header, but I found some code online that did. (I have been searching for about 12 hours :?)
The solution:
protected int GetHeader(bool finalFrame, bool contFrame)
{
int header = finalFrame ? 1 : 0;//fin: 0 = more frames, 1 = final frame
header = (header << 1) + 0;//rsv1
header = (header << 1) + 0;//rsv2
header = (header << 1) + 0;//rsv3
header = (header << 4) + (contFrame ? 0 : 1);//opcode : 0 = continuation frame, 1 = text
header = (header << 1) + 0;//mask: server -> client = no mask
return header;
}
protected byte[] IntToByteArray(ushort value)
{
var ary = BitConverter.GetBytes(value);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(ary);
}
return ary;
}
public static IEnumerable<string> SplitInGroups(this string original, int size)
{
var p = 0;
var l = original.Length;
while (l - p > size)
{
yield return original.Substring(p, size);
p += size;
}
yield return original.Substring(p);
}
public static void SendMessage(string packet) {
Queue<string> que = new Queue<string>(packet.SplitInGroups(125)); //Make it so the message is never longer then 125 (Split the message into parts & store them in a queue)
int len = que.Count;
while (que.Count > 0)
{
var header = GetHeader(
que.Count > 1 ? false : true,
que.Count == len ? false : true
); //Get the header for a part of the queue
byte[] list = Encoding.UTF8.GetBytes(qui.Dequeue()); //Get part of the message out of the queue
header = (header << 7) + list.Length; //Add the length of the part we are going to send
//Send the header & message to client
stream.write(IntToByteArray((ushort)header));
stream.write(list);
}
}
I have not coded this myself, but sadly I cant find the link where I got it from to credit the person who did.
I'm trying to create a app checking email exist using .NET
I was thinking for 2 hours didn't figure any solution
the purpose of this solution is make my server dodging the ban or exceed of test.
my problem is how to auto-reconnect the TcpClient after number of email checked and continuing from last email in the Array
public void isChecked(string[] MailCheck,string length)
{
//converte ArrayLength from string to int
int num = int.Parse(length);
TcpClient tClient = new TcpClient("smtp-in.orange.fr", 25);
string CRLF = "\r\n";
byte[] dataBuffer;
string ResponseString;
NetworkStream netStream = tClient.GetStream();
StreamReader reader = new StreamReader(netStream);
ResponseString = reader.ReadLine();
/* Perform HELO to SMTP Server and get Response */
dataBuffer = BytesFromString("HELO Contact" + CRLF);
netStream.Write(dataBuffer, 0, dataBuffer.Length);
ResponseString = reader.ReadLine();
dataBuffer = BytesFromString("mail from:<contact#contact.com>" + CRLF);
netStream.Write(dataBuffer, 0, dataBuffer.Length);
ResponseString = reader.ReadLine();
for (i = 0; i < num; i++)
{
/* Read Response of the RCPT TO Message to know from google if it exist or not */
dataBuffer = BytesFromString("rcpt to:<" + MailCheck[i] + ">" + CRLF);
netStream.Write(dataBuffer, 0, dataBuffer.Length);
ResponseString = reader.ReadLine();
if (GetResponseCode(ResponseString) == 550)
{
//MessageBox.Show("false " + ResponseString);
System.Diagnostics.Debug.WriteLine("false || " + ResponseString);
}
else
{
//MessageBox.Show("true " + ResponseString);
System.Diagnostics.Debug.WriteLine("true || " + ResponseString);
System.IO.File.AppendAllText(#"C:/WarningsLog.txt", MailCheck[i] + Environment.NewLine);
}
}
You could
put the recipients into a List
as outer loop, iterate while the list is not empty. To avoid an endless loop, you may consider to limit the number of iterations.
connect to the SMPT server
as inner loop, send the messages. When a mail could be sent, remove the recipient from the list. If a transient error occured, exit the inner loop
Did you consider using an existing SMTP client implementation like https://github.com/jstedfast/MailKit or at least System.Net.SmtpClient?
I'm working on my own Jabber client (mostly to learn both XMPP and C#) and currently I'm trying to connect to server using SCARAM-SHA-1 over TLS. TLS negotiation goes fine as well as First Client/Server messages exchange, I get Server Challenge and generating Client Final Message with following code:
//Following block generates Client Final Message
//---STEP 1. Creating Salted Password---
byte[] SaltBytes = Encoding.UTF8.GetBytes(Salt);
byte[] SaltedPasswordBytes = GetSaltedPassword(UserPassword, Convert.FromBase64String(Salt), Iterations);
//---STEP 2. Creating Client Key---
byte[] ClientKeyBytes = GetHash("Client Key", SaltedPasswordBytes);
string ClientKey = BitConverter.ToString(ClientKeyBytes);
//---STEP 3. Creating Stored Key---
SHA1 StoredKeySHA = SHA1.Create();
byte[] StoredKeyBytes = StoredKeySHA.ComputeHash(ClientKeyBytes);
string StoredKey = BitConverter.ToString(StoredKeyBytes);
//---STEP 4. Creating Auth Message---
string AuthMessage = "n=test_guy,r=" + ClientNonce + "," + ServerChallenge + "," + "c=" + StringToBase64("n,,") + ",r=" + ClientAndServerNonces; //concern: AuthMessage might start with "n=<username>" or "n,,n=<username>" - which one is right?
LogRTB.Text += "AuthMessage is:\n" + AuthMessage + "\n";
//---STEP 5. Creating Client Signature---
byte[] ClientSignatureBytes = GetHash(AuthMessage, StoredKeyBytes);
string ClientSignature = BitConverter.ToString(ClientSignatureBytes);
//---STEP 6. Creating Client Proof---
LogRTB.Text += "---STEP 6. Calculating Client Proof---\n" + "Client Key is: " + ClientKey + "\nClientSignature is: " + ClientSignature;
byte[] ClientProofBytes = new byte[ClientKeyBytes.Length];
for (int i = 0; i < ClientKeyBytes.Length; ++i)
{
ClientProofBytes[i] = (byte)(ClientKeyBytes[i] ^ ClientSignatureBytes[i]);
}
LogRTB.Text += "\nClient Proof (string) is: " + ClientProof + "\n";
//---STEP 7. Creating Server Key---
byte[] ServerKeyBytes = GetHash("Server Key", SaltedPasswordBytes);
string ServerKey = BitConverter.ToString(ServerKeyBytes);
LogRTB.Text += "Server Key is: " + ServerKey + "\n";
//---STEP 8. Creating Server Signature---
byte[] ServerSignatureBytes = GetHash(AuthMessage, ServerKeyBytes);
string ServerSignature = Convert.ToBase64String(ServerSignatureBytes);
//DONE!
ClientProof = StringToBase64(ClientProof);
string ClientResponse = "c=biws,r=" + ClientAndServerNonces +",p=" + ClientProof; //putting together Client Response (most important part of Client Final Message)
//ClientResponse.Replace("==",""); //NO! just no!
LogRTB.Text += "Client response is:\n" + ClientResponse + "\n"; //DEBUG!
string ClientResponseBase64 = StringToBase64(ClientResponse);
if (IsBase64String(ClientResponseBase64))
{
string ClientFinalMessage = "<response xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">" + ClientResponseBase64 + "</response>";
LogRTB.Text += "--> Client response (Client Final Message) is:\n" + ClientFinalMessage + "\n";
LogRTB.Text += "--> SENDING NOW!\n";
ServerReply = SendXMPPQueryOverTLS(ServerSocket, SecureConnection, ClientFinalMessage); //Sending Client Final Message
LogRTB.Text += ServerReply;
}
Problem is - I don't get ANY reply from the server, when according to RFC6120 (XMPP Core) server is supposed to reply with failure or success message. Also, if I deliberately send wrong message (for instance omitting Client Proof) it does reply with bad-protocol message. Server is ejabberd with default settings.
I spent couple of days trying to figure out what's wrong and now getting a bit desperate. I hope someone here will be able to help me.
(If needed I can also provide logs that my app generates during connection process)
Thanks in advance!
I have tested agsXMPP SCRAM implementation and it works good with ejabberd. Try to compare with your code - https://github.com/meebey/agsxmpp/blob/master/agsxmpp/Sasl/Scram/ScramSha1Mechanism.cs
I developed a simple TCP client on Windows Phone, as shown here on MSDN
This is working just as expected.
Now, I want to send very large Base64 strings though this client (for transferring images).
But, when I try to send Base64 strings from this client, I only receive a portion of the string at the server, due to which I'm not able to generate the entire image at the server.
The server side code for receiving strings is: (Edited)
IPAddress ipAd = IPAddress.Any;
Console.Write("Port No. (leave blank for port 8001): ");
string port;
port = Console.ReadLine();
if (port == "")
port = "8001";
/* Initializes the Listener */
TcpListener myList = new TcpListener(ipAd, int.Parse(port));
/* Start Listeneting at the specified port */
myList.Start();
Console.WriteLine("\nThe server is running at port " + port);
Console.WriteLine("The local End point is :" +
myList.LocalEndpoint);
Console.WriteLine("\nWaiting for a connection.....");
Socket s = myList.AcceptSocket();
Console.WriteLine("\nConnection accepted from " + s.RemoteEndPoint);
byte[] b = new byte[5 * 1024 * 1024]; // BIG SIZE for byte array, is this correct?
String message = String.Empty;
int k = s.Receive(b);
Console.WriteLine("\nRecieved...");
for (int i = 0; i < k; i++)
{
message += Convert.ToChar(b[i]);
Console.Write(Convert.ToChar(b[i]));
}
System.IO.File.WriteAllText(#"Message.txt", message); // write it to a file
ASCIIEncoding asen = new ASCIIEncoding();
s.Send(asen.GetBytes("The string was recieved by the server."));
Console.WriteLine("\n\nSent Acknowledgement");
/* clean up */
s.Close();
myList.Stop();
I'm really stuck here.
Please help me.
I think the problem is with the client and not the server.
Please assist me.
The class I've used in the client can be found at the MSDN article referred to above.
PS: I've already tried to increase the values of TIMEOUT_MILLISECONDS and MAX_BUFFER_SIZE in the class. But it did not help.
Update:
Here's some client side code (look here on MSDN for reference):
// Make sure we can perform this action with valid data
if (ValidateRemoteHost() && ValidateInput())
{
// Instantiate the SocketClient
SocketClient client = new SocketClient();
// Attempt to connect to the echo server
Log(String.Format("Connecting to server '{0}' over port {1} (echo) ...", txtRemoteHost.Text, ECHO_PORT), true);
string result = client.Connect(txtRemoteHost.Text, ECHO_PORT);
Log(result, false);
byte[] bytearray = null;
// Attempt to send our message to be echoed to the echo server
Log(String.Format("Sending '{0}' to server ...", txtInput.Text), true);
if (checkBox1.IsChecked == true) // this checkbox is for image selection
{
// This is the part where we send images
using (MemoryStream ms = new MemoryStream())
{
WriteableBitmap wbitmp = new WriteableBitmap((BitmapImage)image1.Source);
wbitmp.SaveJpeg(ms, (int)wbitmp.PixelWidth, (int)wbitmp.PixelHeight, 0, 10);
bytearray = ms.ToArray();
string str = Convert.ToBase64String(bytearray);
result = client.Send(str);
System.Diagnostics.Debug.WriteLine("\n\nMessge sent:\n\n" + str + "\n\n");
}
}
else
{
result = client.Send(txtInput.Text);
}
Log(result, false);
// Receive a response from the server
Log("Requesting Receive ...", true);
result = client.Receive();
Log(result, false);
// Close the socket connection explicitly
client.Close();
}
while ((RecBytes = netstream.Read(RecData, 0, RecData.Length)) > 0)
{
Fs.Write(RecData, 0, RecBytes);
totalrecbytes += RecBytes;
}
Edit: now that section of code has been reduced down to only
int k = s.Receive(b);
is bad: it assumes all the data sends perfectly in one go, which isn't how networking works.
Two options:
At the start of the string, include how long it should.
At the end of the string, have an end symbol (a null perhaps) that won't be anywhere else in the message
Then that while loop should keep going until either the entire length is found or the end symbol is found.
(Also, sending Base64 is a bad idea when you can avoid it. Why not send as a stream of raw bytes?)
[ED: This portion is no longer relevant](Also, why is the server choosing where to save the file [and delaying everything until the server makes a pick] - the client should indicate where to save it at the start, and then the server merely sanity checks it. [Unless you have a very good reason not do it that way])
EDIT: a quick simple implementation of what I was saying:
This server code
int k = s.Receive(b);
Console.WriteLine("\nRecieved...");
for (int i = 0; i < k; i++)
{
message += Convert.ToChar(b[i]);
Console.Write(Convert.ToChar(b[i]));
}
change to
while (true)
{
int k = s.Receive(b);
Console.WriteLine("\nRecieved...");
for (int i = 0; i < k; i++)
{
char bc = Convert.ToChar(b[i]); // This is a very wrong way of doing this but it works I guess meh.
if (bc == ' ')
{ // You've struck the end! Get out of this infinite loop!
goto endmyloop;
}
message += bc;
Console.Write(bc);
}
}
endmyloop:
This piece of client code
result = client.Send(str);
change to
result = client.Send(str + " ");
-- Base64 can never have a space in it, so that will be used to mark the end.
Be warned that if the client errors (and doesn't send a space at the end for some weird reason), this code will be trapped in the while loop forever (zero-CPU-usage infinite-wait)
I am doing an embedded project in C# and I have written a socket based web server. Everything works well, except I can't for the life of me get the request body. Content-Length says that there is 12 characters, but the socket.Recieve method only gets the headers.
while (true)
{
using (Socket clientSocket = listeningSocket.Accept())
{
IPEndPoint clientIP = clientSocket.RemoteEndPoint as IPEndPoint;
Debug.Print("Received request from " + clientIP.ToString());
var x = clientSocket.RemoteEndPoint;
int availableBytes = clientSocket.Available;
Debug.Print(DateTime.Now.ToString() + " " + availableBytes.ToString() + " request bytes available");
int bytesReceived = (availableBytes > maxRequestSize ? maxRequestSize : availableBytes);
if (bytesReceived > 0)
{
byte[] buffer = new byte[bytesReceived]; // Buffer probably should be larger than this.
int readByteCount = clientSocket.Receive(buffer, bytesReceived, SocketFlags.None);
using (Request r = new Request(clientSocket, Encoding.UTF8.GetChars(buffer)))
{
Debug.Print(DateTime.Now.ToString() + " " + r.URL);
if (requestReceived != null) requestReceived(r);
}
}
}
Thread.Sleep(10);
}
availableBytes = 499
bytesReceived = 499
readByteCount = 487 (12 characters short)
What am I missing here? The body is multipart form data if that makes any difference.
int bytesReceived = (availableBytes > maxRequestSize ? maxRequestSize : availableBytes);
If maxRequestSize is 487, then you will get the results you describe.
Also remember Content-Length is not bytes - it's octets: What's the "Content-Length" field in HTTP header? (OK I'm being pedantic - and octet is 8 bits ;))
I wonder how reliable that Available property is. It looks like it's only useful for non-blocking sockets, and then only as a boolean flag saying that something is available.
Why not just read the stream in a loop parsing messages as you go?