1*c2c66affSColin Finck /*
2*c2c66affSColin Finck * general.c
3*c2c66affSColin Finck * - diagnostic functions
4*c2c66affSColin Finck * - vbuf handling
5*c2c66affSColin Finck */
6*c2c66affSColin Finck /*
7*c2c66affSColin Finck * This file is
8*c2c66affSColin Finck * Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk>
9*c2c66affSColin Finck *
10*c2c66affSColin Finck * It is part of adns, which is
11*c2c66affSColin Finck * Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk>
12*c2c66affSColin Finck * Copyright (C) 1999-2000 Tony Finch <dot@dotat.at>
13*c2c66affSColin Finck *
14*c2c66affSColin Finck * This program is free software; you can redistribute it and/or modify
15*c2c66affSColin Finck * it under the terms of the GNU General Public License as published by
16*c2c66affSColin Finck * the Free Software Foundation; either version 2, or (at your option)
17*c2c66affSColin Finck * any later version.
18*c2c66affSColin Finck *
19*c2c66affSColin Finck * This program is distributed in the hope that it will be useful,
20*c2c66affSColin Finck * but WITHOUT ANY WARRANTY; without even the implied warranty of
21*c2c66affSColin Finck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22*c2c66affSColin Finck * GNU General Public License for more details.
23*c2c66affSColin Finck *
24*c2c66affSColin Finck * You should have received a copy of the GNU General Public License
25*c2c66affSColin Finck * along with this program; if not, write to the Free Software Foundation,
26*c2c66affSColin Finck * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27*c2c66affSColin Finck */
28*c2c66affSColin Finck
29*c2c66affSColin Finck #include <stdlib.h>
30*c2c66affSColin Finck
31*c2c66affSColin Finck #ifdef ADNS_JGAA_WIN32
32*c2c66affSColin Finck # include "adns_win32.h"
33*c2c66affSColin Finck #else
34*c2c66affSColin Finck # include <unistd.h>
35*c2c66affSColin Finck # include <sys/types.h>
36*c2c66affSColin Finck # include <sys/socket.h>
37*c2c66affSColin Finck # include <netinet/in.h>
38*c2c66affSColin Finck # include <arpa/inet.h>
39*c2c66affSColin Finck #endif
40*c2c66affSColin Finck
41*c2c66affSColin Finck #include "internal.h"
42*c2c66affSColin Finck
43*c2c66affSColin Finck /* Core diagnostic functions */
44*c2c66affSColin Finck
adns__vdiag(adns_state ads,const char * pfx,adns_initflags prevent,int serv,adns_query qu,const char * fmt,va_list al)45*c2c66affSColin Finck void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
46*c2c66affSColin Finck int serv, adns_query qu, const char *fmt, va_list al) {
47*c2c66affSColin Finck const char *bef, *aft;
48*c2c66affSColin Finck vbuf vb;
49*c2c66affSColin Finck
50*c2c66affSColin Finck if (!ads->diagfile ||
51*c2c66affSColin Finck (!(ads->iflags & adns_if_debug) && (!prevent || (ads->iflags & prevent))))
52*c2c66affSColin Finck return;
53*c2c66affSColin Finck
54*c2c66affSColin Finck if (ads->iflags & adns_if_logpid) {
55*c2c66affSColin Finck fprintf(ads->diagfile,"adns%s [%ld]: ",pfx,(long)getpid());
56*c2c66affSColin Finck } else {
57*c2c66affSColin Finck fprintf(ads->diagfile,"adns%s: ",pfx);
58*c2c66affSColin Finck }
59*c2c66affSColin Finck
60*c2c66affSColin Finck vfprintf(ads->diagfile,fmt,al);
61*c2c66affSColin Finck
62*c2c66affSColin Finck bef= " (";
63*c2c66affSColin Finck aft= "\n";
64*c2c66affSColin Finck
65*c2c66affSColin Finck if (qu && qu->query_dgram) {
66*c2c66affSColin Finck adns__vbuf_init(&vb);
67*c2c66affSColin Finck fprintf(ads->diagfile,"%sQNAME=%s, QTYPE=%s",
68*c2c66affSColin Finck bef,
69*c2c66affSColin Finck adns__diag_domain(qu->ads,-1,0, &vb,
70*c2c66affSColin Finck qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
71*c2c66affSColin Finck qu->typei ? qu->typei->rrtname : "<unknown>");
72*c2c66affSColin Finck if (qu->typei && qu->typei->fmtname)
73*c2c66affSColin Finck fprintf(ads->diagfile,"(%s)",qu->typei->fmtname);
74*c2c66affSColin Finck bef=", "; aft=")\n";
75*c2c66affSColin Finck adns__vbuf_free(&vb);
76*c2c66affSColin Finck }
77*c2c66affSColin Finck
78*c2c66affSColin Finck if (serv>=0) {
79*c2c66affSColin Finck fprintf(ads->diagfile,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr));
80*c2c66affSColin Finck bef=", "; aft=")\n";
81*c2c66affSColin Finck }
82*c2c66affSColin Finck
83*c2c66affSColin Finck fputs(aft,ads->diagfile);
84*c2c66affSColin Finck }
85*c2c66affSColin Finck
adns__debug(adns_state ads,int serv,adns_query qu,const char * fmt,...)86*c2c66affSColin Finck void adns__debug(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
87*c2c66affSColin Finck va_list al;
88*c2c66affSColin Finck
89*c2c66affSColin Finck va_start(al,fmt);
90*c2c66affSColin Finck adns__vdiag(ads," debug",0,serv,qu,fmt,al);
91*c2c66affSColin Finck va_end(al);
92*c2c66affSColin Finck }
93*c2c66affSColin Finck
adns__warn(adns_state ads,int serv,adns_query qu,const char * fmt,...)94*c2c66affSColin Finck void adns__warn(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
95*c2c66affSColin Finck va_list al;
96*c2c66affSColin Finck
97*c2c66affSColin Finck va_start(al,fmt);
98*c2c66affSColin Finck adns__vdiag(ads," warning",adns_if_noerrprint|adns_if_noserverwarn,serv,qu,fmt,al);
99*c2c66affSColin Finck va_end(al);
100*c2c66affSColin Finck }
101*c2c66affSColin Finck
adns__diag(adns_state ads,int serv,adns_query qu,const char * fmt,...)102*c2c66affSColin Finck void adns__diag(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
103*c2c66affSColin Finck va_list al;
104*c2c66affSColin Finck
105*c2c66affSColin Finck va_start(al,fmt);
106*c2c66affSColin Finck adns__vdiag(ads,"",adns_if_noerrprint,serv,qu,fmt,al);
107*c2c66affSColin Finck va_end(al);
108*c2c66affSColin Finck }
109*c2c66affSColin Finck
110*c2c66affSColin Finck /* vbuf functions */
111*c2c66affSColin Finck
adns__vbuf_init(vbuf * vb)112*c2c66affSColin Finck void adns__vbuf_init(vbuf *vb) {
113*c2c66affSColin Finck vb->used= vb->avail= 0; vb->buf= 0;
114*c2c66affSColin Finck }
115*c2c66affSColin Finck
adns__vbuf_ensure(vbuf * vb,int want)116*c2c66affSColin Finck int adns__vbuf_ensure(vbuf *vb, int want) {
117*c2c66affSColin Finck void *nb;
118*c2c66affSColin Finck
119*c2c66affSColin Finck if (vb->avail >= want) return 1;
120*c2c66affSColin Finck nb= realloc(vb->buf, (size_t) want); if (!nb) return 0;
121*c2c66affSColin Finck vb->buf= nb;
122*c2c66affSColin Finck vb->avail= want;
123*c2c66affSColin Finck return 1;
124*c2c66affSColin Finck }
125*c2c66affSColin Finck
adns__vbuf_appendq(vbuf * vb,const byte * data,int len)126*c2c66affSColin Finck void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
127*c2c66affSColin Finck memcpy(vb->buf+vb->used,data, (size_t) len);
128*c2c66affSColin Finck vb->used+= len;
129*c2c66affSColin Finck }
130*c2c66affSColin Finck
adns__vbuf_append(vbuf * vb,const byte * data,int len)131*c2c66affSColin Finck int adns__vbuf_append(vbuf *vb, const byte *data, int len) {
132*c2c66affSColin Finck int newlen;
133*c2c66affSColin Finck void *nb;
134*c2c66affSColin Finck
135*c2c66affSColin Finck newlen= vb->used+len;
136*c2c66affSColin Finck if (vb->avail < newlen) {
137*c2c66affSColin Finck if (newlen<20) newlen= 20;
138*c2c66affSColin Finck newlen <<= 1;
139*c2c66affSColin Finck nb= realloc(vb->buf,(size_t) newlen);
140*c2c66affSColin Finck if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf, (size_t) newlen); }
141*c2c66affSColin Finck if (!nb) return 0;
142*c2c66affSColin Finck vb->buf= nb;
143*c2c66affSColin Finck vb->avail= newlen;
144*c2c66affSColin Finck }
145*c2c66affSColin Finck adns__vbuf_appendq(vb,data,len);
146*c2c66affSColin Finck return 1;
147*c2c66affSColin Finck }
148*c2c66affSColin Finck
adns__vbuf_appendstr(vbuf * vb,const char * data)149*c2c66affSColin Finck int adns__vbuf_appendstr(vbuf *vb, const char *data) {
150*c2c66affSColin Finck int l;
151*c2c66affSColin Finck l= strlen(data);
152*c2c66affSColin Finck return adns__vbuf_append(vb,(byte*)data,l);
153*c2c66affSColin Finck }
154*c2c66affSColin Finck
adns__vbuf_free(vbuf * vb)155*c2c66affSColin Finck void adns__vbuf_free(vbuf *vb) {
156*c2c66affSColin Finck free(vb->buf);
157*c2c66affSColin Finck adns__vbuf_init(vb);
158*c2c66affSColin Finck }
159*c2c66affSColin Finck
160*c2c66affSColin Finck /* Additional diagnostic functions */
161*c2c66affSColin Finck
adns__diag_domain(adns_state ads,int serv,adns_query qu,vbuf * vb,const byte * dgram,int dglen,int cbyte)162*c2c66affSColin Finck const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
163*c2c66affSColin Finck vbuf *vb, const byte *dgram, int dglen, int cbyte) {
164*c2c66affSColin Finck adns_status st;
165*c2c66affSColin Finck
166*c2c66affSColin Finck st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok, dgram,dglen,&cbyte,dglen);
167*c2c66affSColin Finck if (st == adns_s_nomemory) {
168*c2c66affSColin Finck return "<cannot report domain... out of memory>";
169*c2c66affSColin Finck }
170*c2c66affSColin Finck if (st) {
171*c2c66affSColin Finck vb->used= 0;
172*c2c66affSColin Finck if (!(adns__vbuf_appendstr(vb,"<bad format... ") &&
173*c2c66affSColin Finck adns__vbuf_appendstr(vb,adns_strerror(st)) &&
174*c2c66affSColin Finck adns__vbuf_appendstr(vb,">") &&
175*c2c66affSColin Finck adns__vbuf_append(vb,(byte*)"",1))) {
176*c2c66affSColin Finck return "<cannot report bad format... out of memory>";
177*c2c66affSColin Finck }
178*c2c66affSColin Finck }
179*c2c66affSColin Finck if (!vb->used) {
180*c2c66affSColin Finck adns__vbuf_appendstr(vb,"<truncated ...>");
181*c2c66affSColin Finck adns__vbuf_append(vb,(byte*)"",1);
182*c2c66affSColin Finck }
183*c2c66affSColin Finck return (char*)vb->buf;
184*c2c66affSColin Finck }
185*c2c66affSColin Finck
adns_rr_info(adns_rrtype type,const char ** rrtname_r,const char ** fmtname_r,int * len_r,const void * datap,char ** data_r)186*c2c66affSColin Finck adns_status adns_rr_info(adns_rrtype type,
187*c2c66affSColin Finck const char **rrtname_r, const char **fmtname_r,
188*c2c66affSColin Finck int *len_r,
189*c2c66affSColin Finck const void *datap, char **data_r) {
190*c2c66affSColin Finck const typeinfo *typei;
191*c2c66affSColin Finck vbuf vb;
192*c2c66affSColin Finck adns_status st;
193*c2c66affSColin Finck
194*c2c66affSColin Finck typei= adns__findtype(type);
195*c2c66affSColin Finck if (!typei) return adns_s_unknownrrtype;
196*c2c66affSColin Finck
197*c2c66affSColin Finck if (rrtname_r) *rrtname_r= typei->rrtname;
198*c2c66affSColin Finck if (fmtname_r) *fmtname_r= typei->fmtname;
199*c2c66affSColin Finck if (len_r) *len_r= typei->rrsz;
200*c2c66affSColin Finck
201*c2c66affSColin Finck if (!datap) return adns_s_ok;
202*c2c66affSColin Finck
203*c2c66affSColin Finck adns__vbuf_init(&vb);
204*c2c66affSColin Finck st= typei->convstring(&vb,datap);
205*c2c66affSColin Finck if (st) goto x_freevb;
206*c2c66affSColin Finck if (!adns__vbuf_append(&vb,(byte*)"",1)) { st= adns_s_nomemory; goto x_freevb; }
207*c2c66affSColin Finck assert((int)strlen((char*)vb.buf) == vb.used-1);
208*c2c66affSColin Finck *data_r= realloc(vb.buf, (size_t) vb.used);
209*c2c66affSColin Finck if (!*data_r) *data_r= (char*)vb.buf;
210*c2c66affSColin Finck return adns_s_ok;
211*c2c66affSColin Finck
212*c2c66affSColin Finck x_freevb:
213*c2c66affSColin Finck adns__vbuf_free(&vb);
214*c2c66affSColin Finck return st;
215*c2c66affSColin Finck }
216*c2c66affSColin Finck
217*c2c66affSColin Finck
218*c2c66affSColin Finck #define SINFO(n,s) { adns_s_##n, #n, s }
219*c2c66affSColin Finck
220*c2c66affSColin Finck static const struct sinfo {
221*c2c66affSColin Finck adns_status st;
222*c2c66affSColin Finck const char *abbrev;
223*c2c66affSColin Finck const char *string;
224*c2c66affSColin Finck } sinfos[]= {
225*c2c66affSColin Finck SINFO( ok, "OK" ),
226*c2c66affSColin Finck
227*c2c66affSColin Finck SINFO( nomemory, "Out of memory" ),
228*c2c66affSColin Finck SINFO( unknownrrtype, "Query not implemented in DNS library" ),
229*c2c66affSColin Finck SINFO( systemfail, "General resolver or system failure" ),
230*c2c66affSColin Finck
231*c2c66affSColin Finck SINFO( timeout, "DNS query timed out" ),
232*c2c66affSColin Finck SINFO( allservfail, "All nameservers failed" ),
233*c2c66affSColin Finck SINFO( norecurse, "Recursion denied by nameserver" ),
234*c2c66affSColin Finck SINFO( invalidresponse, "Nameserver sent bad response" ),
235*c2c66affSColin Finck SINFO( unknownformat, "Nameserver used unknown format" ),
236*c2c66affSColin Finck
237*c2c66affSColin Finck SINFO( rcodeservfail, "Nameserver reports failure" ),
238*c2c66affSColin Finck SINFO( rcodeformaterror, "Query not understood by nameserver" ),
239*c2c66affSColin Finck SINFO( rcodenotimplemented, "Query not implemented by nameserver" ),
240*c2c66affSColin Finck SINFO( rcoderefused, "Query refused by nameserver" ),
241*c2c66affSColin Finck SINFO( rcodeunknown, "Nameserver sent unknown response code" ),
242*c2c66affSColin Finck
243*c2c66affSColin Finck SINFO( inconsistent, "Inconsistent resource records in DNS" ),
244*c2c66affSColin Finck SINFO( prohibitedcname, "DNS alias found where canonical name wanted" ),
245*c2c66affSColin Finck SINFO( answerdomaininvalid, "Found syntactically invalid domain name" ),
246*c2c66affSColin Finck SINFO( answerdomaintoolong, "Found overly-long domain name" ),
247*c2c66affSColin Finck SINFO( invaliddata, "Found invalid DNS data" ),
248*c2c66affSColin Finck
249*c2c66affSColin Finck SINFO( querydomainwrong, "Domain invalid for particular DNS query type" ),
250*c2c66affSColin Finck SINFO( querydomaininvalid, "Domain name is syntactically invalid" ),
251*c2c66affSColin Finck SINFO( querydomaintoolong, "Domain name or component is too long" ),
252*c2c66affSColin Finck
253*c2c66affSColin Finck SINFO( nxdomain, "No such domain" ),
254*c2c66affSColin Finck SINFO( nodata, "No such data" )
255*c2c66affSColin Finck };
256*c2c66affSColin Finck
si_compar(const void * key,const void * elem)257*c2c66affSColin Finck static int si_compar(const void *key, const void *elem) {
258*c2c66affSColin Finck const adns_status *st= key;
259*c2c66affSColin Finck const struct sinfo *si= elem;
260*c2c66affSColin Finck
261*c2c66affSColin Finck return *st < si->st ? -1 : *st > si->st ? 1 : 0;
262*c2c66affSColin Finck }
263*c2c66affSColin Finck
findsinfo(adns_status st)264*c2c66affSColin Finck static const struct sinfo *findsinfo(adns_status st) {
265*c2c66affSColin Finck return bsearch(&st,sinfos,sizeof(sinfos)/sizeof(*sinfos),sizeof(*sinfos),si_compar);
266*c2c66affSColin Finck }
267*c2c66affSColin Finck
adns_strerror(adns_status st)268*c2c66affSColin Finck const char *adns_strerror(adns_status st) {
269*c2c66affSColin Finck const struct sinfo *si;
270*c2c66affSColin Finck
271*c2c66affSColin Finck si= findsinfo(st);
272*c2c66affSColin Finck return si->string;
273*c2c66affSColin Finck }
274*c2c66affSColin Finck
adns_errabbrev(adns_status st)275*c2c66affSColin Finck const char *adns_errabbrev(adns_status st) {
276*c2c66affSColin Finck const struct sinfo *si;
277*c2c66affSColin Finck
278*c2c66affSColin Finck si= findsinfo(st);
279*c2c66affSColin Finck return si->abbrev;
280*c2c66affSColin Finck }
281*c2c66affSColin Finck
282*c2c66affSColin Finck
283*c2c66affSColin Finck #define STINFO(max) { adns_s_max_##max, #max }
284*c2c66affSColin Finck
285*c2c66affSColin Finck static const struct stinfo {
286*c2c66affSColin Finck adns_status stmax;
287*c2c66affSColin Finck const char *abbrev;
288*c2c66affSColin Finck } stinfos[]= {
289*c2c66affSColin Finck { adns_s_ok, "ok" },
290*c2c66affSColin Finck STINFO( localfail ),
291*c2c66affSColin Finck STINFO( remotefail ),
292*c2c66affSColin Finck STINFO( tempfail ),
293*c2c66affSColin Finck STINFO( misconfig ),
294*c2c66affSColin Finck STINFO( misquery ),
295*c2c66affSColin Finck STINFO( permfail )
296*c2c66affSColin Finck };
297*c2c66affSColin Finck
sti_compar(const void * key,const void * elem)298*c2c66affSColin Finck static int sti_compar(const void *key, const void *elem) {
299*c2c66affSColin Finck const adns_status *st= key;
300*c2c66affSColin Finck const struct stinfo *sti= elem;
301*c2c66affSColin Finck
302*c2c66affSColin Finck adns_status here, min, max;
303*c2c66affSColin Finck
304*c2c66affSColin Finck here= *st;
305*c2c66affSColin Finck min= (sti==stinfos) ? 0 : sti[-1].stmax+1;
306*c2c66affSColin Finck max= sti->stmax;
307*c2c66affSColin Finck
308*c2c66affSColin Finck return here < min ? -1 : here > max ? 1 : 0;
309*c2c66affSColin Finck }
310*c2c66affSColin Finck
adns_errtypeabbrev(adns_status st)311*c2c66affSColin Finck const char *adns_errtypeabbrev(adns_status st) {
312*c2c66affSColin Finck const struct stinfo *sti;
313*c2c66affSColin Finck
314*c2c66affSColin Finck sti= bsearch(&st,stinfos,sizeof(stinfos)/sizeof(*stinfos),sizeof(*stinfos),sti_compar);
315*c2c66affSColin Finck return sti->abbrev;
316*c2c66affSColin Finck }
317*c2c66affSColin Finck
318*c2c66affSColin Finck
adns__isort(void * array,int nobjs,int sz,void * tempbuf,int (* needswap)(void * context,const void * a,const void * b),void * context)319*c2c66affSColin Finck void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
320*c2c66affSColin Finck int (*needswap)(void *context, const void *a, const void *b),
321*c2c66affSColin Finck void *context) {
322*c2c66affSColin Finck byte *data= array;
323*c2c66affSColin Finck int i, place;
324*c2c66affSColin Finck
325*c2c66affSColin Finck for (i=0; i<nobjs; i++) {
326*c2c66affSColin Finck for (place= i;
327*c2c66affSColin Finck place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
328*c2c66affSColin Finck place--);
329*c2c66affSColin Finck if (place != i) {
330*c2c66affSColin Finck memcpy(tempbuf, data + i*sz, (size_t) sz);
331*c2c66affSColin Finck memmove(data + (place+1)*sz, data + place*sz, (size_t) (i-place)*sz);
332*c2c66affSColin Finck memcpy(data + place*sz, tempbuf, (size_t) sz);
333*c2c66affSColin Finck }
334*c2c66affSColin Finck }
335*c2c66affSColin Finck }
336*c2c66affSColin Finck
337*c2c66affSColin Finck /* SIGPIPE protection. */
338*c2c66affSColin Finck /* Not required under Win32 with MSVC */
339*c2c66affSColin Finck
adns__sigpipe_protect(adns_state ads)340*c2c66affSColin Finck void adns__sigpipe_protect(adns_state ads) {
341*c2c66affSColin Finck #ifndef ADNS_JGAA_WIN32
342*c2c66affSColin Finck sigset_t toblock;
343*c2c66affSColin Finck struct sigaction sa;
344*c2c66affSColin Finck int r;
345*c2c66affSColin Finck
346*c2c66affSColin Finck if (ads->iflags & adns_if_nosigpipe) return;
347*c2c66affSColin Finck
348*c2c66affSColin Finck sigfillset(&toblock);
349*c2c66affSColin Finck sigdelset(&toblock,SIGPIPE);
350*c2c66affSColin Finck
351*c2c66affSColin Finck sa.sa_handler= SIG_IGN;
352*c2c66affSColin Finck sigfillset(&sa.sa_mask);
353*c2c66affSColin Finck sa.sa_flags= 0;
354*c2c66affSColin Finck
355*c2c66affSColin Finck r= sigprocmask(SIG_SETMASK,&toblock,&ads->stdsigmask); assert(!r);
356*c2c66affSColin Finck r= sigaction(SIGPIPE,&sa,&ads->stdsigpipe); assert(!r);
357*c2c66affSColin Finck #endif
358*c2c66affSColin Finck }
359*c2c66affSColin Finck
adns__sigpipe_unprotect(adns_state ads)360*c2c66affSColin Finck void adns__sigpipe_unprotect(adns_state ads) {
361*c2c66affSColin Finck #ifndef ADNS_JGAA_WIN32
362*c2c66affSColin Finck int r;
363*c2c66affSColin Finck
364*c2c66affSColin Finck if (ads->iflags & adns_if_nosigpipe) return;
365*c2c66affSColin Finck
366*c2c66affSColin Finck r= sigaction(SIGPIPE,&ads->stdsigpipe,0); assert(!r);
367*c2c66affSColin Finck r= sigprocmask(SIG_SETMASK,&ads->stdsigmask,0); assert(!r);
368*c2c66affSColin Finck #endif
369*c2c66affSColin Finck }
370