Official RaSPF page
Ok, time to go a little more public with this.
Here's a page for it (click on "read more") and I will ask the openspf guys to put it on the implementations list (let's see how that goes).
Ok, time to go a little more public with this.
Here's a page for it (click on "read more") and I will ask the openspf guys to put it on the implementations list (let's see how that goes).
I have been able to work some more on RaSPF and the results are encouraging.
Thanks to valgrind and test suites, I am pretty confident it doesn't leak memory, or at least, that it doesn't leak except on very rare cases.
I think I found a neat way to simplify memory management, though, and that's what I wanted to mention.
This is probably trivial for everyone reading, but I am a limited C programmer, so whenever something works unexpectedly right, I am happy ;-)
One problem with C memory management is that if you have many exit points for your functions, releasing everything you allocate is rather annoying, since you may have to do it in several different locations.
I compounded this problem because I am using exceptions (yeah, C doesn't have them. I used this).
Now not only do I have my returns but also my throws and whatever uncaught throw something I called has!
Hell, right?
Nope: what exceptions complicated, exceptions fixed. Look at this function:
bstring spf_query_get_explanation(spf_query *q, bstring spec) { bstring txt=0; struct bstrList *l=0; bstring expanded=0; bstring result=0; struct tagbstring s=bsStatic(""); try { // Expand an explanation if (spec && spec->slen) { expanded=spf_query_expand(q,spec,1); l=spf_query_dns_txt(q,expanded); if (l) { txt=bjoin(l,&s); } else { txt=bfromcstr(""); } result=spf_query_expand(q,txt,0); throw(EXC_OK,0); } else { result=bfromcstr("explanation: Required option is missing"); throw(EXC_OK,0); } } except { if(expanded) bdestroy(expanded); if(txt) bdestroy(txt); if(l) bstrListDestroy(l); on (EXC_OK) { return result; } if(result) bdestroy(result); throw(EXCEPTION.type,EXCEPTION.param1); } }
It doesn't matter if spf_query_expand or spf_query_dns_txt throw an exception, this will not leak.
Nice, I think :-)
Here are the results as of right now:
Give the expected results: 82 tests
Give the wrong result: 48 tests
Give a correct but not preferred result (mostly because of SPF records and IPv6): 6 tests
Fail (crash): 9 tests
So, depending on how you look at it, RASPF passes between 61% and 56% of the tests.
Not bad so far :-)
Update: As of 20:52 ART, it's 105/0/35/5 and 72-76%. The bad news is that that was all the low hanging fruit, and now it gets much harder.
It now can do a bunch of things like expanding macros and (in some cases) validating mechanisms.
I am making very heavy use of unit testing, because it's a pretty complex piece and each function needs to do exactly the right thing or everything else fails (it's pretty hard to figure out where it will fail ;-)
You can check the 947 LOC thing at http://code.google.com/p/raspf (the Code tab).
If you do check it, jeep in mind the following:
It uses a few libs, and they are included in the source code for simplicity.
I do sometimes commit code that doesn't compile
I do sometimes commit code that fails tests
You need cmake
I am not giving a damn about memory management right now, so don't bother worrying about leaks: everything leaks in this code. I want to make it functional first, then I can plug it one function at a time (simply by running the unit testing code with a memory checker).
Enjoy (although it's not precisely enjoyable code right now ;-)