-
Notifications
You must be signed in to change notification settings - Fork 456
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Some improvements to the socket code. #1081
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1081 +/- ##
==========================================
- Coverage 24.95% 24.91% -0.05%
==========================================
Files 168 168
Lines 18072 18104 +32
==========================================
Hits 4510 4510
- Misses 13562 13594 +32 ☔ View full report in Codecov by Sentry. |
Yep, I've found the socket code over the years when I've needed to take a look at things always a bit confusing in terms of the same class handling client versus server plus tcp and udp all in one. Will take a look at the commits.
You did mention not being a native English speaker 😉 Should be "...that struck me..", like being struck by a bolt of lightning as opposed to stroking a cat. |
I have to confess that when I wrote the initial implementation of the telnet interface I kind of made it up as I went. It was the first time I wrote any socket code. Feels like a hundred years ago. 😊
|
Indeed but I'm wondering which would be the more painful ? A Swiss army knife class such as
Haha 😆 You've been warned ! |
I guess that's where we all are. I'm no socket/network code specialist either and I learn as I go. But note that the current code still looks very much like the code you wrote many years ago, that's not so bad for "made up" code ! |
I have just pushed another commit to this PR:
|
…ssage when relevant.
Another commit to the PR to check the returned value of socket functions and print an error message when |
…ive in order to avoid console flooding.
Following my previous commit, I now see that Windows is returning lots of errors "Socket error: A non-blocking socket operation could not be completed immediately" in In addition, the messages lack context (where the error message has been issued from ?) and are flooding the console. So I have pushed one last commit to add context to the messages and print them only if |
In terms of tons of "error messages" now, I think this particular case of printing/logging an error is misplaced and shouldn't be there. jsbsim/src/input_output/FGfdmSocket.cpp Lines 280 to 284 in 84768c7
So, in this case since we've set the socket for the telnet connection to be non-blocking, the return value of And in particular if the FDM is running at 120Hz and you have say a human sending intermittent telnet commands there are going to be thousands of these sorts of "error messages" logged in just say a 10s period when the human isn't sending a telnet command. So I would change this code to only log an error message along these lines (having to still deal with Windows vs Unix last error checking differences): if (num_chars == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK)
PrintSocketError("Receive - TCP data reception"); |
@seanmcleod Good point ! I have amended the code according to your feedback. |
Yep, looks good. One more thing 😉 As I mentioned in the original discussion - #1079 I'm pretty sure that the following block of code, although it can also be simplified, needs to be executed for Unix systems as well. jsbsim/src/input_output/FGfdmSocket.cpp Lines 293 to 304 in 7590e8d
In other words, in the case that So I'd suggest replacing that if (num_chars == 0) {
PrintSocketError("Receive - TCP data reception- Socket Closed. Back to listening");
closesocket(sckt_in);
sckt_in = INVALID_SOCKET;
} This would fix the issue that the user reported when running JSBSim on Mac (Unix based), i.e. killing the telnet connection with ctrl-c or equivalent as opposed to sending Actually, thinking about it, we probably want to perform this also in the case of |
It seems there is always one more thing with regards to the socket code 😉 So in the UDP case, in the same jsbsim/src/input_output/FGfdmSocket.cpp Lines 308 to 315 in 7590e8d
|
…uld block" + some further error management improvements.
@seanmcleod Just pushed another commit that implements your suggestions (both of them). I took this opportunity to add a check of the value returned by jsbsim/src/input_output/FGfdmSocket.cpp Line 306 in 92ebcca
I've also added some additional asserts in FGfdmSocket::Close() and FGfdmSocket::Reply() as both of these methods are using sckt_in which is only initialized for TCP sockets.
|
@bcoconni it looks good. |
Thanks for the detailed review, @seanmcleod |
While investigating the "socket" code to address the topics discussed in #1079, I have found a number of small details that could be improved. I don't think these will resolve the discussion #1079 but I'm pushing this PR nonetheless for the record.
Minor changes / documentation
FGfdmSocket
have actually very different purposes as one constructor is returning a socket for a client connection while the other one returns a socket for a server connection. To document that, I have added comments toFGfdmSocket.h
. Note that the documentation has been generated by an AI (GitHub Copilot) and reviewed by a non native English speaker (myself) so brace yourself before reading 😄connected=true
to a location that makes its purpose more obvious as the previous location of this line of code was misleadingly suggesting thatconnected=true
was indicating that the call toaccept()
had succeeded.FGInputSocket.cpp
, when the commandquit
is issued to JSBSim, the methodFGfdmSocket::Send()
is now called to return "Closing connection" instead of callingFGfdmSocket::Reply()
. This avoids displaying the promptJSBSim>
just after the message "Connection closed" which looks weird to me.Improvements to the error management
bind()
orlisten()
fail,FGfdmSocket
now closes the socketsckt
and sets it toINVALID_SOCKET
which is a good practice in order to release unused file descriptors to the OS (see StackOverflow Should I call close() on bind() or listen() error)~FGfdmSocket()
shutdownssckt_in
and closessckt
(in that order otherwise it crashes according to my tests) to release the file descriptors to the OS.recv
inFGfdmSocket::Receive()
is now enclosed in anif (Protocol == ptTCP) { ... }
as callingrecv
is meaningless for UDP sockets.sckt != INVALID_SOCKET
before callingsend
inFGfdmSocket::Send()
. Alsosend
is now usingsckt_in
if the socket is using the TCP protocol. Indeed this method is called from the classFGOutputSocket
which can define a socket with either protocol UDP or TCP.sckt != INVALID_SOCKET
before callingselect
inFGfdmSocket::WaitUntilReadable()
. Also I have added an assert to check thatProtocol == ptTCP
so that we are sure that this method is never called for a UDP socket. At the moment,FGfdmSocket::WaitUntilReadable()
is only called by the classFGInputSocket
which is guaranteed to be a TCP socket so the assert passes.