Dirk-Willem van Gulik (NXP/mbed)
/
Bonjour
Bonjour/Zerconf library
services/mDNS/mDNSResponder.cpp@1:59820ca5c83a, 2010-07-22 (annotated)
- Committer:
- dirkx
- Date:
- Thu Jul 22 00:08:38 2010 +0000
- Revision:
- 1:59820ca5c83a
- Parent:
- 0:355018f44c9f
- Child:
- 2:816cbd922d3e
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
dirkx | 0:355018f44c9f | 1 | /* Class: mDNSResponder |
dirkx | 0:355018f44c9f | 2 | * Copyright 1991, 2003, 2010 Dirk-Willem van Gulik <dirkx(at)apache(punto)org> |
dirkx | 0:355018f44c9f | 3 | * |
dirkx | 0:355018f44c9f | 4 | * License: Any BSD or ASF License. |
dirkx | 0:355018f44c9f | 5 | * |
dirkx | 0:355018f44c9f | 6 | * Rough and ready port of some mDNS code. |
dirkx | 0:355018f44c9f | 7 | * |
dirkx | 0:355018f44c9f | 8 | * Typical use is something like |
dirkx | 0:355018f44c9f | 9 | * |
dirkx | 0:355018f44c9f | 10 | * EthernetNetIf eth; |
dirkx | 0:355018f44c9f | 11 | * HTTPServer svr; |
dirkx | 0:355018f44c9f | 12 | * mDNSResponder mdns; |
dirkx | 0:355018f44c9f | 13 | * |
dirkx | 0:355018f44c9f | 14 | * int main()... |
dirkx | 0:355018f44c9f | 15 | * |
dirkx | 0:355018f44c9f | 16 | * // get internet |
dirkx | 0:355018f44c9f | 17 | * EthernetErr ethErr = eth.setup(); |
dirkx | 0:355018f44c9f | 18 | * ... etc .. |
dirkx | 0:355018f44c9f | 19 | * |
dirkx | 0:355018f44c9f | 20 | * // set up some server |
dirkx | 0:355018f44c9f | 21 | * svr.addHandler<SimpleHandler>("/"); //Default handler |
dirkx | 0:355018f44c9f | 22 | * svr.bind(80); * * |
dirkx | 0:355018f44c9f | 23 | |
dirkx | 0:355018f44c9f | 24 | * // Extract the IP address. |
dirkx | 0:355018f44c9f | 25 | * IpAddr ip = eth.getIp(); |
dirkx | 0:355018f44c9f | 26 | * printf("mbed IP Address is %d.%d.%d.%d\r\n", ip[0], ip[1], ip[2], ip[3]); |
dirkx | 0:355018f44c9f | 27 | * |
dirkx | 0:355018f44c9f | 28 | * // Announce ourselves. |
dirkx | 1:59820ca5c83a | 29 | * mdns.announce(ip, "fred", "_http._tcp", 80, "The Little Server that Could", "path=/demo"); |
dirkx | 0:355018f44c9f | 30 | * |
dirkx | 0:355018f44c9f | 31 | * while()... enter some run loop |
dirkx | 1:59820ca5c83a | 32 | * ... |
dirkx | 1:59820ca5c83a | 33 | * |
dirkx | 1:59820ca5c83a | 34 | * This will cause http://fred.local./demo to be announced as 'The Little Server that Could'. |
dirkx | 1:59820ca5c83a | 35 | * |
dirkx | 1:59820ca5c83a | 36 | * Or as another example: (http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt) |
dirkx | 1:59820ca5c83a | 37 | * and the various RFCs: |
dirkx | 0:355018f44c9f | 38 | * |
dirkx | 0:355018f44c9f | 39 | * mdns.announce(ip, "_ssh._tcp", 22, SSH to Serial Gateway", NULL); |
dirkx | 0:355018f44c9f | 40 | * |
dirkx | 0:355018f44c9f | 41 | * CAVEAT - a lot of the buffer overrun and copy checks |
dirkx | 0:355018f44c9f | 42 | * where removed; and this is not anywhere near |
dirkx | 0:355018f44c9f | 43 | * threadsafve or sane. Not for production use. |
dirkx | 0:355018f44c9f | 44 | */ |
dirkx | 0:355018f44c9f | 45 | |
dirkx | 0:355018f44c9f | 46 | #include "mDNSResponder.h" |
dirkx | 0:355018f44c9f | 47 | #include <stdio.h> |
dirkx | 0:355018f44c9f | 48 | |
dirkx | 0:355018f44c9f | 49 | // #define MCAST 192,168,1,71 |
dirkx | 0:355018f44c9f | 50 | |
dirkx | 0:355018f44c9f | 51 | mDNSResponder::mDNSResponder() : NetService(false), |
dirkx | 0:355018f44c9f | 52 | moi_txt(NULL), moi_port(0), moi_ip(0), |
dirkx | 0:355018f44c9f | 53 | moi_name(NULL), moi_proto(NULL), |
dirkx | 0:355018f44c9f | 54 | moi_local_proto(NULL), moi_local_name(NULL), moi_local_pglue(NULL), |
dirkx | 0:355018f44c9f | 55 | announcer() |
dirkx | 0:355018f44c9f | 56 | { |
dirkx | 0:355018f44c9f | 57 | // nothing yet... |
dirkx | 0:355018f44c9f | 58 | } |
dirkx | 0:355018f44c9f | 59 | |
dirkx | 0:355018f44c9f | 60 | mDNSResponder::~mDNSResponder() { |
dirkx | 0:355018f44c9f | 61 | announcer.stop(); |
dirkx | 0:355018f44c9f | 62 | close(); |
dirkx | 0:355018f44c9f | 63 | } |
dirkx | 0:355018f44c9f | 64 | |
dirkx | 1:59820ca5c83a | 65 | void mDNSResponder::announce(IpAddr ip, const char * ldn, const char * proto, uint16_t port, const char * name, char ** txt) { |
dirkx | 0:355018f44c9f | 66 | Host localhost(IpAddr(MCAST), MDNS_PORT, NULL /* fqdn */); |
dirkx | 0:355018f44c9f | 67 | |
dirkx | 0:355018f44c9f | 68 | m_pUDPSocket = new UDPSocket; |
dirkx | 0:355018f44c9f | 69 | m_pUDPSocket->bind(localhost); |
dirkx | 0:355018f44c9f | 70 | |
dirkx | 0:355018f44c9f | 71 | m_pUDPSocket->setOnEvent(this, &mDNSResponder::onUDPSocketEvent); |
dirkx | 0:355018f44c9f | 72 | |
dirkx | 0:355018f44c9f | 73 | moi_port = port; |
dirkx | 0:355018f44c9f | 74 | moi_txt = txt; |
dirkx | 0:355018f44c9f | 75 | moi_ip = ip; |
dirkx | 0:355018f44c9f | 76 | moi_proto = proto; |
dirkx | 0:355018f44c9f | 77 | moi_name = name; |
dirkx | 0:355018f44c9f | 78 | |
dirkx | 0:355018f44c9f | 79 | moi_local_proto = (char *)malloc(128); |
dirkx | 0:355018f44c9f | 80 | moi_local_name = (char *)malloc(128); |
dirkx | 0:355018f44c9f | 81 | moi_local_pglue = (char *)malloc(128); |
dirkx | 0:355018f44c9f | 82 | |
dirkx | 0:355018f44c9f | 83 | #define LOCAL "local" |
dirkx | 0:355018f44c9f | 84 | snprintf(moi_local_proto,128,"%s.%s.", moi_proto, LOCAL); |
dirkx | 1:59820ca5c83a | 85 | snprintf(moi_local_name,128,"%s.%s.", ldn, LOCAL); |
dirkx | 0:355018f44c9f | 86 | snprintf(moi_local_pglue,128,"%s.%s.%s.", moi_name,moi_proto, LOCAL); |
dirkx | 0:355018f44c9f | 87 | |
dirkx | 0:355018f44c9f | 88 | // Gratuis intro - and repeat such regularly.. |
dirkx | 0:355018f44c9f | 89 | // |
dirkx | 0:355018f44c9f | 90 | mDNSResponder::sendReply(0, localhost); |
dirkx | 0:355018f44c9f | 91 | announcer.start(); |
dirkx | 0:355018f44c9f | 92 | } |
dirkx | 0:355018f44c9f | 93 | |
dirkx | 0:355018f44c9f | 94 | void mDNSResponder::close() { |
dirkx | 0:355018f44c9f | 95 | m_pUDPSocket->resetOnEvent(); |
dirkx | 0:355018f44c9f | 96 | m_pUDPSocket->close(); |
dirkx | 0:355018f44c9f | 97 | delete m_pUDPSocket; |
dirkx | 0:355018f44c9f | 98 | } |
dirkx | 0:355018f44c9f | 99 | |
dirkx | 0:355018f44c9f | 100 | |
dirkx | 0:355018f44c9f | 101 | |
dirkx | 0:355018f44c9f | 102 | void mDNSResponder::poll() { //Called by NetServices |
dirkx | 0:355018f44c9f | 103 | if (announcer.read_ms() > 1000 * MDNS_INTERVAL) { |
dirkx | 0:355018f44c9f | 104 | |
dirkx | 0:355018f44c9f | 105 | Host mch(IpAddr(MCAST), MDNS_PORT, NULL); |
dirkx | 0:355018f44c9f | 106 | mDNSResponder::sendReply(0, mch); |
dirkx | 0:355018f44c9f | 107 | |
dirkx | 0:355018f44c9f | 108 | announcer.reset(); |
dirkx | 0:355018f44c9f | 109 | } |
dirkx | 0:355018f44c9f | 110 | } |
dirkx | 0:355018f44c9f | 111 | |
dirkx | 0:355018f44c9f | 112 | char * index(char * str, char c) { |
dirkx | 0:355018f44c9f | 113 | for(;str && *str;str++) { |
dirkx | 0:355018f44c9f | 114 | if (*str == c) return str; |
dirkx | 0:355018f44c9f | 115 | }; |
dirkx | 0:355018f44c9f | 116 | return NULL; |
dirkx | 0:355018f44c9f | 117 | } |
dirkx | 0:355018f44c9f | 118 | |
dirkx | 0:355018f44c9f | 119 | #ifndef THREADINGCOMPRESS |
dirkx | 0:355018f44c9f | 120 | #ifndef MAXCACHEDNSLABELS |
dirkx | 0:355018f44c9f | 121 | #define MAXCACHEDNSLABELS (10) |
dirkx | 0:355018f44c9f | 122 | #endif |
dirkx | 0:355018f44c9f | 123 | static int labelCacheCnt = 0; |
dirkx | 0:355018f44c9f | 124 | static uint16_t _cache_off[MAXCACHEDNSLABELS]; |
dirkx | 0:355018f44c9f | 125 | static char * _cache_och[MAXCACHEDNSLABELS]; |
dirkx | 0:355018f44c9f | 126 | static char * labelCacheOffset = 0; |
dirkx | 0:355018f44c9f | 127 | |
dirkx | 0:355018f44c9f | 128 | void initLabelCache(char * off) { |
dirkx | 0:355018f44c9f | 129 | labelCacheOffset = off; |
dirkx | 0:355018f44c9f | 130 | labelCacheCnt = 0; |
dirkx | 0:355018f44c9f | 131 | memset(_cache_off,0, sizeof(_cache_off)); // Rely on min value to be 12 |
dirkx | 0:355018f44c9f | 132 | }; |
dirkx | 0:355018f44c9f | 133 | |
dirkx | 0:355018f44c9f | 134 | uint16_t checkLabelCache(char * name) { |
dirkx | 0:355018f44c9f | 135 | for(int i=0; i < MAXCACHEDNSLABELS; i++) |
dirkx | 0:355018f44c9f | 136 | if (_cache_off[i] && !strcmp(_cache_och[i],name)) |
dirkx | 0:355018f44c9f | 137 | return _cache_off[i]; |
dirkx | 0:355018f44c9f | 138 | return 0; |
dirkx | 0:355018f44c9f | 139 | }; |
dirkx | 0:355018f44c9f | 140 | |
dirkx | 0:355018f44c9f | 141 | void addLabelCache(char * p, char * name) { |
dirkx | 0:355018f44c9f | 142 | _cache_off[labelCacheCnt] = p - labelCacheOffset; |
dirkx | 0:355018f44c9f | 143 | _cache_och[labelCacheCnt] = name; |
dirkx | 0:355018f44c9f | 144 | |
dirkx | 0:355018f44c9f | 145 | labelCacheCnt++; |
dirkx | 1:59820ca5c83a | 146 | // we intentionally do not wack the first entries - as they are the most |
dirkx | 0:355018f44c9f | 147 | // likely ones to be used. |
dirkx | 0:355018f44c9f | 148 | if (labelCacheCnt>=MAXCACHEDNSLABELS) |
dirkx | 0:355018f44c9f | 149 | labelCacheCnt = MAXCACHEDNSLABELS / 3; |
dirkx | 0:355018f44c9f | 150 | }; |
dirkx | 0:355018f44c9f | 151 | #else |
dirkx | 0:355018f44c9f | 152 | #define initLabelCache(x) {} /* Ignored */ |
dirkx | 0:355018f44c9f | 153 | #define checkLabelCache(x) (0) /* never a hit */ |
dirkx | 0:355018f44c9f | 154 | #define addLabelCache(x,y) {} /* Ignored */ |
dirkx | 0:355018f44c9f | 155 | #endif |
dirkx | 0:355018f44c9f | 156 | |
dirkx | 0:355018f44c9f | 157 | char * breakname(char *p, char *name) { |
dirkx | 0:355018f44c9f | 158 | int l = 0, de = 1; |
dirkx | 0:355018f44c9f | 159 | char * q; |
dirkx | 0:355018f44c9f | 160 | uint16_t off; |
dirkx | 0:355018f44c9f | 161 | |
dirkx | 0:355018f44c9f | 162 | do { |
dirkx | 0:355018f44c9f | 163 | if (off = checkLabelCache(name)) { |
dirkx | 0:355018f44c9f | 164 | *p++ = 192 + (off >> 8); |
dirkx | 0:355018f44c9f | 165 | *p++ = (off & 0xFF); |
dirkx | 0:355018f44c9f | 166 | return p; |
dirkx | 0:355018f44c9f | 167 | } else { |
dirkx | 0:355018f44c9f | 168 | addLabelCache(p, name); |
dirkx | 0:355018f44c9f | 169 | }; |
dirkx | 0:355018f44c9f | 170 | |
dirkx | 0:355018f44c9f | 171 | q = index(name,'.'); |
dirkx | 0:355018f44c9f | 172 | if (!q) { |
dirkx | 0:355018f44c9f | 173 | q = name + strlen(name); |
dirkx | 0:355018f44c9f | 174 | de = 0; |
dirkx | 0:355018f44c9f | 175 | }; |
dirkx | 0:355018f44c9f | 176 | l = q - name; |
dirkx | 0:355018f44c9f | 177 | *p++ = l; |
dirkx | 0:355018f44c9f | 178 | memcpy(p, name, l); |
dirkx | 0:355018f44c9f | 179 | p+=l; |
dirkx | 0:355018f44c9f | 180 | name = q + 1; |
dirkx | 0:355018f44c9f | 181 | } while(l && *name); |
dirkx | 0:355018f44c9f | 182 | |
dirkx | 0:355018f44c9f | 183 | // terminating root field if any (not the case for |
dirkx | 0:355018f44c9f | 184 | // things like TXTs). |
dirkx | 0:355018f44c9f | 185 | if (de) *p++ = 0; |
dirkx | 0:355018f44c9f | 186 | return p; |
dirkx | 0:355018f44c9f | 187 | } |
dirkx | 0:355018f44c9f | 188 | |
dirkx | 0:355018f44c9f | 189 | char * mRR(char *p, char * name, uint16_t tpe, uint16_t cls, uint32_t ttl) |
dirkx | 0:355018f44c9f | 190 | { |
dirkx | 0:355018f44c9f | 191 | uint16_t i; |
dirkx | 0:355018f44c9f | 192 | uint32_t j; |
dirkx | 0:355018f44c9f | 193 | |
dirkx | 0:355018f44c9f | 194 | p = breakname(p, name); |
dirkx | 0:355018f44c9f | 195 | |
dirkx | 0:355018f44c9f | 196 | // NOTE: Cannot assume proper byte boundaries. |
dirkx | 0:355018f44c9f | 197 | // |
dirkx | 0:355018f44c9f | 198 | i = htons(tpe); // Type |
dirkx | 0:355018f44c9f | 199 | memcpy(p, &i, 2); |
dirkx | 0:355018f44c9f | 200 | p+=2; |
dirkx | 0:355018f44c9f | 201 | |
dirkx | 0:355018f44c9f | 202 | i = htons(cls); // Class |
dirkx | 0:355018f44c9f | 203 | memcpy(p, &i, 2); |
dirkx | 0:355018f44c9f | 204 | p+=2; |
dirkx | 0:355018f44c9f | 205 | |
dirkx | 0:355018f44c9f | 206 | j = htonl(ttl); // TTL (4 bytes) |
dirkx | 0:355018f44c9f | 207 | memcpy(p, &j, 4); |
dirkx | 0:355018f44c9f | 208 | p+=4; |
dirkx | 0:355018f44c9f | 209 | |
dirkx | 0:355018f44c9f | 210 | return p; |
dirkx | 0:355018f44c9f | 211 | } |
dirkx | 0:355018f44c9f | 212 | |
dirkx | 1:59820ca5c83a | 213 | char * mRRLABEL(char *p, char * name, uint16_t tpe, char ** rr) { |
dirkx | 0:355018f44c9f | 214 | uint16_t i; |
dirkx | 0:355018f44c9f | 215 | |
dirkx | 0:355018f44c9f | 216 | p = mRR(p, name, tpe, 1, MDNS_TTL); // Type, IN, TTL |
dirkx | 0:355018f44c9f | 217 | |
dirkx | 0:355018f44c9f | 218 | // RR String |
dirkx | 0:355018f44c9f | 219 | char * q = p + 2; |
dirkx | 1:59820ca5c83a | 220 | |
dirkx | 1:59820ca5c83a | 221 | for(;*rr;rr++) |
dirkx | 1:59820ca5c83a | 222 | q = breakname(q, *rr); |
dirkx | 1:59820ca5c83a | 223 | |
dirkx | 0:355018f44c9f | 224 | i = htons(q - p - 2); // RDLEN |
dirkx | 0:355018f44c9f | 225 | memcpy(p, &i, 2); |
dirkx | 0:355018f44c9f | 226 | return q; |
dirkx | 0:355018f44c9f | 227 | } |
dirkx | 0:355018f44c9f | 228 | |
dirkx | 1:59820ca5c83a | 229 | char * mPTR(char *p, char * name, char * r) { |
dirkx | 1:59820ca5c83a | 230 | char *rr[] = { r, NULL }; |
dirkx | 1:59820ca5c83a | 231 | return mRRLABEL(p, name, 12 /* PTR */, rr ); |
dirkx | 0:355018f44c9f | 232 | } |
dirkx | 0:355018f44c9f | 233 | |
dirkx | 1:59820ca5c83a | 234 | char * mTXT(char *p, char * name, char ** rr) { |
dirkx | 0:355018f44c9f | 235 | return mRRLABEL(p, name, 16 /* TXT */, rr); |
dirkx | 0:355018f44c9f | 236 | } |
dirkx | 0:355018f44c9f | 237 | |
dirkx | 0:355018f44c9f | 238 | char * mARR(char *p, char * name, IpAddr ip) { |
dirkx | 0:355018f44c9f | 239 | uint16_t i; |
dirkx | 0:355018f44c9f | 240 | |
dirkx | 0:355018f44c9f | 241 | p = mRR(p, name, 1, 1, MDNS_TTL ); // A, IN |
dirkx | 0:355018f44c9f | 242 | |
dirkx | 0:355018f44c9f | 243 | i = htons(4); // RDLEN - we're just doing a single IPv4 address - our primary link ? |
dirkx | 0:355018f44c9f | 244 | memcpy(p, &i, 2); |
dirkx | 0:355018f44c9f | 245 | |
dirkx | 0:355018f44c9f | 246 | // IP already in network order. |
dirkx | 0:355018f44c9f | 247 | memcpy(p+2, &ip, 4); |
dirkx | 0:355018f44c9f | 248 | |
dirkx | 0:355018f44c9f | 249 | return p + 2 + 4; |
dirkx | 0:355018f44c9f | 250 | } |
dirkx | 0:355018f44c9f | 251 | |
dirkx | 0:355018f44c9f | 252 | char * mSRV(char *p, char * name, uint16_t port, char * rr) { |
dirkx | 0:355018f44c9f | 253 | uint16_t i; |
dirkx | 0:355018f44c9f | 254 | char * q; |
dirkx | 0:355018f44c9f | 255 | |
dirkx | 0:355018f44c9f | 256 | p = mRR(p, name, 33, 1, MDNS_TTL); // SRV, IN |
dirkx | 0:355018f44c9f | 257 | |
dirkx | 0:355018f44c9f | 258 | // Keep space for RDLEN |
dirkx | 0:355018f44c9f | 259 | q = p; p+=2; |
dirkx | 0:355018f44c9f | 260 | |
dirkx | 0:355018f44c9f | 261 | i = htons(1); // Priority |
dirkx | 0:355018f44c9f | 262 | memcpy(p, &i, 2); p+=2; |
dirkx | 0:355018f44c9f | 263 | |
dirkx | 0:355018f44c9f | 264 | i = htons(0); // Weight (see rfc2782) |
dirkx | 0:355018f44c9f | 265 | memcpy(p, &i, 2); p+=2; |
dirkx | 0:355018f44c9f | 266 | |
dirkx | 0:355018f44c9f | 267 | i = htons(port); // Port |
dirkx | 0:355018f44c9f | 268 | memcpy(p, &i, 2); p+=2; |
dirkx | 0:355018f44c9f | 269 | |
dirkx | 0:355018f44c9f | 270 | p = breakname(p, rr); |
dirkx | 0:355018f44c9f | 271 | |
dirkx | 0:355018f44c9f | 272 | i = htons(p - q - 2); // RDLEN |
dirkx | 0:355018f44c9f | 273 | memcpy(q, &i, 2); |
dirkx | 0:355018f44c9f | 274 | |
dirkx | 0:355018f44c9f | 275 | return p; |
dirkx | 0:355018f44c9f | 276 | } |
dirkx | 0:355018f44c9f | 277 | |
dirkx | 0:355018f44c9f | 278 | char * qANY(char *p, char * name, uint16_t tpe, uint16_t cls) { |
dirkx | 0:355018f44c9f | 279 | uint16_t i; |
dirkx | 0:355018f44c9f | 280 | p = breakname(p, name); // QNAME |
dirkx | 0:355018f44c9f | 281 | |
dirkx | 0:355018f44c9f | 282 | i = htons(tpe); // QTYPE |
dirkx | 0:355018f44c9f | 283 | memcpy(p, &i, 2); p+=2; |
dirkx | 0:355018f44c9f | 284 | |
dirkx | 0:355018f44c9f | 285 | i = htons(cls); // QCLASS |
dirkx | 0:355018f44c9f | 286 | memcpy(p, &i, 2); p+=2; |
dirkx | 0:355018f44c9f | 287 | |
dirkx | 0:355018f44c9f | 288 | return p; |
dirkx | 0:355018f44c9f | 289 | } |
dirkx | 0:355018f44c9f | 290 | |
dirkx | 0:355018f44c9f | 291 | char * qPTR(char *p, char *name) { |
dirkx | 0:355018f44c9f | 292 | return qANY(p,name,12 /* PTR */,1); |
dirkx | 0:355018f44c9f | 293 | } |
dirkx | 0:355018f44c9f | 294 | |
dirkx | 0:355018f44c9f | 295 | |
dirkx | 0:355018f44c9f | 296 | void mDNSResponder::sendReply(uint16_t tid, Host dst) { |
dirkx | 0:355018f44c9f | 297 | // sent a reply - basically a precooked A/PTR/SRV with the TransactionID |
dirkx | 0:355018f44c9f | 298 | // and my URI squeezed in. |
dirkx | 0:355018f44c9f | 299 | char out[ 1500 ], *p; |
dirkx | 0:355018f44c9f | 300 | DNSPacket * op = (DNSPacket *) out; |
dirkx | 0:355018f44c9f | 301 | |
dirkx | 0:355018f44c9f | 302 | initLabelCache(out); // Offsets are relative to the ID header. |
dirkx | 0:355018f44c9f | 303 | |
dirkx | 0:355018f44c9f | 304 | op->tid = ntohs(tid); |
dirkx | 0:355018f44c9f | 305 | op->flags = ntohs(0x8000U); // Answer |
dirkx | 0:355018f44c9f | 306 | op->question_count = ntohs(1); // Courtesy copy of the question. |
dirkx | 0:355018f44c9f | 307 | op->answer_count = ntohs(1); // The PTR record asked for |
dirkx | 0:355018f44c9f | 308 | op->a_count = ntohs(0); |
dirkx | 0:355018f44c9f | 309 | |
dirkx | 0:355018f44c9f | 310 | // The 2 or 3 extra records (A, SRV and optional TXT) we know will be needed next |
dirkx | 0:355018f44c9f | 311 | op->aa_count = ntohs(moi_txt ? 3 : 2); |
dirkx | 0:355018f44c9f | 312 | |
dirkx | 0:355018f44c9f | 313 | p = out + 12; |
dirkx | 0:355018f44c9f | 314 | |
dirkx | 0:355018f44c9f | 315 | p = qPTR(p,moi_local_proto); |
dirkx | 0:355018f44c9f | 316 | p = mPTR(p,moi_local_proto, moi_local_pglue); |
dirkx | 0:355018f44c9f | 317 | p = mSRV(p,moi_local_pglue,80, moi_local_name); |
dirkx | 1:59820ca5c83a | 318 | if (moi_txt && * moi_txt) |
dirkx | 1:59820ca5c83a | 319 | p = mTXT(p,moi_local_pglue,moi_txt); |
dirkx | 0:355018f44c9f | 320 | p = mARR(p,moi_local_name,moi_ip); // fill out my own IP address. |
dirkx | 0:355018f44c9f | 321 | |
dirkx | 0:355018f44c9f | 322 | m_pUDPSocket->sendto(out,p-out,&dst); |
dirkx | 0:355018f44c9f | 323 | } |
dirkx | 0:355018f44c9f | 324 | |
dirkx | 0:355018f44c9f | 325 | void mDNSResponder::onUDPSocketEvent(UDPSocketEvent e) { |
dirkx | 0:355018f44c9f | 326 | char udp[ 1500 ]; |
dirkx | 0:355018f44c9f | 327 | Host from; |
dirkx | 0:355018f44c9f | 328 | int len; |
dirkx | 0:355018f44c9f | 329 | |
dirkx | 0:355018f44c9f | 330 | switch (e) { |
dirkx | 0:355018f44c9f | 331 | case UDPSOCKET_READABLE: //The only event for now |
dirkx | 0:355018f44c9f | 332 | // parse through the packet; find any PTR requests |
dirkx | 0:355018f44c9f | 333 | // and respond to any for _http._tcp._local. |
dirkx | 0:355018f44c9f | 334 | while ( len = m_pUDPSocket->recvfrom( (char*)&udp, sizeof(udp), &from )) { |
dirkx | 0:355018f44c9f | 335 | DNSPacket * dp = (DNSPacket *) udp; |
dirkx | 0:355018f44c9f | 336 | unsigned int tid = ntohs(dp->tid); |
dirkx | 0:355018f44c9f | 337 | unsigned int flags = ntohs(dp->flags); |
dirkx | 0:355018f44c9f | 338 | unsigned int nQ = ntohs(dp->question_count); |
dirkx | 0:355018f44c9f | 339 | unsigned int nA = ntohs(dp->answer_count); |
dirkx | 0:355018f44c9f | 340 | |
dirkx | 0:355018f44c9f | 341 | if (flags & 2 != 0 || nQ == 0) |
dirkx | 0:355018f44c9f | 342 | continue; // we only want questions |
dirkx | 0:355018f44c9f | 343 | |
dirkx | 0:355018f44c9f | 344 | #define MAXDEPTH 64 |
dirkx | 0:355018f44c9f | 345 | #define MAXRR 192 /* including dot */ |
dirkx | 1:59820ca5c83a | 346 | |
dirkx | 0:355018f44c9f | 347 | // assume nQ zero terminated fields followed by Qtype & Qclass |
dirkx | 0:355018f44c9f | 348 | char * p = udp + 12; |
dirkx | 0:355018f44c9f | 349 | for (int i = 0; i < nQ; i++) { |
dirkx | 0:355018f44c9f | 350 | char buff[ MAXDEPTH * MAXRR ], * ep = buff; |
dirkx | 0:355018f44c9f | 351 | int depth = 0; |
dirkx | 0:355018f44c9f | 352 | int l; |
dirkx | 0:355018f44c9f | 353 | char * q = 0; |
dirkx | 0:355018f44c9f | 354 | |
dirkx | 0:355018f44c9f | 355 | do { |
dirkx | 0:355018f44c9f | 356 | while (((l = *p++) < 192) && (l > 0)) { |
dirkx | 0:355018f44c9f | 357 | if (p + l >= udp + len) { |
dirkx | 0:355018f44c9f | 358 | printf("RR longer than packet\r\n"); |
dirkx | 0:355018f44c9f | 359 | return; |
dirkx | 0:355018f44c9f | 360 | }; |
dirkx | 0:355018f44c9f | 361 | |
dirkx | 0:355018f44c9f | 362 | memcpy(ep,p,l); |
dirkx | 0:355018f44c9f | 363 | ep[l]='.'; |
dirkx | 0:355018f44c9f | 364 | ep += l + 1; |
dirkx | 0:355018f44c9f | 365 | // printf("%d:%s.", p-udp-12,buff); |
dirkx | 0:355018f44c9f | 366 | p += l; |
dirkx | 0:355018f44c9f | 367 | }; |
dirkx | 0:355018f44c9f | 368 | if (l >= 192) { |
dirkx | 0:355018f44c9f | 369 | // construct an offset pointer by wiping the top 1 bits |
dirkx | 0:355018f44c9f | 370 | // and then getting the remaining 8 bytes to make 14. |
dirkx | 0:355018f44c9f | 371 | l -= 192; |
dirkx | 0:355018f44c9f | 372 | l = l << 8; |
dirkx | 0:355018f44c9f | 373 | l += *p++; |
dirkx | 0:355018f44c9f | 374 | // rescue our reference; as we've not gotten the Qt's yet. |
dirkx | 0:355018f44c9f | 375 | if (!q) q = p; |
dirkx | 0:355018f44c9f | 376 | |
dirkx | 0:355018f44c9f | 377 | // printf(" [->%d] ",l); |
dirkx | 0:355018f44c9f | 378 | p = udp + l; |
dirkx | 0:355018f44c9f | 379 | |
dirkx | 0:355018f44c9f | 380 | if (p >= udp + len || p < udp + 12) { |
dirkx | 0:355018f44c9f | 381 | printf("Pointer to wrong place\r\n"); |
dirkx | 0:355018f44c9f | 382 | return; |
dirkx | 0:355018f44c9f | 383 | }; |
dirkx | 0:355018f44c9f | 384 | }; |
dirkx | 0:355018f44c9f | 385 | if (depth++ >= MAXDEPTH) { |
dirkx | 0:355018f44c9f | 386 | printf("Too deep\r\n"); |
dirkx | 0:355018f44c9f | 387 | return; |
dirkx | 0:355018f44c9f | 388 | }; |
dirkx | 0:355018f44c9f | 389 | } while (l); |
dirkx | 0:355018f44c9f | 390 | *ep = 0; |
dirkx | 0:355018f44c9f | 391 | // in case no compression was used at all. |
dirkx | 0:355018f44c9f | 392 | if (!q) q = p; |
dirkx | 0:355018f44c9f | 393 | |
dirkx | 0:355018f44c9f | 394 | unsigned int Qt = htons(q[0] + q[1]*256); |
dirkx | 0:355018f44c9f | 395 | unsigned int Qc = htons(q[2] + q[3]*256); |
dirkx | 0:355018f44c9f | 396 | p = q + 4; |
dirkx | 1:59820ca5c83a | 397 | |
dirkx | 1:59820ca5c83a | 398 | printf("Q for %s\r\n", buff); |
dirkx | 0:355018f44c9f | 399 | // We want PTR records on the INternet of our type |
dirkx | 0:355018f44c9f | 400 | if ((Qt == 12) && (Qc == 1) && !(strcmp(buff,moi_local_proto))) |
dirkx | 0:355018f44c9f | 401 | sendReply(tid,from); |
dirkx | 0:355018f44c9f | 402 | }; |
dirkx | 0:355018f44c9f | 403 | } |
dirkx | 0:355018f44c9f | 404 | break; |
dirkx | 0:355018f44c9f | 405 | } |
dirkx | 0:355018f44c9f | 406 | } |
dirkx | 0:355018f44c9f | 407 | |
dirkx | 0:355018f44c9f | 408 |