Tuesday, September 25, 2007
Abstraction for its own sake
This is a rather small and unfocused rant on unnecessary abstractions. It may be related to this wiki page on abstraction not scaling; it may not be (told you this was unfocused).
I'm in the process of writing the Sendmail interface for the greylist daemon, and as far as that goes, it's very simple for this application—it just requires the writing of four functions, one that's given the IP address of the remote SMTP server, one that's given the sender email address, one that's given the recipient email address, and one to clean up any resources allocated from the other functions.
Like I said, pretty easy and straightforward.
The oddness comes in the first function's definition. It's:
sfsistat xxfi_connect(SMFICTX *ctx,char *hostname,_SOCK_ADDR *hostaddr);
The _SOCK_ADDR
variable contains the IP address of the remote SMTP server. What is it? I
dunno. What does it contain? I dunno. All I care about is the actual
IP address, and I presume it's
somewhere in this variable (most likely a structure of some kind). But
there's no further API for pulling any useful information out of this
_SOCK_ADDR
.
Well, let's dive into the header files:
#ifndef _SOCK_ADDR # define _SOCK_ADDR struct sockaddr #endif /* ! _SOCK_ADDR */
For some reason, the writers of Sendmail felt it prudent to hide the
definition of the IP address
behind another name. Presumably to make their code more portable to other
non-BSD-derived
network stacks that don't use struct sockaddr
to store IP addresses.
But that does my code no good. I don't care about the hostname, I care about the IP address, yet without further information, I don't know exactly what I have. Is it the binary form of the address? How big? (there's IPv4, in which each address is 32 bits long, and IPv6, in which each address is 128 bits long) I had to dive into the header files to find out what exactly I'm given.
And it's not like the above definition of _SOCK_ADDR
is
wrapped around other #ifdef
's checking for various operating
systems or network stacks. The above definition is it! That's all
there is.
So I really have to wonder why they felt this further abstraction for their code was necessary. It seems to be abstraction for abstraction's sake. Here's a hint: you aren't going to need it.
Reason #98,333,323 why I hate control panels
[The following is a trouble ticket submitted by me into the Company Internal Trouble Ticket Queue System™. It should be of no real surprise to anyone here, but it still makes for decent blog fodder.]
I have the graylist sendmail module written, so I go to install it for the XXXXXXXXXXXXX domain. The initial module does nothing but log the requests and let the email through—I did the same for the postfix module to ensure that the module worked before hooking it up to the greylist daemon.
Anyway, I'm going to install the sendmail module for XXXXXXXXXXXXX. XXXXXXXXXXXXX is
on XXXXXXXXXXXXXXXXXX, which is a box managed by
Insipid
. Now, the
instructions for installing the sendmail module are easy—just modify
/etc/mail/sendmail.mc
with the following lines:
define(`_FFR_MILTER', `1')dnl. INPUT_MAIL_FILTER(`filter1', `S=unix:/tmp/milter')
And run make
in /etc/mail
to generate the new
sendmail.cf
file. Fortunately for us, I made a backup copy of
both the sendmail.cf
and sendmail.mc
files. So I
do thusly. And then I compare the new sendmail.cf
file with the
one supplied by Insipid
.
[root@XXXXXX ~]# cd /etc/mail [root@XXXXXX mail]# diff -y sendmail.cf sendmail.cf.milter
(if you run that, make sure your terminal window is W I D E, since it shows both versions side-by-side)
Lots o' differences.
And while I can merge the two, will an upgrade of Insipid
break sendmail.cf
? What about our warranty? Or are we forever
doomed to manually patch the sendmail.cf
file?