BIND 10 #1593: Cleanup of socket creator code
BIND 10 Development
do-not-reply at isc.org
Thu Feb 16 14:12:19 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 |
-------------------------------------+-------------------------------------
Changes (by stephen):
* owner: stephen => jinmei
Comment:
> I've made a couple of additional commits for further style cleanups. I
believe they are non controversial.
No problems - they were some things I missed.
> 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 had thought that but had used isc::Exception for consistency - all code
in BIND 10 uses the same base exception type and same way of throwing
exceptions. The other thought was that although the failure is returned
via a status code to the environment, we might in future want to log the
reason for the failure via a call to syslog(), in which case a string
would be useful.
> ...in this case, since we explicitly catch the exception and don't use
the what() string anyway, it seems we can simply define
!SocketCreatorError (and its derived classes) as independent classes (not
even derived from std::exception).
In fact there is no need even to define !SocketCreatorError; we could just
throw (and catch) an "int".
I don't mind either way - it depends if you think the arguments above
outweigh the arguments for changing them.
> I'd like to avoid using reinterpret_cast unless there's absolutely no
other alternative (and when we know what we are doing) such as for
converting integer to a pointer so we can always be aware of where exactly
we are using this beast. I'd suggest extending the existing pointer
conversion utility in lib/util/io and using it (attaching a patch). In
this case this conversion should actually be totally valid because we are
using sockaddr* just as an opaque type.
The code that was replaced was similar to your patch, i.e.
{{{
A* a;
B* b = static_cast<B*>(static_cast<void*>(a));
}}}
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.
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.
> 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.
> We could avoid having a mutable variable, although in this case it may
be a matter of taste
For historical reasons I prefer functions to have one entry point and one
exit point. But in this case the code is so trivial it doesn't really
matter so I've adopted your suggestion.
> 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.
> 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:
I did this for the suggested getFamily() (renamed to getSocketType() to
avoid confusion with the address family) and getErrorCode(). (Incidentally
I used a mutable type (c.f. your comments on main.cc) to avoid compiler
warnings in getSocketType(), as protocolError() does not return. Although
not strictly necessary for getErrorCode() - the compiler recognises that
isc_throw will not return - it was used to emphasise the similarity of the
code structure to that of getSocketType().)
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.
> 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.
--
Ticket URL: <http://bind10.isc.org/ticket/1593#comment:10>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development
More information about the bind10-tickets
mailing list