-
Notifications
You must be signed in to change notification settings - Fork 462
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # 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.