Is my loop wrong ? Do I misuse ReadFile() and I/O completion port ? - winapi

I want to implement a server/client using named pipes (for IPC).I'm using async (overlapped) connections and I/O completion port (I searched a lot and it seems that it is the most efficient way to do that).
First here are the codes:
server: http://pastebin.com/XxeXdunC
and client: http://pastebin.com/fbCH2By8
The problem is in the server (i can improve the client but i will do that when the server works).
I use I/O completion port like that : basically, I run a thread in which I call ReadFile(). If it returns TRUE, I get all the data, if it returns FALSE, and the error is ERROR_IO_PENDING, I wait with GetQueuedCompletionStatus().
What is strange is that, even if I read all the data, the last ReadFile() call fails and the error is ERROR_IO_PENDING
The thread in which I call ReadFile() is beginning line 64 of the server code.
The client sends 24 bytes (the string "salut, c'est le client !") and the ReadFile() buffer is of length 5 bytes (to check how my server deals data that is larger than the Readfile() buffer)
The output is:
waiting for client...
WaitForMultipleObjects : 0
client connected (1)
ReadFile 1 msg (5 -> 05) : salut
ReadFile 2 msg (5 -> 10) : salut, c'e
ReadFile 2 msg (5 -> 15) : salut, c'est le
ReadFile 2 msg (5 -> 20) : salut, c'est le clie
ReadFile 2 msg (4 -> 24) : salut, c'est le client !
ReadFile2: ERROR_IO_PENDING
GQCIOS 0 255 003D3A18
ReadFile3: ERROR_IO_PENDING
ReadFile1: ERROR_IO_PENDING
GQCIOS 5 255 003D3A2C
ReadFile3: ERROR_IO_PENDING
ReadFile1: ERROR_IO_PENDING
GQCIOS 5 255 003D3A2C
ReadFile3: ERROR_IO_PENDING
ReadFile1: ERROR_IO_PENDING
GQCIOS 5 255 003D3A2C
ReadFile3: ERROR_IO_PENDING
ReadFile1: ERROR_IO_PENDING
GQCIOS 5 255 003D3A2C
ReadFile3: ERROR_IO_PENDING
ReadFile1: ERROR_IO_PENDING
GQCIOS 4 255 003D3A2C
ReadFile3: ERROR_IO_PENDING
ReadFile1: ERROR_IO_PENDING
What I do not understand is that even if I read all the data, ReadFile() still returns a pending operation (it's the "ReadFile2: ERROR_IO_PENDING" error message after the last "msg" output)
Is my loop wrong ? Do I misuse ReadFile() / GetQueuedCompletionStatus() ?
thank you

Where is your write related function? it seems that your code is in wrong order. In the _read_data_cb routine, GetQueuedCompletionStatus should be called first, then depending on the lpOverlapped parameter, the received data should be ready in the buffer that you specified in the ReadFile function. Since you're calling Readfile without checking whether OVERLAPPED is a overlapped structure for the send context or recv context, you're not getting the expected output. The following code should clear things up:
while(TRUE)
{
bReturnValue=GetQueuedCompletionStatus(pIOCPServer->m_pIOCP, &dwBytesTransferred,(DWORD *)pClient,reinterpret_cast<LPOVERLAPPED*>(&pOverlapped),INFINITE);
if(!bReturnValue)
{
if(NULL==pOverlapped)
continue;
else
break;
}
else
{
if(pOverlapped==NULL)
continue;
}
if(dwBytesTransferred==0)
break;
if(lpOverlapped==&(pClient->m_pRecvContext->overlapped))
pClient->handleRecvEvent(dwBytesTransferred)
else if(lpOverlapped==&(pClient->m_pSendContext->overlapped))
pClient->handleSendEvent(dwBytesTransferred)
}
...

Related

ReadFile and WriteFile with Overlapped IO result if not ERROR_IO_PENDING?

The docs for FILE_FLAG_OVERLAPPED on WriteFile() say you must provide OVERLAP and recommend NULL for lpNumberOfBytesWritten because value is misleading. However docs for GetOverlappedResult() say to only call if WriteFile() returned FALSE with ERROR_IO_PENDING. So that leaves the case where ReadFile() / WriteFile() complete in the API call itself. How are you supposed to get the number of bytes read/written? Do you presume it's the number requested? But WriteFile() says "When writing to a non-blocking, byte-mode pipe handle with insufficient buffer space, WriteFile returns TRUE with * lpNumberOfBytesWritten < nNumberOfBytesToWrite".
TIA!!
If hFile was opened with FILE_FLAG_OVERLAPPED The
lpNumberOfBytesWritten parameter should be set to NULL.
this is not true (mistake or lie). the lpNumberOfBytesWritten can be set to NULL, but not should. if I/O request complete synchronous with success in *lpNumberOfBytesWritten will be valid number of bytes.
note also that lpNumberOfBytes must not point to location which will be valid until operation is complete (like lpOverlapped) - it can point to local variable in function for example and you can exit from function before I/O is complete - and this is will be ok too. system simply copy InternalHigh from OVERLAPPED to *lpNumberOfBytes. so in pseudo code :
if (lpNumberOfBytes) *lpNumberOfBytes = (ULONG)lpOverlapped->InternalHigh;
obvivous correct value in *lpNumberOfBytes will be only if I/O already completed with success. so and can use it only in this case. system doesn't remember value of lpNumberOfBytes - because this it must be valid only during [Write|Read]File call but not during I/O active (which can be longer in case asynchronous I/O)
GetOverlappedResult we can call if I/O request complete synchronous with success (in case ReadFile or WriteFile, if thay return TRUE) of if pending returned. this api can not be called only in case I/O request just fail (ReadFile or WriteFile return FALSE and GetLastError() != ERROR_IO_PENDING)
so the best always pass not 0 lpNumberOfBytes to api and use it, if api complete just with success. otherwise use GetOverlappedResult or if say you use BindIoCompletionCallback - you direct got dwNumberOfBytesTransfered in callback.
so in conceptually can use next code:
inline ULONG BOOL_TO_ERROR(BOOL f)
{
return f ? NOERROR : GetLastError();
}
HANDLE hFile = CreateFile(*, FILE_GENERIC_READ, FILE_SHARE_READ, 0,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
UCHAR buf[0x200];
OVERLAPPED ov = {};
ULONG NumberOfBytesRead;
ULONG dwError = BOOL_TO_ERROR(ReadFile(hFile, buf, sizeof(buf), &NumberOfBytesRead, &ov));
switch (dwError)
{
case ERROR_IO_PENDING:
dwError = BOOL_TO_ERROR(GetOverlappedResult(hFile, &ov, &NumberOfBytesRead, TRUE));
if (dwError != NOERROR) goto __default;
[[fallthrough]];
case NOERROR:
DbgPrint("NumberOfBytesRead=%x\n", NumberOfBytesRead);
// use GetOverlappedResult(hFile, &ov, &NumberOfBytesRead, TRUE) here also possible
break;
__default:
default:
DbgPrint("dwError = %u\n", dwError);
}
CloseHandle(hFile);
}

GetOverlappedResult when ReadFile returns true

Can I use GetOverlappedResult to return the number of bytes read if ReadFile with OVERLAPPED IO returned true (meaning the result was never pending?)
yes. you can call GetOverlappedResult in this case.
in your concrete case, if ReadFile return true, mean that io operation already completed. the GetOverlappedResult from self side first of all check IO_STATUS_BLOCK at begin of OVERLAPPED . more concrete checked Internal (NTSTATUS Status) for STATUS_PENDING
The status code for the I/O request. When the request is issued, the
system sets this member to STATUS_PENDING to indicate that the
operation has not yet started. When the request is completed, the
system sets this member to the status code for the completed request.
if here not STATUS_PENDING (Status != STATUS_PENDING) GetOverlappedResult understand that io already completed. if it error status (Status < 0) convert it to win32 error and set last error, otherwise read InternalHigh (The number of bytes transferred for the I/O request. The system sets this member if the request is completed without errors.) and copy it to *lpNumberOfBytesTransferred.
so in your case - Status != STATUS_PENDING and Status >= 0 (because ReadFile return true) - and GetOverlappedResult just return true to you and set *lpNumberOfBytesTransferred = (DWORD)lpOverlapped->InternalHigh
If the operation completes synchronously you cannot use use GetOverlappedResult to query the result or the bytes read.
If, on the other hand, an operation is completed immediately, then &NumberOfBytesRead passed into ReadFile is valid for the number of bytes read. In this case, ignore the OVERLAPPED structure passed into ReadFile; do not use it with GetOverlappedResult or WaitForSingleObject.
See https://support.microsoft.com/en-gb/help/156932/asynchronous-disk-i-o-appears-as-synchronous-on-windows for details.

ReadFile named pipe after client closed other end

I have multithreaded app working quite well, except the following scenario:
Initially I read from pipe 16 bytes, then depending on the header I read the rest.
The problem is that sometimes client writes a message (say 300 bytes long) and then close connection.
My server receives first 16 bytes, then decide to get the rest 284 bytes, but ReadFile returns error 233 (No process is on the other end of the pipe.)
So, where are those 284 bytes go ? I suppose they should be in a pipe buffer or something.
Pipe created as usually like in all examples over the net:
HANDLE h= CreateNamePipe(
name, // 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
100000, // output buffer size
100000, // input buffer size
0, // client time-out
lpSecurityAttributes); // default security attributes
As WhozCraig noticed, client does not do FlushFileBuffers before DisconnectNamePIpe. Unfortunately.

Socket programming Update: recv returning -1, error = 10053

I'm implementing a TCP/IP application on Windows 7 that loops around a socket recv() call. For small amount of data (< 5 MB) it works fine, but for large data (>20 MB), the recv fails in between.
Details: My app needs to communicate with HTTP server running , both running on same machine, in this scenerio, tcp app is sending heavy data to HTTP server
It gives error = 2, recv returns 0.
Error 2 means ENOENT, but what does it means?. Does anyone know what this is (in regards to a socket) and how I can get around this?
msgLen = recv(s,msg,BUFFER_SIZE,0);
if(msgLen > 0)
{
// do processing
}
else
{
printf("\n no data received .... msgLen=%d",msgLen);
printf("\n no data received .... errno=%d",errno);
}
Update Code as per comment
msgLen = recv(s,msg,BUFFER_SIZE,0);
if(msgLen > 0)
{
// do processing
}
else if(msgLen == 0)
{
printf("\n sender disconnected");
}
else
{
printf("\n no data received .... msgLen=%d",msgLen);
printf("\n no data received .... errno=%d",WSAGetLastError());
}
The error I get now is:
Firstly, recv = 0 many times, i.e. sender disconnected;
Finally, recv returns -1, and error = 10053.
My TCP/IP application is sending data to HTTP Server. The same works fine with small data, but the issue comes with large amount of data. Is HTTP server getting time out?
When recv() returns 0, it means the other party disconnected gracefully (assuming that your requested buffer size is not 0). recv() only provides an error code when it returns SOCKET_ERROR (-1). On Windows, you have to use WSAGetLastError() to get the error code, not errno, eg:
msgLen = recv(s,msg,BUFFER_SIZE,0);
if(msgLen > 0)
{
// do processing
}
else if (msgLen == 0)
{
printf("\n sender disconnected");
}
else
{
printf("\n no data received .... error=%d",WSAGetLastError());
}
Also keep in mind that if you are using a non-blocking socket, the error code may be WSAEWOULDBLOCK, which is not a fatal error. You can use select() to detect when the socket has data and then attempt the recv() again.

Why does this SSL_pending call always return zero?

This code is for an HTTPS server using blocking sockets:
request := '';
start := gettickcount;
repeat
if SSL_pending(ssl) > 0 then
begin
bytesin := SSL_read(ssl, buffer, sizeof(buffer)-1);
if bytesin > 0 then
begin
buffer[bytesin] := #0;
request := request + buffer;
end
else break; // read failed
end; // pending
until (gettickcount - start) > LARGETIMEOUT;
// "request" is ready, though possibly empty
SSL_pending() always returns zero and the SSL_read() is never reached. If the SSL_pending() call is removed, SSL_read() is executed. Why doesn't SSL_pending() indicate how many bytes are available?
Note that if you call SSL_read() and the number of bytes returned is less than your buffer size, you've read everything and are done.
If the incoming data is larger than your buffer size, the first SSL_read() call fills the buffer, and you can repeat calling SSL_read() until you can't fill the buffer.
BUT if the incoming data is an exact multiple of your buffer size, the last chunk of data fills the buffer. If you attempt another SSL_read() thinking there might be more data on a blocking socket, it hangs indefinitely. Hence the desire to check SSL_pending() first. Yet that doesn't appear to work.
How do you avoid hanging on a final SSL_read()? (I can't imagine the answer is to go non-blocking, since that means you could never use SSL_read with blocking.)
UPDATE: The following works. Apparently SSL_pending() doesn't work until after the first SSL_read():
request := '';
repeat
bytesin := SSL_read(ssl, buffer, sizeof(buffer)-1);
if bytesin > 0 then
begin
buffer[bytesin] := #0;
request := request + buffer;
end
else break; // read failed
until SSL_pending(ssl) <= 0;
// "request" is ready, though possibly empty
You are using SSL_pending() the completely wrong way. OpenSSL uses a state machine, where SSL_pending() indicates if the state machine has any pending bytes that have been buffered and are awaiting processing. Since you are never calling SSL_read(), you are never buffering any data or advancing the state machine.
If the SSL_pending function returns a return code of 0, it does not necessarily mean that there is no data immediately available for reading on the SSL session. A return code of 0 indicates that there is no more data in the current SSL data record. However, more SSL data records may have been received from the network already. If the SSL_pending function returns a return code of 0, issue the select function, passing the file descriptor of the socket to check if the socket is readable. Readable means more data has been received from the network on the socket.

Resources