Once I have enabled O_NONBLOCK, and then call a non-blocking function, and after it returns some I/O error happens, how may I get to know that something bad has happened, and how to handle it?
You get the errors when they are ready for you to see them and you are ready to receive them.
sooner or later you end up calling read() or close() or whatever and that will give you the error.
Related
I want to send a message to the UI thread using PostMessage(), and I need to guarantee that the message is actually sent. However, PostMessage() can fail, so how should I handle the case when it fails, should I place it in a while loop that does not exit until PostMessage() returns success?
Since you can't guarantee delivery, as you indicate yourself, you need to instead decide how bad failure is. It sounds pretty critical, so I'd simply terminate the app. What else could you do?
This question already has an answer here:
Calling WSAGetLastError() from an IOCP thread return incorrect result
(1 answer)
Closed 7 years ago.
I'm writing a tcp server in Windows NT using completion ports to exploit asynchronous I/O.
I have a TcpSocket class, a TcpServer class and some (virtual functions) callbacks to call when an I/O operation is completed, e.g. onRead() for when a read is completed. I have also onOpen() for when the connection is established and onEof() for when the connection is closed, and so on.
I always have a pending read for the socket, so if the socket effectively gets data (the read will be completed with size > 0) it calls onRead(), instead if the client closes the socket from the client side (the read will be completed with size == 0) it calls onEof(), and the server is aware of when the client closes the socket with closesocket(server_socket); from its side.
All works gracefully, but I have noticed a thing:
when i call closesocket(client_socket); on the server's side endpoint of the connection, instead of the client side, (either with setting linger {true, 0} or not), the pending read will be completed as erroneous,
that is, the read size will not only be == 0, but also GetLastError() returns an error: 64, or 'ERROR_NETNAME_DELETED'. I have searched much about this on the web, but didn't find nothing interesting.
Then I asked myself: but is this a real error? I mean, can this really be considered an error?
The problem is that on the server side, the onError() callback will be called when I closesocket(client_socket); instead of the onEof(). So I thought this:
What about if I, when this 'ERROR_NETNAME_DELETED' "error" is received, call onEof() instead of onError() ?
Would that introduce some bugs or undefined behavior?
Another important point that made me ask this question is this:
When I have received this read completion with 'ERROR_NETNAME_DELETED', I have checked the OVERLAPPED
structure, in particular the overlapped->Internal parameter which contain the NTSTATUS error code
of the underlying driver. If we see a list of NTSTATUS error codes [ http://www.tenox.tc/links/ntstatus.html ]
we can clearly see that the 'ERROR_NETNAME_DELETED' is generated by the NTSTATUS 0xC000013B, which is an error, but it is called 'STATUS_LOCAL_DISCONNECT'. Well, it doesn't look like a name for an error. It seems more like `ERROR_IO_PENDING' which is an error, but also a status for a correct behavior.
So what about checking the OVERLAPPED structure's Internal parameter, and when this is == to 'STATUS_LOCAL_DISCONNECT' a call to the onEof() callback is performed? Would mess things up?
In addition, I have to say that from the server side, if I call DisconnectEx() before calling
closesocket(client_socket); I will not receive that error. But what about I don't want to call DisconnectEx() ? E.g. when the server is shutting down and doesn't want to wait all DisconnectEx() completions, but just want to close all client's connected.
It's entirely up to you how you treat an error condition. In your case this error condition is entirely to be expected, and it's perfectly safe for you to treat it as an expected condition.
Another example of this nature is when you call an API function but don't know how large a buffer to provide. So you provide a buffer that you hope will be big enough. But if the API call fails, you then check that the last error is ERROR_INSUFFICIENT_BUFFER. That's an expected error condition. You can then try again with a larger buffer.
It's up to you how to treat an error condition, but the question is a sign of potential problems in your code (from logic errors to undefined behavior).
The most important point is that you shouldn't touch SOCKET handle after closesocket. What do you do on EOF? It would be logical to closesocket on our side when we detect EOF, but that's what you cannot do in ERROR_NETNAME_DELETED handler, because closesocket already happened and the handle is invalid.
It's also profitable to imagine what happens if pending read completes (with real data available) just before closesocket, and your application detects it right after closesocket. You handle incoming data and... Do you send an answer to the client using the same socket handle? Do you schedule the next read on that handle? It would be all wrong, and there would be no ERROR_NETNAME_DELETED to tell you about it.
What happens if pending read completes with EOF in that very unfortunate moment, just before closesocket? If your regular OnEof callback is fired, and that callback does closesocket, it would be wrong again.
The problem you describe might hint at more serious problem if closesocket is done in one thread, while another thread waits for I/O completion. Are you sure that another thread is not calling WSARecv/ReadFile while the first thread is calling closesocket? That's undefined behavior, even though winsock makes it look as if it worked most of the time.
To summarize, the code handling completing (or failing) reads cannot be correct if it's unaware of socket handle being useless because it was closed. After closesocket, it's useful to wait for pending I/O completion because you can't reuse OVERLAPPED structure if you don't; but there's no point in handling this kind of completion as if it happened during normal operation, with socket being still open (error/status code is irrelevant).
You're calling the wrong method. You should be calling WSAGetLastError(). The result of GetLastError() after a Winsock API call is meaningless.
I have a boost::thread which performs synchronous reads on a boost::asio::serial_port. When I destroy an instance of the class which contains both, I want the thread to end gracefully even if its blocked in a read call. How can I do this?
Looking at the docs, I tried cancel, but it works only for asynchronous reads/writes. Then I tried close, but I got an exception and it wasn't the kind you can recover from. Perhaps using send_break or native_handle? (this is Windows and portability's not critical)
Update: I also tried to stop the io_service I passed to the serial port object's constructor, but the read wasn't unblocked.
Edit: The exception is actually "catchable", but I'd hate to put a try/catch block inside a destructor, and refactoring the code to do the shutdown process outside the destructor would trigger lots of changes in upper layers. So I'd only go for this solution if some Boost authority says there is no other way.
There is no way to unblock the synchronous read as you ask to.
There are two options:
close/shutdown the port and catch an exception, which was raised
use asynchronous reads and cancel them, when you shutdown your application
The first one, of course, is not a good idea, because you cannot distinguish terminating application from error.
On close, you say that you get an exception that 'wasn't the kind you can recover from'.
What does this mean?
The solution seems to be to catch the exception. Why cannot you do that?
For the case when you want to distinguish between an error and program termination, set a flag on program termination before the close. In the exception handler ( catch ) check the flag. If set, handle as program termination, else handle as error.
You say that you do not wish to place a try/catch block inside a destructor. This seems like an odd prejudice to me, but OK there are other ways.
You can allow the exception to propagate all the way to the topmost catch block that surrounds all your code, and handle it there. ( You do have such a try/catch block protecting your entire application, of course :-)
Other ways are also possible ... but boss just dropped by
I'm writing a VC++ application. Just for the sake of argument, what could cause the ResetEvent API to fail? The Microsoft documentation is not clear on this. Thanks.
Most commonly an invalid handle will cause this to fail. An invalid handle, in turn, could result from:
the handle being closed by another process or thread prematurely
passing gobbledy-gook to ResetEvent()
Passing a handle to a thing that isn't an even
Number 1 can often be avoided by creating a duplicate of the handle, by calling DuplicateHandle().
GetLastError() generally will tell you exactly what the problem is, or at least point you in the direction.
Without access to the source of Windows we can only guess. Here's my guess at what could go wrong:
The handle is not a valid handle to an event object.
The handle does not have the necessary access rights. The documentation states that the handle must have the EVENT_MODIFY_STATE access right.
The OS runs out of memory or has some other critical failure.
Reading the WINE source reveals no other explicit failure modes.
If a call to fread() returns 0 and ferror() indicates an error (vs. EOF), is it OK to retry the read or is it better to close and reopen the file?
I can't start over entirely -- the input file has been partially processed in a way that can't be undone (say I'm writing out a chunk at a time to a socket and, due to existing protocol, have no way of telling the remote end, "never mind, I need to start over").
I could fclose() and fopen() the file, fseek() past the data already processed, and continue the fread()-ing from there, but is all that necessary?
There's no "one size fits all" solution, since different errors can require different handling. Errors from fread() are unusual; if you're calling it correctly, an error may indicate a situation that has left the FILE* in a weird error state. In that case you're best off calling fclose(), fopen(), fseek() to get things back in a good state.
If you're coding for something that's happening, please mention the actual errors you're getting from ferror()...
You can give the clearerr function a look.
You can show the error to the user with perror() or strerror() and ask her is she wants to retry.
It's not mandatory for the implementation to provide such an error message, though. You should set errno to 0 before calling fread(); if it fails and errno is still 0 then no error information will be available.