BIND 10 #1593: Cleanup of socket creator code

BIND 10 Development do-not-reply at isc.org
Thu Feb 16 19:48:59 UTC 2012


#1593: Cleanup of socket creator code
-------------------------------------+-------------------------------------
                   Reporter:         |                 Owner:  jinmei
  vorner                             |                Status:  reviewing
                       Type:  task   |             Milestone:
                   Priority:  major  |  Sprint-20120221
                  Component:         |            Resolution:
  Unclassified                       |             Sensitive:  0
                   Keywords:         |           Sub-Project:  Core
            Defect Severity:  N/A    |  Estimated Difficulty:  4
Feature Depending on Ticket:         |           Total Hours:  0
  Socket creator                     |
        Add Hours to Ticket:  0      |
                  Internal?:  0      |
-------------------------------------+-------------------------------------

Comment (by jinmei):

 Replying to [comment:10 stephen]:

 > > Using exceptions is probably a good idea, but maybe we'd avoid using
 isc_throw and isc Exception classes. isc::Exception relies on <string>,
 ...
 [...]
 > I don't mind either way - it depends if you think the arguments above
 outweigh the arguments for changing them.

 I'm personally okay with keeping isc::Exception with <string>.  Others
 (e.g. Michal) may have a different opinion, however, so my suggestion
 is to keep the current version for the purpose of this ticket and
 confirm the intent at bind10-dev.  Also, if we keep using it, I'd
 explicitly add dependency to libexception in the Makefile.am:
 {{{
 b10_sockcreator_LDADD +=
 $(top_builddir)/src/lib/exceptions/libexceptions.la
 }}}

 I suspect currently it happens to work because libutil_io internally
 adds this dependency.  But if the sock creator becomes a direct user
 of it, it's fragile to rely on the indirect dependency setup.

 > > I'd like to avoid using reinterpret_cast [...]
 > The code that was replaced was similar to your patch, i.e.
 {{{
 A* a;
 B* b = static_cast<B*>(static_cast<void*>(a));
 }}}

 Yes, I know.

 > In other words, going from a pointer to one type to a pointer to an
 incompatible type via a void* pointer.  I understand the point about
 sockaddr as an opaque type (so it is an "allowable" incompatible cast),
 but the same method could be used for an "invalid" incompatible cast, e.g.
 to end up having sockaddr* variable pointing to an int.  So I changed the
 code to use reinterpret_cast on the grounds that if it walks like a duck
 and it quacks like a duck...  Also, it is shorter and simpler to
 understand.

 I agree the above nested static_cast is almost equally evil as
 reinterpret_cast in that you could abuse it (and the intent is often
 unclear - whether the developer was confident it was actually safe or
 just tried to deceive the compiler).  The convertSockAddr() templates
 are an attempt to at least make the intent clearer: they are supposed
 to be used for only converting between compatible sockaddr variants
 when it's known to be safe, although the template interface does not
 prevent abuse.  If we want we could even perform static checker to
 enforce to specify the templated type explicitly and must be some
 sockaddr(_xxx).

 In that sense, it won't be much different if we add detailed comments
 on why we use reinterpret_cast and why it's actually safe in this
 specific case.  In fact, I'd like to propose doing so wherever we use
 reinterpret_cast in our code (and it would be checked in review) -
 that would discourage an easy use of really dangerous reinterpret_cast
 in development.  And, by reducing the number of cases where
 reinterpret_cast is used, we can more easily check if we follow this
 convention via a simple grep and eye-check.  If grep produces 100
 matches that would be more difficult.  For this reason I'd still
 prefer avoiding reinterpret_cast in this case.

 > An alternative that avoids a cast is a union:
 > {{{
 > union {
 >     sockaddr     addr;
 >     sockaddr_in  addr_in;
 >     sockaddr_in6 addr_in6;
 > };
 > }}}
 > This would emphasise that the different structs are alternative ways of
 representing the same data.  For the time being I have left the code as it
 is (with reinterpret_cast) but am happy to change it.

 Right, in the specific case of sockaddr variants, this is equally
 safe.  My concern with this approach is that it could convey a false
 sense of message that we could abuse union to deceive the compiler.
 Detailed comments about it may help discourage such attempts, though.

 Going back to the branch, I'd prefer avoiding reinterpret_cast
 somehow.  If you are okay with it and have a stronger preference on
 one of the alternatives, I'm okay with that if we can make it clearer
 why we do this, why it's safe in this specific case, and that the same
 workaround shouldn't easily be adopted just to deceive the compiler
 (especially if you use an alternative that is different from the
 existing convertSockAddr() framework that is dedicated for that kind
 of purpose); if you still think reinterpret_cast is the best among all
 approaches, I think we should discuss project-wide to reach consensus.

 > > adding comments to clarify the magic characters (these were a perfect
 example of 'read only code', which can be only understood by the original
 author) like this is good ... but I wonder we'd even make them even more
 reader-friendly by introducing more descriptive constant variables like
 this
 > Possible, but the REAME description of the protocol explicitly talks
 about the individual characters sent back.  To make it easier to relate
 that description to the code I would suggest that we leave the literal
 text as is.

 Okay.

 > > and while looking at it, I wonder whether this one is better than
 hardcoding 0 and 1:
 > {{{
 > run(stdin, stdout); // Read commands from stdin, output to stdout
 > }}}
 > stdin/stdout are FILE* variables, but I have altered it to use
 STDIN_FILENO and STDOUT_FILENO.

 Oops, I was confused.  Confirmed the revised code.

 > > suggestion: I wonder whether handleRequest() (btw I renamed it from
 handle_request to be more aligned with the coding guideline) if we changed
 it to something like this: [...]

 > The problem with the suggested getSockAddr() function is that the
 sockaddr pointer is a pointer to another data structure.  Either that
 would have to be allocated statically within getSockAddr() or allocated
 dynamically with the caller responsbile for deallocating it.  Either
 seemed to make the code more complicated so I left it as is.

 Okay.

 > > If you mean passing the FD through output_fd by "message/socket", I
 don't think it's correct. FDs are passed through a separate UNIX domain
 socket.
 > As I understand the fs_send code, it is done via the CMSG macros which
 "are used to create and access control messages (also called ancillary
 data) that are not a part of the socket payload" (cmsg(3) man page).
 output_fd appears to be the socket used for communication.  I have updated
 the header though.

 Oops, you're right, I was confused on this, too.  I didn't know we can
 pass FD via the interprocess channel with the stdin/stdout interfaces.
 So the original description was actually correct, but the revised
 version is also okay.

 Finally, I made a few more trivial style cleanups.

-- 
Ticket URL: <http://bind10.isc.org/ticket/1593#comment:11>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development


More information about the bind10-tickets mailing list