Connectionless named pipes on windows - c++

What I want to do is create a named pipe server that routes messages between connected peers. On Windows it seems that you first have to create a pipe and then connect it to a client and then you read from the connected client pipe to get the message you want and then that handle is bound to that client and you have to create a new named pipe. Is there no way to easily multiplex all the clients into one handle so I don't have to read from each client separately? To write to the clients from the server you obviously have to use the clients’ handle. Maybe the server can close the connection every time it has processed a request but that seems a bit unnecessarily wasteful. I would rather avoid implementing my own named pipes with shared memory...

"you first have to create a pipe and then connect it to a client"
Not exactly. The server process creates the pipe, but the client connects itself. Also, the client can try to connect and block if the server hasn't yet created the pipe.
"you read from the connected client pipe to get the message you want and then that handle is bound to that client". True. Doesn't stop you from immediately waiting for the next client.
"Is there no way to easily multiplex all the clients into one handle?". No, that would defeat the point of the HANDLE. That's the bit you need to demultiplex the clients.
What you seem to miss is that you can set the number of pipe instances to PIPE_UNLIMITED_INSTANCES, and read all of them using a shared LPOVERLAPPED_COMPLETION_ROUTINE callback. The callback will tell you which HANDLE and thus which pipe has data available.

Related

Multiple writes on same socket c++

I'm currently trying to develop a server and some clients which communicate with each other using something like a proxy in the middle. The "proxy" will have sockets opened to every client and server on the system. This means that I'm currently using threads to keep all the connections opened. Every time a client decides to send a message it uses its socket with the proxy and sends the message. Then the proxy will propagate the message to every other node using the respective socket.
As you can see, a node can be receiving messages by having the proxy writing on the socket or a node may want to send messages by writing on the socket.
How do I guarantee that the content in the socket does not get overwritten ? Do I have to use mutexes to lock the access to the socket ? What is a good practice to solve this problem ?
Connections are bi-directional. Content going one way does not overwrite content going the other way. No mutex is needed for this.
Besides, you couldn't use a mutex anyway, as both sides of the connection are separate.

the use of windows completion port in named pipe

I need to transfer data between processes, I have a local server process and multiple clients process, they may send data and receive data at the same time.I create the namedpipe and CreateIoCompletionPort in server. And when the client CreateFile , the GetQueuedCompletionStatus will return which is what I expect, however, when the client writefile, the server cannot get Completion port package, I want the server to be notified when client come , out and send message, how should I do?
I know a little about the PostQueuedCompletionStatus function which can notify the completion port but I cannot get the Completion port handle in client process, could anyone tell me the common implementation, thanks!

Is it possible to change the ULONG_PTR completion key associated to an HANDLE in Windows I/O Completion Ports?

I associate an HANDLE "h_server" that I create with CreateNamedPipe() with an I/O Completion Port, and
for the completion key I use a function pointer: namedpipe_server_completion_routine().
Now, when a named pipe client connection request triggers, that HANDLE "h_server" became the client endpoint
in the named pipe server application, so I should change its I/O Completion Key to another kind of routine pointer, the one that completes I/O, Read, Write etc, io_arrival_completion_routine(), which is different from the named pipe server completion routine.
I thought to call again CreateIoCompletionPort() with the new completion key on that HANDLE, but it seems not working, so there is a way to change that key? Maybe with some hacks with DuplicateHandle or something?
If not, how I could solve this?
NOTE: this problem is only present with named pipe servers, because AcceptEx() works in a different way: with tcp servers, when a connection arrives, you basically got a new HANDLE for the client endpoint on the server, so you can associate that new HANDLE with the io completion port and the correct completion key as the correct io_arrival_completion_routine(), while the HANDLE of the tcp server associated with the tcp_server_completion_routine() will remain correct, and its unique role will be to listen for new connections.
Change the completion key from being a pointer to a function to being a pointer to a data block. This data block can then include whatever status information you need.
In the simplest case the data block would just contain the function pointer you're currently trying to use as the completion key.

How to use waitformultipleobject in C++

I am trying to write a code that will wait for client connections. As soon as it gets connected to a client, it should start reading a file and send it.
I need to have notifications for the socket handles, that is if connection gets lost from client side it will notify me so that I can try to reconnect.
If a connection is lost, it is up to the client side to reconnect. Servers do not connect or reconnect to clients.
If your server is simply dispensing a file, all you need to do is to accept connections and pass them to a handler that will invoke TransmitFile() at some point and clean up.
I am assuming the parts about waiting for client connections and sending a file are just for clarification and you already got that working. If not, there are lots of tutorials on sockets and file I/O out there.
In your case, detecting whether or not a client is still connected should be simple. Since your server is sending a file as soon as the connection is made, the client will start reading from the socket as soon as it is open. The read-function blocks, as long as the connection is open and no data was received. If the connection is closed, it will return having read 0 bytes. At that point you know, that the connection was terminated and you can try to reconnect.
If you are not permanently reading from the socket but keeping it open for future communication, you should look into the select-function, which allows monitoring one or more sockets and notifies you, as soon as one of them has an update (for example new data available or connection closed)

How to detect client connection to a named pipe server using overlapped I/O?

I was studying the MSDN examples of using named pipes:
Named pipe server using overlapped I/O
Named pipe client
The server easily detects when the client is disconnected and creates a instance of a named pipe. But I cannot figure out how the server knows that a client is connected to a pipe before any data from client is sent.
Can server detect a connceted client before client sends any data?
If server calls DisconnectNamedPipe before client disconnects itself first, will this disconnect the client as well? Can server disconnect a client from a pipe without negotiating it with the client?
Not sure I understand the hang-up. The server calls ConnectNamedPipe to wait for a client connection. No data needs to be sent. Nor can it be sent, you cannot issue a ReadFile until a client is connected. Note that the SDK sample uses this as well.
If the server disconnects ungracefully (without notifying the client with some kind of message so it can close its end of the pipe) then the client will get an error, ERROR_PIPE_NOTCONNECTED (I think). There's little reason to rely on that for a normal shutdown, you need to do something reasonable when the pipe server process crashed and burned unexpectedly.
Beware that pipes are tricky to get right due to their asynchronous nature. Getting errors that are not actually problems is common and you'll need to deal with it. My pipe code deals with these errors:
ConnectNamedPipe: ERROR_PIPE_CONNECTED on connection race, ignore
FlushFileBuffers: race on pipe closure, ignore all errors
WaitNamedPipe: ERROR_FILE_NOT_FOUND if the timeout expired, translate to WAIT_TIMEOUT
CreateFile: ERROR_PIPE_BUSY if another client managed to grab the pipe first, repeat
Server works incorrectly when clients get ERROR_FILE_NOT_FOUND error during WaitNamedPipe() or/and CreateFile() calls. This error code means there no pipes with specified name available on server. You should create new pipe on server immediately after ConnectNamedPipe() call to avoid this issue.