]>
Commit | Line | Data |
---|---|---|
870a0fe4 AT |
1 | #ifdef HAVE_CONFIG_H |
2 | #include "config.h" | |
3 | #endif | |
a48e03da OM |
4 | |
5 | #include <boost/format.hpp> | |
6 | ||
a9e2e5ef BH |
7 | #include "utility.hh" |
8 | #include <cstdio> | |
c6a60874 | 9 | #include <math.h> |
a9e2e5ef BH |
10 | #include <cstdlib> |
11 | #include <sys/types.h> | |
a9e2e5ef | 12 | #include <string> |
dc6aa7f5 | 13 | #include <cerrno> |
c6a60874 | 14 | #include "dnsrecords.hh" |
20177d1d | 15 | |
5e617ff1 OM |
16 | const static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000, |
17 | 1000000,10000000,100000000,1000000000}; | |
a9e2e5ef | 18 | |
a9e2e5ef | 19 | /* converts ascii size/precision X * 10**Y(cm) to 0xXY. moves pointer.*/ |
49a06471 | 20 | static uint8_t precsize_aton(const char **strptr) |
a9e2e5ef BH |
21 | { |
22 | unsigned int mval = 0, cmval = 0; | |
49a06471 | 23 | uint8_t retval = 0; |
a9e2e5ef BH |
24 | const char *cp; |
25 | int exponent; | |
26 | int mantissa; | |
27 | ||
28 | cp = *strptr; | |
29 | ||
30 | while (isdigit(*cp)) | |
31 | mval = mval * 10 + (*cp++ - '0'); | |
32 | ||
33 | if (*cp == '.') { /* centimeters */ | |
34 | cp++; | |
35 | if (isdigit(*cp)) { | |
36 | cmval = (*cp++ - '0') * 10; | |
37 | if (isdigit(*cp)) { | |
4957a608 | 38 | cmval += (*cp++ - '0'); |
a9e2e5ef BH |
39 | } |
40 | } | |
41 | } | |
42 | cmval = (mval * 100) + cmval; | |
43 | ||
44 | for (exponent = 0; exponent < 9; exponent++) | |
45 | if (cmval < poweroften[exponent+1]) | |
46 | break; | |
47 | ||
48 | mantissa = cmval / poweroften[exponent]; | |
49 | if (mantissa > 9) | |
50 | mantissa = 9; | |
51 | ||
52 | retval = (mantissa << 4) | exponent; | |
53 | ||
54 | *strptr = cp; | |
55 | ||
56 | return (retval); | |
57 | } | |
58 | ||
59 | /* converts ascii lat/lon to unsigned encoded 32-bit number. | |
60 | * moves pointer. */ | |
092f210a | 61 | static uint32_t |
a9e2e5ef BH |
62 | latlon2ul(const char **latlonstrptr, int *which) |
63 | { | |
64 | const char *cp; | |
092f210a | 65 | uint32_t retval; |
a9e2e5ef BH |
66 | int deg = 0, min = 0, secs = 0, secsfrac = 0; |
67 | ||
68 | cp = *latlonstrptr; | |
69 | ||
70 | while (isdigit(*cp)) | |
71 | deg = deg * 10 + (*cp++ - '0'); | |
bb85386d | 72 | |
a9e2e5ef BH |
73 | while (isspace(*cp)) |
74 | cp++; | |
bb85386d | 75 | |
a9e2e5ef BH |
76 | if (!(isdigit(*cp))) |
77 | goto fndhemi; | |
bb85386d | 78 | |
a9e2e5ef BH |
79 | while (isdigit(*cp)) |
80 | min = min * 10 + (*cp++ - '0'); | |
bb85386d | 81 | |
a9e2e5ef BH |
82 | while (isspace(*cp)) |
83 | cp++; | |
bb85386d | 84 | |
4eec51b6 | 85 | if (*cp && !(isdigit(*cp))) |
a9e2e5ef | 86 | goto fndhemi; |
bb85386d | 87 | |
a9e2e5ef BH |
88 | while (isdigit(*cp)) |
89 | secs = secs * 10 + (*cp++ - '0'); | |
90 | ||
91 | if (*cp == '.') { /* decimal seconds */ | |
92 | cp++; | |
93 | if (isdigit(*cp)) { | |
94 | secsfrac = (*cp++ - '0') * 100; | |
95 | if (isdigit(*cp)) { | |
4957a608 BH |
96 | secsfrac += (*cp++ - '0') * 10; |
97 | if (isdigit(*cp)) { | |
98 | secsfrac += (*cp++ - '0'); | |
99 | } | |
a9e2e5ef BH |
100 | } |
101 | } | |
102 | } | |
bb85386d | 103 | |
4eec51b6 | 104 | while (*cp && !isspace(*cp)) /* if any trailing garbage */ |
a9e2e5ef | 105 | cp++; |
bb85386d | 106 | |
a9e2e5ef BH |
107 | while (isspace(*cp)) |
108 | cp++; | |
bb85386d | 109 | |
a9e2e5ef BH |
110 | fndhemi: |
111 | switch (*cp) { | |
112 | case 'N': case 'n': | |
113 | case 'E': case 'e': | |
114 | retval = ((unsigned)1<<31) | |
115 | + (((((deg * 60) + min) * 60) + secs) * 1000) | |
116 | + secsfrac; | |
117 | break; | |
118 | case 'S': case 's': | |
119 | case 'W': case 'w': | |
120 | retval = ((unsigned)1<<31) | |
121 | - (((((deg * 60) + min) * 60) + secs) * 1000) | |
122 | - secsfrac; | |
123 | break; | |
124 | default: | |
125 | retval = 0; /* invalid value -- indicates error */ | |
126 | break; | |
127 | } | |
bb85386d | 128 | |
a9e2e5ef BH |
129 | switch (*cp) { |
130 | case 'N': case 'n': | |
131 | case 'S': case 's': | |
132 | *which = 1; /* latitude */ | |
133 | break; | |
134 | case 'E': case 'e': | |
135 | case 'W': case 'w': | |
136 | *which = 2; /* longitude */ | |
137 | break; | |
138 | default: | |
139 | *which = 0; /* error */ | |
140 | break; | |
141 | } | |
142 | ||
79b45a37 RG |
143 | if (!*cp) |
144 | return 0; | |
145 | ||
a9e2e5ef | 146 | cp++; /* skip the hemisphere */ |
bb85386d | 147 | |
4eec51b6 | 148 | while (*cp && !isspace(*cp)) /* if any trailing garbage */ |
a9e2e5ef | 149 | cp++; |
bb85386d | 150 | |
a9e2e5ef BH |
151 | while (isspace(*cp)) /* move to next field */ |
152 | cp++; | |
bb85386d | 153 | |
a9e2e5ef | 154 | *latlonstrptr = cp; |
bb85386d | 155 | |
a9e2e5ef BH |
156 | return (retval); |
157 | } | |
158 | ||
e52fb6a4 | 159 | void LOCRecordContent::report() |
c6a60874 | 160 | { |
3bb50daa | 161 | regist(1, QType::LOC, &make, &make, "LOC"); |
162 | regist(254, QType::LOC, &make, &make, "LOC"); | |
c6a60874 BH |
163 | } |
164 | ||
32122aab | 165 | std::shared_ptr<DNSRecordContent> LOCRecordContent::make(const string& content) |
a9e2e5ef | 166 | { |
32122aab | 167 | return std::make_shared<LOCRecordContent>(content); |
c6a60874 BH |
168 | } |
169 | ||
170 | ||
d06dcda4 | 171 | void LOCRecordContent::toPacket(DNSPacketWriter& pw) const |
c6a60874 BH |
172 | { |
173 | pw.xfr8BitInt(d_version); | |
174 | pw.xfr8BitInt(d_size); | |
175 | pw.xfr8BitInt(d_horizpre); | |
176 | pw.xfr8BitInt(d_vertpre); | |
177 | ||
178 | pw.xfr32BitInt(d_latitude); | |
179 | pw.xfr32BitInt(d_longitude); | |
180 | pw.xfr32BitInt(d_altitude); | |
181 | } | |
182 | ||
d73de874 | 183 | std::shared_ptr<LOCRecordContent::DNSRecordContent> LOCRecordContent::make(const DNSRecord& /* dr */, PacketReader& pr) |
c6a60874 | 184 | { |
32122aab | 185 | auto ret=std::make_shared<LOCRecordContent>(); |
c6a60874 BH |
186 | pr.xfr8BitInt(ret->d_version); |
187 | pr.xfr8BitInt(ret->d_size); | |
188 | pr.xfr8BitInt(ret->d_horizpre); | |
189 | pr.xfr8BitInt(ret->d_vertpre); | |
190 | ||
191 | pr.xfr32BitInt(ret->d_latitude); | |
192 | pr.xfr32BitInt(ret->d_longitude); | |
193 | pr.xfr32BitInt(ret->d_altitude); | |
bb85386d | 194 | |
c6a60874 BH |
195 | return ret; |
196 | } | |
197 | ||
d73de874 | 198 | LOCRecordContent::LOCRecordContent(const string& content, const string& /* zone */) |
c6a60874 BH |
199 | { |
200 | // 51 59 00.000 N 5 55 00.000 E 4.00m 1.00m 10000.00m 10.00m | |
201 | // convert this to d_version, d_size, d_horiz/vertpre, d_latitude, d_longitude, d_altitude | |
202 | d_version = 0; | |
203 | ||
a9e2e5ef | 204 | const char *cp, *maxcp; |
bb85386d | 205 | |
092f210a | 206 | uint32_t lltemp1 = 0, lltemp2 = 0; |
a9e2e5ef | 207 | int altmeters = 0, altfrac = 0, altsign = 1; |
c6a60874 BH |
208 | d_horizpre = 0x16; /* default = 1e6 cm = 10000.00m = 10km */ |
209 | d_vertpre = 0x13; /* default = 1e3 cm = 10.00m */ | |
210 | d_size = 0x12; /* default = 1e2 cm = 1.00m */ | |
a9e2e5ef BH |
211 | int which1 = 0, which2 = 0; |
212 | ||
213 | cp = content.c_str(); | |
214 | maxcp = cp + strlen(content.c_str()); | |
215 | ||
216 | lltemp1 = latlon2ul(&cp, &which1); | |
a9e2e5ef BH |
217 | lltemp2 = latlon2ul(&cp, &which2); |
218 | ||
219 | switch (which1 + which2) { | |
220 | case 3: /* 1 + 2, the only valid combination */ | |
221 | if ((which1 == 1) && (which2 == 2)) { /* normal case */ | |
c6a60874 BH |
222 | d_latitude = lltemp1; |
223 | d_longitude = lltemp2; | |
a9e2e5ef | 224 | } else if ((which1 == 2) && (which2 == 1)) {/*reversed*/ |
c6a60874 BH |
225 | d_latitude = lltemp1; |
226 | d_longitude = lltemp2; | |
a9e2e5ef BH |
227 | } else { /* some kind of brokenness */ |
228 | return; | |
229 | } | |
230 | break; | |
231 | default: /* we didn't get one of each */ | |
bea513c7 | 232 | throw MOADNSException("Error decoding LOC content"); |
a9e2e5ef BH |
233 | } |
234 | ||
235 | /* altitude */ | |
236 | if (*cp == '-') { | |
237 | altsign = -1; | |
238 | cp++; | |
239 | } | |
240 | ||
241 | if (*cp == '+') | |
242 | cp++; | |
bb85386d | 243 | |
a9e2e5ef BH |
244 | while (isdigit(*cp)) |
245 | altmeters = altmeters * 10 + (*cp++ - '0'); | |
bb85386d | 246 | |
a9e2e5ef BH |
247 | if (*cp == '.') { /* decimal meters */ |
248 | cp++; | |
249 | if (isdigit(*cp)) { | |
250 | altfrac = (*cp++ - '0') * 10; | |
251 | if (isdigit(*cp)) { | |
4957a608 | 252 | altfrac += (*cp++ - '0'); |
a9e2e5ef BH |
253 | } |
254 | } | |
255 | } | |
bb85386d | 256 | |
c6a60874 | 257 | d_altitude = (10000000 + (altsign * (altmeters * 100 + altfrac))); |
bb85386d | 258 | |
a9e2e5ef BH |
259 | while (!isspace(*cp) && (cp < maxcp)) |
260 | /* if trailing garbage or m */ | |
261 | cp++; | |
bb85386d | 262 | |
a9e2e5ef BH |
263 | while (isspace(*cp) && (cp < maxcp)) |
264 | cp++; | |
bb85386d FM |
265 | |
266 | ||
a9e2e5ef BH |
267 | if (cp >= maxcp) |
268 | goto defaults; | |
bb85386d | 269 | |
c6a60874 | 270 | d_size = precsize_aton(&cp); |
bb85386d | 271 | |
a9e2e5ef BH |
272 | while (!isspace(*cp) && (cp < maxcp))/*if trailing garbage or m*/ |
273 | cp++; | |
bb85386d | 274 | |
a9e2e5ef BH |
275 | while (isspace(*cp) && (cp < maxcp)) |
276 | cp++; | |
bb85386d | 277 | |
a9e2e5ef BH |
278 | if (cp >= maxcp) |
279 | goto defaults; | |
bb85386d | 280 | |
c6a60874 | 281 | d_horizpre = precsize_aton(&cp); |
bb85386d | 282 | |
a9e2e5ef BH |
283 | while (!isspace(*cp) && (cp < maxcp))/*if trailing garbage or m*/ |
284 | cp++; | |
bb85386d | 285 | |
a9e2e5ef BH |
286 | while (isspace(*cp) && (cp < maxcp)) |
287 | cp++; | |
bb85386d | 288 | |
a9e2e5ef BH |
289 | if (cp >= maxcp) |
290 | goto defaults; | |
bb85386d | 291 | |
c6a60874 | 292 | d_vertpre = precsize_aton(&cp); |
bb85386d | 293 | |
a9e2e5ef | 294 | defaults: |
c6a60874 BH |
295 | ; |
296 | } | |
297 | ||
298 | ||
d73de874 | 299 | string LOCRecordContent::getZoneRepresentation(bool /* noDot */) const |
c6a60874 BH |
300 | { |
301 | // convert d_version, d_size, d_horiz/vertpre, d_latitude, d_longitude, d_altitude to: | |
302 | // 51 59 00.000 N 5 55 00.000 E 4.00m 1.00m 10000.00m 10.00m | |
303 | ||
5e94eeac RG |
304 | double latitude= ((int32_t)((uint32_t)d_latitude - ((uint32_t)1<<31)))/3600000.0; |
305 | double longitude=((int32_t)((uint32_t)d_longitude - ((uint32_t)1<<31)))/3600000.0; | |
5e843b4e | 306 | double altitude= ((int32_t)d_altitude )/100.0 - 100000; |
bb85386d | 307 | |
c6a60874 BH |
308 | double size=0.01*((d_size>>4)&0xf); |
309 | int count=d_size & 0xf; | |
310 | while(count--) | |
311 | size*=10; | |
a9e2e5ef | 312 | |
c6a60874 BH |
313 | double horizpre=0.01*((d_horizpre>>4) & 0xf); |
314 | count=d_horizpre&0xf; | |
315 | while(count--) | |
316 | horizpre*=10; | |
317 | ||
318 | double vertpre=0.01*((d_vertpre>>4)&0xf); | |
319 | count=d_vertpre&0xf; | |
320 | while(count--) | |
321 | vertpre*=10; | |
322 | ||
323 | double remlat=60.0*(latitude-(int)latitude); | |
324 | double remlong=60.0*(longitude-(int)longitude); | |
3cbe2773 | 325 | static const boost::format fmt("%d %d %2.03f %c %d %d %2.03f %c %.2fm %.2fm %.2fm %.2fm"); |
0e12635d | 326 | std::string ret = boost::str( |
3cbe2773 | 327 | boost::format(fmt) |
0e12635d CHB |
328 | % abs((int)latitude) % abs((int) ((latitude-(int)latitude)*60)) |
329 | % fabs((double)((remlat-(int)remlat)*60.0)) % (latitude>0 ? 'N' : 'S') | |
330 | % abs((int)longitude) % abs((int) ((longitude-(int)longitude)*60)) | |
331 | % fabs((double)((remlong-(int)remlong)*60.0)) % (longitude>0 ? 'E' : 'W') | |
332 | % altitude % size | |
333 | % horizpre % vertpre | |
334 | ); | |
c6a60874 BH |
335 | |
336 | return ret; | |
a9e2e5ef | 337 | } |