Win32 API: ReadFile timeout - winapi

How can I set timeout for ReadFile and WriteFile operations,
When using interprocess pipes?

You have to use the asynchronous version of the function, by specifying FILE_FLAG_OVERLAPPED.
When a timeout is reached you can call CancelIO with the file handle.

Related

Can a OVERLAPPED read on a file handle complete synchronously?

When I'm doing a OVERLAPPED read on a file handle I usually handle both cases of completeion: ReadFile immediately returns TRUE or it returns FALSE and GetLastError() returns ERROR_IO_PENDING. But is this really necessary ? Will a OVERLAPPED read never complete synchonously ? Maybe the data is already in the cache and can rapidly provided to the ReadFile call synchronously.

WinHTTP over HTTP/2 with multiplexing

I'm wondering if it is possible with the Windows API WinHTTP to use HTTP/2 multiplexing (multiple requests over one TCP connection). If so, is there example code how to archieve this?
I found this message from Microsoft (https://learn.microsoft.com/en-us/windows/win32/winhttp/about-winhttp):
Caution
WinHTTP is not reentrant except during asynchronous completion callback. That is, while a thread has a call pending to one of the WinHTTP functions such as WinHttpSendRequest, WinHttpReceiveResponse, WinHttpQueryDataAvailable, WinHttpSendData, or WinHttpWriteData, it must never call WinHTTP a second time until the first call has completed. One scenario under which a second call could occur is as follows: If an application queues an Asynchronous Procedure Call (APC) to the thread that calls into WinHTTP, and if WinHTTP performs an alertable wait internally, the APC can run. If the APC routine happens also to call WinHTTP, it reenters the WinHTTP API, and the internal state of WinHTTP can be corrupted.
That's why I'm not sure if asynchronous calls of WinHttpReadData are possible.
I recently found out about WinHTTP's HTTP2 support and also wondered if full multiplexing was possible, as there is pretty much no documentation about it. Since the request / response in synchronous mode does not support sending a second request without reading the first one, I rearchitected my application to use the asynchronous mode, and issued multiple requests at once with the following options:
const DWORD tlsProtocols = WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2 |
WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_3;
const DWORD enableHTTP2Flag = WINHTTP_PROTOCOL_FLAG_HTTP2;
const DWORD decompression = WINHTTP_DECOMPRESSION_FLAG_ALL;
HINTERNET hSession = WinHttpOpen(L"WinHttp Test",
WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS,
WINHTTP_FLAG_ASYNC);
WinHttpSetOption(hSession, WINHTTP_OPTION_SECURE_PROTOCOLS,
(LPVOID)&tlsProtocols, sizeof(tlsProtocols));
WinHttpSetOption(hSession, WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL,
(LPVOID)&enableHTTP2Flag, sizeof(enableHTTP2Flag));
WinHttpSetOption(hSession, WINHTTP_OPTION_DECOMPRESSION,
(LPVOID)&decompression, sizeof(decompression));
WinHttpSetStatusCallback(hSession, WinhttpStatusCallback,
WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS, 0);
HINTERNET hConnect = WinHttpConnect(hSession,
L"example.com",
INTERNET_DEFAULT_HTTPS_PORT, 0);
Despite only calling WinHttpConnect a single time, issuing multiple requests with WinHttpOpenRequest caused WinHTTP to internally open a new connection to the target server, which suggests that multiplexing is unfortunately not implemented.

Named pipe in windows, difference between FILE_FLAG_OVERLAPPED and PIPE_NOWAIT

I am using named pipe in windows and confused about the difference between FILE_FLAG_OVERLAPPED and PIPE_NOWAIT which are parameters set in CreateNamedPipe ,I set parameters like this.
HANDLE hPipe = CreateNamedPipe(
lpszPipename, // pipe name
PIPE_ACCESS_DUPLEX | // read/write access
FILE_FLAG_OVERLAPPED, // overlapped mode
PIPE_TYPE_MESSAGE | // message-type pipe
PIPE_READMODE_MESSAGE | // message read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // unlimited instances
BUFSIZE * sizeof(TCHAR), // output buffer size
BUFSIZE * sizeof(TCHAR), // input buffer size
PIPE_TIMEOUT, // client time-out
NULL); // default security attributes
the ConnectNamedPipe return immediately and I get ERROR_IO_PENDING from GetLastError.With a nonblocking-wait handle, the connect operation returns zero immediately, and the GetLastError function returns ERROR_IO_PENDING.However the MSDN tells:
With a nonblocking-wait handle, the connect operation returns zero immediately, and the GetLastError function returns ERROR_PIPE_LISTENING.
so, what does nonblocking-wait mean, PIPE_NOWAIT or FILE_FLAG_OVERLAPPED, thanks a lot!
PIPE_NOWAIT mean that Nonblocking mode is enabled on handle. In this mode, ReadFile, WriteFile, and ConnectNamedPipe always completed immediately.
the FILE_FLAG_OVERLAPPED mean asynchronous mode is enabled on handle. If this mode is enabled, all not synchronous io [1] operations always return immediately.
so FILE_FLAG_OVERLAPPED vs PIPE_NOWAIT - this is return immediately vs completed immediately.
completed immediately (which include return immediately ) mean that io operation is already completed when api return. but visa versa not true. if operation return immediately this not mean that operation is completed already. if operation still not completed ntapi return code STATUS_PENDING. win32 api in such situations usual set last error to ERROR_IO_PENDING.
exist 3 way determinate when io operation completed in case asynchronous handle mode.
bind handle to IOCP (via CreateIoCompletionPort or
BindIoCompletionCallback or CreateThreadpoolIo). as result when
io complete - pointer to OVERLAPPED which we pass to io call -
will be queued back to IOCP (in case BindIoCompletionCallback or
CreateThreadpoolIo system yourself create IOCP and listen on it
and call our registered callback, when pointer to OVERLAPPED will
be queued to IOCP)
some win32 api such ReadFileEx or WriteFileEx and all ntapi let
specify APC completion routine which will be called in context of
thread, which begin io operation, when io operation is completed.
thread must do alertable wait in this case. this wait is not
compatible with bind handle to IOCP (we can not use APC routine in
api call if file handle binded to IOCP - system return invalid
parameter error)
we can create event and pass it to api call (via
OVERLAPPED::hEvent) - in this case this event will be reset by
system when io operation begin and set to signaled state when io
operation is completed. unlike first 2 option in this case we have
no additional context (in face pointer to OVERLAPPED) when io
operation is completed. usually this is worst option.
[1] exist some io operations which is always synchronous api. for example GetFileInformationByHandleEx, SetFileInformationByHandle. but almost io operations is not synchronous io. all this io operations take pointer to OVERLAPPED as parameter. so if no pointer to OVERLAPPED in api signature - this is synchronous api call. if exist - usually asynchronous (exception CancelIoEx for example where pointer to overlapped is related not to current operation but to previous io operation which we want cancel). in particular ReadFile, WriteFile, DeviceIoControl, ConnectNamedPipe( internally this is call DeviceIoControl with FSCTL_PIPE_LISTEN) ) is not synchronous io api

How is it possible to repeatedly read from a NamedPipe in Windows?

How is it possible to repeatedly read from a NamedPipe in Windows? I get an 109 error, saying it could not open pipe, if I have a ReadFile() function after another ReadFile() function.
of course this is possible and need do after your pipe is connected and until disconnect. 109 this is ERROR_BROKEN_PIPE - you got this error in ReadFile when another end is close pipe handle, by call CloseHandle. in this case you need call DisconnectNamedPipe and then wait for new client by call ConnectNamedPipe. after connection is complete - you need just call ReadFile , in read completion again call ReadFile and so on until disconnect - some error returned. if you got error ERROR_PIPE_NOT_CONNECTED in ReadFile (just or in completion) this mean that remote end call DisconnectNamedPipe - your pipe already disconnected, so you can skip call to DisconnectNamedPipe and just call ConnectNamedPipe.

server using an overlapped named pipe : how to use GetOverlappedResult() with ReadFile()?

I have written a server and a client that are using an overlapped named pipe. My problem is mainly with Readfile() and GetOverlappedResult().
Note that this program is a test code. It will be integrated later in a framework (I'm porting linux code to unix that uses AF_UNIX adress family for socket connections)
I describe the server part. I have 2 threads :
1) the main thread opens an overlapped named pipe, then loop over WaitForMultipleObjects(). WaitForMultipleObjects() waits for 3 events: the 1st one waits for a client to connect. The 2nd allows me to cleanly quit the program. The 3rd is signaled when an operation is pending in ReadFile().
2) The second thread is launched when the client is connected. It loops over ReadFile().
Here is the server code:
http://pastebin.com/5rka7dK7
I mainly used MSDN doc (named pipe server using overlapped I/O, named pipe client), the SDK, and other doc on internet, to write that code. Look in [1] for the client code. The client code needs some love, but for now, I focus on making the server working perfectly.
There are 4 functions in the server code (i forget the function that display error messages):
a) svr_new: it creates the overlapped named pipe and the 3 events, and calls ConnectNamedPipe()
b) svr_del frees all the resources
c) _read_data_cb: the thread that calls ReadFile()
d) the main() function (the main thread), which loops over WaitForMultipleObjects()
My aim is to detect in _read_data_cb() when the client disconnects (ReadFile() fails and GetLastError() returns ERROR_BROKEN_PIPE) and when data comes from the client.
What I don't understand:
Should I call GetOverlappedResult() ?
If yes, where ? When ReadFile() fails and GetLastError() returns ERROR_IO_PENDING (line 50 of the paste) ? When WaitForMultipleObjects() returns (line 303 of the paste, I commented the code there) ? Somewhere else ?
I do a ResetEvent of the event of ReadFile() when WaitForMultipleObjects() returns (line 302 of the paste). Is it the correct place to call it ?
With the code I pasted, here is the result if the client sends these 24 bytes (the ReadFile() buffer is of size 5 bytes. I intentionnaly set that value to test what to do if a client sends some data larger than the ReadFile() buffer)
message : "salut, c'est le client !"
output:
$ ./server.exe
waiting for client...
WaitForMultipleObjects : 0
client connected (1)
WaitForMultipleObjects : 2
* ReadFile : 5
WaitForMultipleObjects : 2
* ReadFile : 5
WaitForMultipleObjects : 2
* ReadFile : 5
WaitForMultipleObjects : 2
* ReadFile : 5
WaitForMultipleObjects : 2
* ReadFile : 4
Note: WaitForMultipleObjects() can be called less than that, it seems random.
So, in my code, I do not call getOverlappedResult(), ReadFile() succeeds (il reads 5*4 + 4 = 24 bytes), but I don't know when the read operation has finished.
Note: I I add a printf() when ReadFile() fails with ERROR_IO_PENDING, that printf() is called indefinitely.
In addition, the client sends 2 messages. The one above, and another one 3seconds later. The 2nd message is never read and ReadFile() fails with the error ERROR_SUCCESS... (so to be precise, ReadFile() returns FALSE and GetLastError() returns ERROR_SUCCESS)
So, I'm completely lost. I have searched hours on Internet, in MSDN, in the SDK code (Server32.c and Client32.c). I still do not know what to do in my specific case.
So, ca someone explain me how to use GetOverlappedResult() (if I have to use it) to know how to check if the read operation finished, and where ? And even, if someone can fix my code :-) I gave the code so that everyone can test it (i find a lot of doc on internet, but it is almost always not precise at all :-/ )
thank you
[1] http://pastebin.com/fbCH2By8
Take a look at I/O Completion Ports. In my opinion it's the most efficient way to receive and handle notifications about overlapped operations in Windows. So basically you will need to use GetQueuedCompletionStatus and GetQueuedCompletionStatusEx in blocking and non-blocking mode when you're ready to process new completion events, instead of calling GetOverlappedResult from time to time. As a matter of fact, you can even get rid of WaitForMultipleObjects completely.
Also, which flavor of Unix are you targeting? In Solaris there's a very similar abstraction. Check out man port_create.
Unfortunately, there's nothing similar in Linux. Signals (including real-time) can be used to some extent as waitable completion objects, but they are not as comprehensive as the ports in Windows and Solaris.

Resources