Replace WCF NetNamedPipeBinding - c#

I'm using a WCF service with NetNamedPipeBinding for IPC. This prevents the code to be updated to .Net 7 so I want to replace the WCF server with a client compatible solution. I can't afford breaking changes, so replacing server and client with sth else is no option.
Getting the windows name of the named pipe works
//localhost replaced by + or *, capitals, trailing slash
string normalizedName = "net.pipe://+/SOME/PATH/";
var base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(normalizedName));
string namedPipeMMFName = string.Format(#"Global\net.pipe:E{0}", base64);
For the server
mmf = MemoryMappedFile.CreateOrOpen(namedPipeMMFName, 20, MemoryMappedFileAccess.ReadWrite);
{
using (var accessor = mmf.CreateViewAccessor(0, 20, MemoryMappedFileAccess.Write))
{
//Reverse engineered. Meaning unclear
accessor.Write(0, 1);
accessor.Write(1, 0);
accessor.Write(2, 0);
accessor.Write(3, 0);
Guid pipeGuid = Guid.NewGuid();
accessor.Write<Guid>(4, ref pipeGuid);
retVal = pipeGuid.ToString();
}
}
For the client
using (var mmf = MemoryMappedFile.OpenExisting(namedPipeMMFName, MemoryMappedFileRights.Read))
{
using (var accessor = mmf.CreateViewAccessor(4, 16, MemoryMappedFileAccess.Read))
{
accessor.Read(0, out Guid pipeGuid);
retVal = pipeGuid.ToString();
}
}
The server now looks like that
var pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.InOut, maxNumberOfServerInstances, PipeTransmissionMode.Message, PipeOptions.Asynchronous);
pipeServer.BeginWaitForConnection(WaitForConnectionCallBack, null);
When the client (WCF!) opens the connection the new server recognizes it and begins to read.
After calling EndRead() I get the first result
"\0\u0001\0\u0001\u0002\u0002\u0019net.pipe://localhost/IF13\u0003\b\f"
which looks like sth from the client. Further read calls result in no data as if the pipe was closed by the client
I expect that WCF client requires some kind of hand shake.
What do I have to answer after the first successful read?
Thanks
Tom

Related

Communication between Node.js and C# .Net using named pipe: 'data' event not fired

I've setup a named pipe to have a nodejs app communicate with a C# app. I am able to have the pipe connected, and send data from nodejs to C#, but the opposite doesn't work. i.e. When I write in the pipe from C#, the data event is never fired on the nodejs side.
nodejs code:
const net = require('net');
const pipeName = 'mypipe';
var server = net.createServer(function (client) {
client.on('data', function (data) {
console.log("data: " + data.toString());
});
});
server.listen(path.join('\\\\.\\pipe', pipeName), function() {
console.log("connected");
});
C# code:
var pipe = new NamedPipeClientStream(".", "mypipe", PipeDirection.InOut, PipeOptions.Asynchronous);
pipe.Connect();
if (pipe.IsConnected && pipe.CanWrite) {
var data = new byte[4] {0, 1, 2, 3};
pipe.WriteAsync(data, 0, data.Length);
}
As I mentioned, when I write in the client socket in nodejs, I properly receive the data on C# side using ReadyAsync. The pipe client is created using PipeDirection.InOut so it should support reading as well as writing?
EDIT: Also tried using BeginWrite/EndWrite with no success.
Thanks.

Deserializing Protobuf c# from wire

I am using the protobuf google implementation for c#.
The story so far..I have a server in c++ and clients in c# and the talk via protobuf messages with TCP.
On the client side, I retrieve the buffers returned from the tcpClient.BeginReceive via the callback provided and append them (so I guess it is cleared from the netstream junk). Then on a worker thread, I try to deserialize the messages.
On the server side the serialization code is:
google::protobuf::uint32 msgSize = msg->ByteSize();
int prefix_length = sizeof(msgSize);
int buffer_length = msgSize + prefix_length;
google::protobuf::uint8 buffer[buffer_length];
google::protobuf::io::ArrayoutputStream array_output(buffer, buffer_length, msgSize);
google::protobuf::io::CodedOutputStream coded_output(&array_output);
coded_output.WriteVarint32(msgSize);
msg->SerializeToCodedStream(&coded_output);
//Send to socket
mSendBuffer.Write(buffer, buffer_length);
On the client I read each chunk using CodedInputStream, read the first number and dispatch the prefix+the msg it contains for deserialization
Figuring out the length:
using (var input = new CodedInputStream(chunk))
{
int len = input.ReadInt32();
int requiredLength = len + input.Position; //(we re sure each time the codedInput starts from the beginning)
byte[] read = await AccumulateResources(requiredLength, chunk);
byte[] msg = new byte[requiredLength];
Buffer.BlockCopy(read, 0, msg , 0 , requiredLength);
Dispatch(msg);
}
Deserialization:
using (var ms = new MemoryStream(buff))
{
ServerMessageFrame msg = null;
try
{
msg = ServerMessageFrame.Parser.ParseDelimitedFrom(ms);
}
catch(Exception e)
{
Logger.Write(conn.clntPrefx + " " + e.ToString());
}
//Use the message
}
The error Messages I receive are:
1)System.InvalidOperationExeption: Wire Type is invalid
2)Protocol message contained invalid tag (zero).
The communication is correct at the beginning and it desyncs at some point, from where it breaks (until I read another msg which starts with a prefixed value aka is not a partial message)
My question is the de/serialization sound or I am missing the mark completely like there is something that I don't account for at all.

Programically get the system name of named pipe

I am writing a inter-process comunication using WCF NetNamedPipeBinding.
My goal is to have service running at "net.pipe://localhost/service", so I running the simplest host:
host = new ServiceHost(contract, new Uri[] { "net.pipe://localhost" });
host.AddServiceEndpoint(typeof (IContract),
new NetNamedPipeBinding(), "service");
host.Open();
According to http://blogs.msdn.com/b/rodneyviana/archive/2011/03/22/named-pipes-in-wcf-are-named-but-not-by-you-and-how-to-find-the-actual-windows-object-name.aspx
the name is hidden behind system-generated guid.
And here comes the question.
Is there any possible way to get the name generated by system (guid) inside my program, so I could get path like "\Device\NamedPipe\GUID", like in the procexp, so it will be easier to sniff it?
(Except running sys internals executables in separate process and parsing its output?)
After a lot of fiddling around and breaking my head against the wall, I finally got this working:
Guid pipeGuid;
if (PipeName.Equals("*", StringComparison.InvariantCultureIgnoreCase) || PipeName.Equals("localhost", StringComparison.InvariantCultureIgnoreCase))
PipeName = "*";
string s = string.Format(#"net.pipe://{0}/", PipeName.ToUpper());
if(!string.IsNullOrWhiteSpace(ServiceName))
s = string.Format(#"net.pipe://*/{0}/", ServiceName.ToUpper());
var bytes = Encoding.UTF8.GetBytes(s);
var base64 = Convert.ToBase64String(bytes);
string namedPipeMMFName = string.Format(#"Global\net.pipe:E{0}", base64);
MemoryMappedFileSecurity mSec = new MemoryMappedFileSecurity();
mSec.AddAccessRule(new AccessRule<MemoryMappedFileRights>(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MemoryMappedFileRights.FullControl, AccessControlType.Allow));
using (var mmf = MemoryMappedFile.OpenExisting(namedPipeMMFName, MemoryMappedFileRights.Read))
{
using (var accessor = mmf.CreateViewAccessor(4, 45, MemoryMappedFileAccess.Read))
{
accessor.Read<Guid>(0, out pipeGuid);
}
}
using (NamedPipeClientStream client = new NamedPipeClientStream(GetResolvedText(ServerName), pipeGuid, PipeDirection.InOut,
PipeOptions.None, TokenImpersonationLevel.Impersonation))
{
client.Connect(10000);
}
I must thank Rodney Viana for his article and #Avner Shahar-Kashtan for his answer and numerous other articles I read. I hope that my answer can help someone in the future.
As the article you link to shows, WCF stores the named pipe name in a memory mapped file. To access it, you need to do the following:
Endpoint: net.pipe://localhost/TradeService/Service1
Normalized Endpoint: net.pipe://+/TRADESERVICE/SERVICE1/
Base 64 representation: bmV0LnBpcGU6Ly8rL1RSQURFU0VSVklDRS9TRVJWSUNFMS8=
Final memory mapped file: net.pipe:EbmV0LnBpcGU6Ly8rL1RSQURFU0VSVklDRS9TRVJWSUNFMS8=
Now you take the final MMF name and open it. Here's an article on using MMFs on MSDN: https://msdn.microsoft.com/en-us/library/dd267590(v=vs.110).aspx
// Open the MMF.
using (var mmf = MemoryMappedFile.OpenExisting(namedPipeMMFName))
{
// Create an accessor for 16 bytes (Size of GUID) starting at
// offset 5 (as the article states)
using (var accessor = mmf.CreateViewAccessor(5, 16))
{
Guid pipeGuid;
accessor.Read<Guid>(0, out pipeGuid);
Console.WriteLine("This should be the pipe name: " + pipeGuid);
}
}

C# equivalent to Java SSL-socket-connection

Hey guys I'm trying to write an AXL-client (SOAP) for the Cisco Unified Communications Manager. For that purpose I need to establish an ssl-connection to the AXL-service. Unfortunatly I dont know much about all that ssl-stuff.
However I was able to find a working Java-example, that does, what I want. The problem is, i need that in C#.NET. So I'm hoping, that someone could "translate" the following Java-code in a C#-version. But it has to do exactly the same, espacially the authentication and certificate-stuff.
Here is the code:
String sAXLSOAPRequest = "...";
byte[] bArray = null; // buffer for reading response from
Socket socket = null; // socket to AXL server
OutputStream out = null; // output stream to server
InputStream in = null; // input stream from server
X509TrustManager xtm = new MyTrustManager();
TrustManager[] mytm = { xtm };
SSLContext ctx = SSLContext.getInstance("SSL");
ctx.init(null, mytm, null);
SSLSocketFactory sslFact = (SSLSocketFactory) ctx.getSocketFactory();
socket = (SSLSocket) sslFact.createSocket("192.168.1.100", Integer.parseInt("8443"));
in = socket.getInputStream();
// send the request to the server
// read the response from the server
StringBuffer sb = new StringBuffer(2048);
bArray = new byte[2048];
int ch = 0;
int sum = 0;
out = socket.getOutputStream();
out.write(sAXLSOAPRequest.getBytes());
while ((ch = in.read(bArray)) != -1) {
sum += ch;
sb.append(new String(bArray, 0, ch));
}
socket.close();
// output the response to the standard output
System.out.println(sb.toString());
and this is the MyTrustManager-Class:
public class MyTrustManager implements X509TrustManager {
MyTrustManager() {
// create/load keystore
}
public void checkClientTrusted(X509Certificate chain[], String authType)
throws CertificateException {
}
public void checkServerTrusted(X509Certificate chain[], String authType)
throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
Any help would be appreciated.
Thanks
edit: sorry i should have mentioned: youre right i can generate a proxy-class, but sadly its not working properly. cisco did a really bad job with that (not to mention the really bad documentation). the proxy class throws some xml-errors when parsing some responses. so i have to do it manually for that cases...
i'll worry about the certificate security later
Have you tried consuming the web service the "proper" way? Add a SOAP web service reference to your C# project in Visual Studio, gets the stubs etc? That's the easiest way of doing it from C#. You can just specify a https protocol in the URL when you add the reference.

using c# .net libraries to check for IMAP messages from gmail servers [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
Does anyone have any sample code in that makes use of the .Net framework that connects to googlemail servers via IMAP SSL to check for new emails?
I'd recommend looking at MailKit as it is probably the most robust mail library out there and it's Open Source (MIT).
One of the awesome things about MailKit is that all network APIs are cancelable (something I haven't seen available in any other IMAP library).
It's also the only library that I know of that supports threading of messages.
using System;
using System.Net;
using System.Threading;
using MailKit.Net.Imap;
using MailKit.Search;
using MailKit;
using MimeKit;
namespace TestClient {
class Program
{
public static void Main (string[] args)
{
using (var client = new ImapClient ()) {
using (var cancel = new CancellationTokenSource ()) {
client.Connect ("imap.gmail.com", 993, true, cancel.Token);
// If you want to disable an authentication mechanism,
// you can do so by removing the mechanism like this:
client.AuthenticationMechanisms.Remove ("XOAUTH");
client.Authenticate ("joey", "password", cancel.Token);
// The Inbox folder is always available...
var inbox = client.Inbox;
inbox.Open (FolderAccess.ReadOnly, cancel.Token);
Console.WriteLine ("Total messages: {0}", inbox.Count);
Console.WriteLine ("Recent messages: {0}", inbox.Recent);
// download each message based on the message index
for (int i = 0; i < inbox.Count; i++) {
var message = inbox.GetMessage (i, cancel.Token);
Console.WriteLine ("Subject: {0}", message.Subject);
}
// let's try searching for some messages...
var query = SearchQuery.DeliveredAfter (DateTime.Parse ("2013-01-12"))
.And (SearchQuery.SubjectContains ("MailKit"))
.And (SearchQuery.Seen);
foreach (var uid in inbox.Search (query, cancel.Token)) {
var message = inbox.GetMessage (uid, cancel.Token);
Console.WriteLine ("[match] {0}: {1}", uid, message.Subject);
}
client.Disconnect (true, cancel.Token);
}
}
}
}
}
The URL listed here might be of interest to you
http://www.codeplex.com/InterIMAP
which was extension to
http://www.codeproject.com/KB/IP/imaplibrary.aspx?fid=91819&df=90&mpp=25&noise=5&sort=Position&view=Quick&fr=26&select=2562067#xx2562067xx
As the author of the above project i can say that yes it does support SSL.
I am currently working on a new version of the library that will be completely asynchronous to increase the speed with which it can interact with IMAP servers.
That code, while not complete, can be downloaded, along with the original synchronous library (which also supports SSL), from the code plex site linked to above.
Cross posted from the other similar question. See what happens when they get so similar?
I've been searching for an IMAP solution for a while now, and after trying quite a few, I'm going with AE.Net.Mail.
There is no documentation, which I consider a downside, but I was able to whip this up by looking at the source code (yay for open source!) and using Intellisense. The below code connects specifically to Gmail's IMAP server:
// Connect to the IMAP server. The 'true' parameter specifies to use SSL
// which is important (for Gmail at least)
ImapClient ic = new ImapClient("imap.gmail.com", "name#gmail.com", "pass",
ImapClient.AuthMethods.Login, 993, true);
// Select a mailbox. Case-insensitive
ic.SelectMailbox("INBOX");
Console.WriteLine(ic.GetMessageCount());
// Get the first *11* messages. 0 is the first message;
// and it also includes the 10th message, which is really the eleventh ;)
// MailMessage represents, well, a message in your mailbox
MailMessage[] mm = ic.GetMessages(0, 10);
foreach (MailMessage m in mm)
{
Console.WriteLine(m.Subject);
}
// Probably wiser to use a using statement
ic.Dispose();
I'm not affiliated with this library or anything, but I've found it very fast and stable.
Lumisoft.net has both IMAP client and server code that you can use.
I've used it to download email from Gmail. The object model isn't the best, but it is workable, and seems to be rather flexible and stable.
Here is the partial result of my spike to use it. It fetches the first 10 headers with envelopes, and then fetches the full message:
using (var client = new IMAP_Client())
{
client.Connect(_hostname, _port, _useSsl);
client.Authenticate(_username, _password);
client.SelectFolder("INBOX");
var sequence = new IMAP_SequenceSet();
sequence.Parse("0:10");
var fetchItems = client.FetchMessages(sequence, IMAP_FetchItem_Flags.Envelope | IMAP_FetchItlags.UID,
false, true);
foreach (var fetchItem in fetchItems)
{
Console.Out.WriteLine("message.UID = {0}", fetchItem.UID);
Console.Out.WriteLine("message.Envelope.From = {0}", fetchItem.Envelope.From);
Console.Out.WriteLine("message.Envelope.To = {0}", fetchItem.Envelope.To);
Console.Out.WriteLine("message.Envelope.Subject = {0}", fetchItem.Envelope.Subject);
Console.Out.WriteLine("message.Envelope.MessageID = {0}", fetchItem.Envelope.MessageID);
}
Console.Out.WriteLine("Fetching bodies");
foreach (var fetchItem in client.FetchMessages(sequence, IMAP_FetchItem_Flags.All, false, true)
{
var email = LumiSoft.Net.Mail.Mail_Message.ParseFromByte(fetchItem.MessageData);
Console.Out.WriteLine("email.BodyText = {0}", email.BodyText);
}
}
There is no .NET framework support for IMAP. You'll need to use some 3rd party component.
Try Mail.dll email component, it's very affordable and easy to use, it also supports SSL:
using(Imap imap = new Imap())
{
imap.ConnectSSL("imap.company.com");
imap.Login("user", "password");
imap.SelectInbox();
List<long> uids = imap.Search(Flag.Unseen);
foreach (long uid in uids)
{
string eml = imap.GetMessageByUID(uid);
IMail message = new MailBuilder()
.CreateFromEml(eml);
Console.WriteLine(message.Subject);
Console.WriteLine(message.Text);
}
imap.Close(true);
}
Please note that this is a commercial product I've created.
You can download it here: https://www.limilabs.com/mail.
MailSystem.NET contains all your need for IMAP4. It's free & open source.
(I'm involved in the project)
the source to the ssl version of this is here: http://atmospherian.wordpress.com/downloads/
Another alternative: HigLabo
https://higlabo.codeplex.com/documentation
Good discussion: https://higlabo.codeplex.com/discussions/479250
//====Imap sample================================//
//You can set default value by Default property
ImapClient.Default.UserName = "your server name";
ImapClient cl = new ImapClient("your server name");
cl.UserName = "your name";
cl.Password = "pass";
cl.Ssl = false;
if (cl.Authenticate() == true)
{
Int32 MailIndex = 1;
//Get all folder
List<ImapFolder> l = cl.GetAllFolders();
ImapFolder rFolder = cl.SelectFolder("INBOX");
MailMessage mg = cl.GetMessage(MailIndex);
}
//Delete selected mail from mailbox
ImapClient pop = new ImapClient("server name", 110, "user name", "pass");
pop.AuthenticateMode = Pop3AuthenticateMode.Pop;
Int64[] DeleteIndexList = new.....//It depend on your needs
cl.DeleteEMail(DeleteIndexList);
//Get unread message list from GMail
using (ImapClient cl = new ImapClient("imap.gmail.com"))
{
cl.Port = 993;
cl.Ssl = true;
cl.UserName = "xxxxx";
cl.Password = "yyyyy";
var bl = cl.Authenticate();
if (bl == true)
{
//Select folder
ImapFolder folder = cl.SelectFolder("[Gmail]/All Mail");
//Search Unread
SearchResult list = cl.ExecuteSearch("UNSEEN UNDELETED");
//Get all unread mail
for (int i = 0; i < list.MailIndexList.Count; i++)
{
mg = cl.GetMessage(list.MailIndexList[i]);
}
}
//Change mail read state as read
cl.ExecuteStore(1, StoreItem.FlagsReplace, "UNSEEN")
}
//Create draft mail to mailbox
using (ImapClient cl = new ImapClient("imap.gmail.com"))
{
cl.Port = 993;
cl.Ssl = true;
cl.UserName = "xxxxx";
cl.Password = "yyyyy";
var bl = cl.Authenticate();
if (bl == true)
{
var smg = new SmtpMessage("from mail address", "to mail addres list"
, "cc mail address list", "This is a test mail.", "Hi.It is my draft mail");
cl.ExecuteAppend("GMail/Drafts", smg.GetDataText(), "\\Draft", DateTimeOffset.Now);
}
}
//Idle
using (var cl = new ImapClient("imap.gmail.com", 993, "user name", "pass"))
{
cl.Ssl = true;
cl.ReceiveTimeout = 10 * 60 * 1000;//10 minute
if (cl.Authenticate() == true)
{
var l = cl.GetAllFolders();
ImapFolder r = cl.SelectFolder("INBOX");
//You must dispose ImapIdleCommand object
using (var cm = cl.CreateImapIdleCommand()) Caution! Ensure dispose command object
{
//This handler is invoked when you receive a mesage from server
cm.MessageReceived += (Object o, ImapIdleCommandMessageReceivedEventArgs e) =>
{
foreach (var mg in e.MessageList)
{
String text = String.Format("Type is {0} Number is {1}", mg.MessageType, mg.Number);
Console.WriteLine(text);
}
};
cl.ExecuteIdle(cm);
while (true)
{
var line = Console.ReadLine();
if (line == "done")
{
cl.ExecuteDone(cm);
break;
}
}
}
}
}
LumiSoft.ee - works great, fairly easy. Compiles with .NET 4.0.
Here are the required links to their lib and examples.
Downloads Main:
http://www.lumisoft.ee/lsWWW/Download/Downloads/
Code Examples:
are located here: ...lsWWW/Download/Downloads/Examples/
.NET:
are located here: ...lsWWW/Download/Downloads/Net/
I am putting a SIMPLE sample up using their lib on codeplex (IMAPClientLumiSoft.codeplex.com). You must get their libraries directly from their site. I am not including them because I don't maintain their code nor do I have any rights to the code. Go to the links above and download it directly. I set LumiSoft project properties in my VS2010 to build all of it in .NET 4.0 which it did with no errors.
Their samples are fairly complex and maybe even overly tight coding when just an example. Although I expect that these are aimed at advanced level developers in general.
Their project worked with minor tweaks. The tweaks: Their IMAP Client Winform example is set in the project properties as "Release" which prevents VS from breaking on debug points. You must use the solution "Configuration Manager" to set the project to "Active(Debug)" for breakpoints to work. Their examples use anonymous methods for event handlers which is great tight coding... not real good as a teaching tool. My project uses "named" event method handlers so you can set breakpoints inside the handlers. However theirs is an excellent way to handle inline code. They might have used the newer Lambda methods available since .NET 3.0 but did not and I didn't try to convert them.
From their samples I simplified the IMAP client to bare minimum.

Categories