-
-
Notifications
You must be signed in to change notification settings - Fork 49
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
Unify socket datatypes #250
Unify socket datatypes #250
Conversation
Looks good to me so far, I don't have any concerns other than minor things I'll comment. |
src/control.cc
Outdated
// remove required mark, stop if not required by dependents | ||
if (do_pin) service->pin_stop(); | ||
service->stop(false); | ||
services->process_queues(); | ||
if (service->get_state() == service_state_t::STOPPED) ack_buf[0] = DINIT_RP_ALREADYSS; | ||
break; | ||
default: | ||
// can't get here (hopefully) | ||
// supreses compiler warning about unused (-Wswitch) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please keep the comment to a minimum - since this is just for suppressing a warning, as little noise as possible is preferable. I suggest:
// avoid warning for unhandled values in switch/case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
src/includes/control-datatypes.h
Outdated
|
||
#include <cstdint> | ||
|
||
namespace dinit_ctypes { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ctypes
sounds a bit too close to the existing character types (std::ctype
), maybe dinit_cptypes
or dinit_cp_types
(for "command protocol types")?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems reasonable to avoid confusion. it's dinit_cptypes now
Just the two comments, otherwise looks good, thanks! |
33cf6ed
to
4109481
Compare
Thanks for the Feedback @davmac314 . I've continued refactoring in the other datatypes used in communication in the same way. I think by now i covered most of them. To be honest, I have some difficulties reading/understanding the protocol related code. It feels a bit 'fragile' with all the hardcoded values/lengths in different places. Most of it should be avoidable with some rework using sizeof/types. Or we could move the static parts of the protocol into standard layout type structs? |
It is slightly tricky code. A lot of it already uses Using regular structs is a bit less simple, since you'd need to make sure they were exactly compatible with the current protocol. Standard C++ has no way to specify a packed struct as far as I know, so this would be only be possible where the packet format already matches standard layout. If you could keep within those constraints I'm happy for such changes, but I think that should be part of a second change set (not part of this PR). |
src/includes/control-datatypes.h
Outdated
using cp_info_t = uint8_t; | ||
using srvname_len_t = uint16_t; | ||
using envvar_len_t = uint16_t; | ||
using sig_num_t = int32_t; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one (sig_num_t
) isn't correct, a signal number is an int
and not guaranteed to be 32-bit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I'm aware that it is not guaranteed to be 32-bit.
The question here would be do we want the protocol to be stable (even across architectures/systems) so it could be used over system boundaries (e.g. over network and/or forwarded to container/vm) ? In that case I would propose to leave it be fixed to 32-bit for the protocol and cast to int in the application. When there is a system, where int is not 32-bit then we may need to handle the conversion in dinitctl differently with an additional check, warning or error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've never had the goal of having the protocol be usable over system boundaries with heterogeneous systems. That requires more than just consistently sized values; you need to ensure consistent byte order, as well, and no struct declaration will do that for you.
I know that for the most part int32_t
will work just fine - 99% of the time it will be the case that sizeof(int) == sizeof(int32_t)
- and the remainder of the time signal numbers will probably not be bigger than 2^31 anyway. However, although it's a bit arbitrary, "works on any POSIX system" is a design goal and POSIX just says that signal numbers are int
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we should be in the clear here, as dinitctl handles the out_of_range exception if the specified signal number does not fit into a sig_num_t/int32_t. I've also added a cast from int32_t to int in control.cc, to make it more explicit. So when there is a system with different sizes it should not break, we just don't support signal numberrs >32bit atm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I may have been unclear. Sorry, but no - the signal number type needs to be int
. That's what POSIX declares it as.
as dinitctl handles the out_of_range exception if the specified signal number does not fit into a sig_num_t/int32_t
dinitctl uses std::stoi
to convert the signal number and that returns int
. It only throws out_of_range
if the number doesn't fit into an int
- it doesn't know anything about sig_num_t
/int32_t
. So if int
is larger than 32-bits there's no checking done in dinitctl that the provided signal number will fit in int32_t
. Just assigning the result to int32_t
will silently truncate it. (Or am I missing something?)
we just don't support signal numberrs >32bit atm
That would be a regression introduced with this change; currently, we do in fact support signal numbers >32 bit.
Everything else in the PR looks good!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah.. now I get it. I've reverted sig_num_t to be int. And I've checked again, that at least in the signal protocol code sizeof is used consequently, so it doesn't break the protocol on systems where sizeof(int) != 4.
src/control.cc
Outdated
// DINIT_RP_CVERSION, (2 byte) minimum compatible version, (2 byte) actual version | ||
char replyBuf[] = { DINIT_RP_CPVERSION, 0, 0, 0, 0 }; | ||
// cp_rply::CVERSION, (2 byte) minimum compatible version, (2 byte) actual version | ||
char replyBuf[] = { (cp_rply_t)cp_rply::CPVERSION, 0, 0, 0, 0 }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Casts should be to the destination type, which would be char
here, if needed at all.
(cp_rply_t)cp_rply::CPVERSION
is superfluous - the type of cp_rply::CPVERSION
is already cp_reply_t
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a cast is actually necessary here, because cp_rply::CPVERSION is of type cp_rply and not cp_rply_t, as it's an enum class.
I've looked it up and narrowing is also applied on static variables in initializer lists. The difference between casting to char or cp_rply_t type in this case would mostly be, that the compiler complains as soon as the value would be out of range for the target type (char, so >127 in this case). So I agree casting to (char) is probably best here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, you're correct, I misread it - still, casting to char is probably best, as you say.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've changed all relevant casts to (char).
src/control.cc
Outdated
@@ -76,7 +81,7 @@ bool control_conn_t::process_packet() | |||
auto sd_type = static_cast<shutdown_type_t>(rbuf[1]); | |||
|
|||
services->stop_all_services(sd_type); | |||
char ackBuf[] = { DINIT_RP_ACK }; | |||
char ackBuf[] = { (cp_rply_t)cp_rply::ACK }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly unnecessary/incorrect cast here, and a bunch throughout, I think.
src/control.cc
Outdated
} | ||
|
||
if (record == nullptr) { | ||
std::vector<char> rp_buf = { fail_code }; | ||
std::vector<char> rp_buf = { (cp_rply_t)fail_code }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(This one is causing build failure on Mac, clang is less lenient than gcc)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The underlying Problem seems to be, that when variables in the initilizer list are non static and the types are not the same then there is narrowing involved (which I don't fully understand). So casting to (char) works, but casting to (cp_rply_t)/(unsigned char) does not, as it's not clear if the value fits into char. So I've opted for casting to (char) in this case.
src/includes/control-cmds.h
Outdated
// Dinit control command packet types | ||
|
||
// Requests: | ||
enum class cp_cmd :dinit_cptypes::cp_cmd_t { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
formatting nit: can you put spaces around :
to match style elsewhere? i.e
enum class cp_cmd : dinit_cptypes::cp_cmd_t {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
Had a quick look through and added some comments, mostly looking good though, thanks! |
Yes i will create an new issue/PR for that to no clutter this PR to much.
Ah I didn't thought about packed structs not being standard c++. As we are currently only targeting compilers, which both (gcc and clang) support attribute((packed)) for structs we may use it? Could discuss this in a new Issue if you don't rule it out. Maybe also discuss other possible ways to optimize the protocol (handling). |
The remaining issues should be fixed now. Let me know if i missed something. I will squash the fixes into the related commits later. |
I don't want to limit support to just those compilers, but that's not necessarily a deal-breaker for using structs with In hindsight I should've just used standard layout structs from the beginning and then we wouldn't need |
src/includes/control.h
Outdated
@@ -15,6 +15,7 @@ | |||
#include <control-cmds.h> | |||
#include <service-listener.h> | |||
#include <cpbuffer.h> | |||
#include "control-datatypes.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi, I reviewd your work and it looks good, unless that control-datatypes.h
should included like this, I guess (with < >
not " "
):
#include <control-datatypes.h>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey, nice catch thanks. Functionally it should not make a difference in this case. But I've changed the includes of control-datatypes.h so they are consistent with the others in the corresponding file.
…class - also rename cmd_t and command_t (to cp_cmd_t and ctl_cmd) to reduce ambiguity
…essages as enum class
0ea8adc
to
33a2bc4
Compare
After fixing the signal type misunderstanding on my part and the includes, I squashed and rebased everything. It should be ready to merge after the pipeline checks are good. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, Thanks for contribution 😁
Thanks! Merged! |
Hey, I've started to work on getting the datatypes used in the socket communication unified. (See #179 ) The types are now defined in control-datatypes.h .
The process led to a little bit of refactoring of the control commands in control-cmds.h .
Before I go on with the other datatypes and control commands I would appriciate some feedback if you have the time @mobin-2008 or @davmac314 .