PageRenderTime 52ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/testPrograms/udpMulti/main.cpp

https://gitlab.com/Guy1394/MoSync
C++ | 368 lines | 297 code | 37 blank | 34 comment | 48 complexity | 7cc8931104fe9797cdce29c030e022e6 MD5 | raw file
  1. /* Copyright 2013 David Axmark
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. */
  12. /**
  13. * This example shows how to do DNS over UDP while using unbound sockets.
  14. */
  15. #include <maapi.h>
  16. #include <MAUtil/Moblet.h>
  17. #include <MAUtil/Connection.h>
  18. #include <conprint.h>
  19. #include <maassert.h>
  20. #include <mastdlib.h>
  21. #include <mastring.h>
  22. #include <inet_ntop.h>
  23. using namespace MAUtil;
  24. typedef unsigned char u8;
  25. typedef unsigned short u16;
  26. typedef unsigned int u32;
  27. #define BUFSIZE 512
  28. #define EXAMPLE_DOMAIN "example.com"
  29. #define USE_FORCED_PORT 0 // Change this to turn on/off forced port.
  30. #if USE_FORCED_PORT
  31. #define FORCED_PORT ":1234"
  32. #else
  33. #define FORCED_PORT ""
  34. #endif
  35. static u16 htons(u16 x) {
  36. return (x << 8) | (x >> 8);
  37. }
  38. static u16 ntohs(u16 x) {
  39. return (x << 8) | (x >> 8);
  40. }
  41. static void dumpInetAddr(const char* name, const MAConnAddr& addr) {
  42. if(addr.family == CONN_FAMILY_INET4) {
  43. int b = addr.inet4.addr;
  44. printf("%s: %i.%i.%i.%i:%i\n", name,
  45. (b >> 24) & 0xff,
  46. (b >> 16) & 0xff,
  47. (b >> 8) & 0xff,
  48. (b) & 0xff,
  49. addr.inet4.port);
  50. } else if(addr.family == CONN_FAMILY_INET6) {
  51. char buf[128];
  52. inet_ntop6(addr.inet6.addr, buf, sizeof(buf));
  53. printf("%s: %s:%i", name, buf, addr.inet6.port);
  54. } else {
  55. printf("family: %i\n", addr.family);
  56. return;
  57. }
  58. }
  59. class MyMoblet : public Moblet, private ConnectionListener {
  60. private:
  61. char mBuffer[BUFSIZE];
  62. Connection mConn;
  63. bool mRepeat;
  64. int mCount;
  65. bool mInProgress;
  66. u16 mQueryId;
  67. MAConnAddr mAddress;
  68. public:
  69. MyMoblet() : mConn(this) {
  70. mRepeat = false;
  71. mCount = 0;
  72. mInProgress = false;
  73. int res = mConn.connect("datagram://" FORCED_PORT);
  74. printf("connect: %i\n", res);
  75. if(res < 0)
  76. return;
  77. MAConnAddr a;
  78. res = mConn.getAddr(&a);
  79. if(res < 0) {
  80. printf("getAddr: %i\n", res);
  81. } else {
  82. dumpInetAddr("local", a);
  83. }
  84. start(EXAMPLE_DOMAIN);
  85. }
  86. /**
  87. * Shows basic information on how to use the program
  88. */
  89. void showInformation()
  90. {
  91. #if 0
  92. printf("DNS query -\n");
  93. printf(" Press fire key or\n");
  94. printf(" touch the screen\n");
  95. printf("Toggle REPEAT -\n");
  96. printf(" Press 5 key\n");
  97. printf("To EXIT -\n");
  98. printf(" Press 0 key or\n");
  99. printf(" soft right key\n");
  100. #endif
  101. }
  102. void start(const char* domain) {
  103. if(mInProgress)
  104. return;
  105. mInProgress = true;
  106. if(mRepeat) {
  107. mCount++;
  108. printf("%i\n", mCount);
  109. }
  110. printf("Preparing query packet...\n");
  111. sendQuery(domain);
  112. }
  113. virtual void connectFinished(Connection* conn, int result) {
  114. printf("connectFinished: %i\n", result);
  115. if(result < 0) {
  116. return;
  117. }
  118. start(EXAMPLE_DOMAIN);
  119. }
  120. virtual void connWriteFinished(Connection* conn, int result) {
  121. printf("connWriteFinished: %i\n", result);
  122. mConn.recvFrom(mBuffer, sizeof(mBuffer), &mAddress);
  123. }
  124. virtual void connRecvFinished(Connection* conn, int result) {
  125. printf("connRecvFinished: %i\n", result);
  126. if(result < 0) {
  127. return;
  128. }
  129. dumpInetAddr("sender", mAddress);
  130. parseReply(result);
  131. mInProgress = false;
  132. if(mRepeat)
  133. start(EXAMPLE_DOMAIN);
  134. else
  135. showInformation();
  136. }
  137. struct DNS_HEADER {
  138. u16 id;
  139. // bits in bit fields are ordered low-to-high significance.
  140. u8 rd : 1;
  141. u8 tc : 1;
  142. u8 aa : 1;
  143. u8 opcode : 4;
  144. u8 qr : 1;
  145. u8 rcode : 4;
  146. u8 z : 3;
  147. u8 ra : 1;
  148. u16 qdcount;
  149. u16 ancount;
  150. u16 nscount;
  151. u16 arcount;
  152. };
  153. void sendQuery(const char* domain) {
  154. // header
  155. //MAASSERT(sizeof(DNS_HEADER) == 12);
  156. printf("size: %i\n", (int)sizeof(DNS_HEADER));
  157. DNS_HEADER* hp = (DNS_HEADER*)mBuffer;
  158. DNS_HEADER& h(*hp);
  159. mQueryId = rand();
  160. printf("query id: 0x%x\n", mQueryId);
  161. h.id = htons(mQueryId);
  162. h.qr = 0;
  163. h.opcode = 0;
  164. h.tc = 0;
  165. h.rd = 1;
  166. h.z = 0;
  167. h.qdcount = htons(1);
  168. h.ancount = 0;
  169. h.nscount = 0;
  170. h.arcount = 0;
  171. // query section: name
  172. const char* src = domain;
  173. char* dst = mBuffer + sizeof(DNS_HEADER);
  174. while(*src) {
  175. const char* dot = strchr(src, '.');
  176. if(!dot) {
  177. int len = strlen(src);
  178. *(u8*)dst++ = (u8)len;
  179. memcpy(dst, src, len);
  180. dst += len;
  181. break;
  182. }
  183. if(dot == src)
  184. break;
  185. MAASSERT(dot > src);
  186. int len = dot - src;
  187. MAASSERT(len < 256);
  188. *(u8*)dst++ = (u8)len;
  189. memcpy(dst, src, len);
  190. dst += len;
  191. src = dot + 1;
  192. }
  193. *dst++ = 0; // root null label
  194. // type A (01)
  195. *dst++ = 0;
  196. *dst++ = 1;
  197. // class IN (01)
  198. *dst++ = 0;
  199. *dst++ = 1;
  200. u32 packetLen = dst - mBuffer;
  201. MAConnAddr a;
  202. a.family = CONN_FAMILY_INET4;
  203. a.inet4.addr = (192 << 24) | (168 << 16) | (0 << 8) | 1;
  204. a.inet4.port = 53;
  205. mConn.writeTo(mBuffer, packetLen, a);
  206. }
  207. void parseReply(u32 packetLen) {
  208. // ensure header holds sane values.
  209. if(packetLen < sizeof(DNS_HEADER)) {
  210. printf("Packet too small.\n");
  211. return;
  212. }
  213. const DNS_HEADER* hp = (DNS_HEADER*)mBuffer;
  214. const DNS_HEADER& h(*hp);
  215. if(ntohs(h.id) != mQueryId) {
  216. printf("Query ID mismatch: 0x%x != 0x%x\n", mQueryId, h.id);
  217. return;
  218. }
  219. if(!h.qr) {
  220. printf("Not a response!\n");
  221. return;
  222. }
  223. if(h.opcode != 0) {
  224. printf("Not a standard response!\n");
  225. return;
  226. }
  227. if(h.tc) {
  228. printf("Message truncated!\n");
  229. return;
  230. }
  231. if(h.rcode != 0) {
  232. printf("Response code 0x%x\n", h.rcode);
  233. return;
  234. }
  235. const u8* src = (u8*)mBuffer + sizeof(DNS_HEADER);
  236. const u8* end = (u8*)mBuffer + packetLen;
  237. // skip questions
  238. printf("%i questions\n", ntohs(h.qdcount));
  239. for(u16 i=0; i<ntohs(h.qdcount); i++) {
  240. if(!skipName(src, end))
  241. return;
  242. src += 4;
  243. }
  244. // parse answers
  245. printf("%i answers\n", ntohs(h.ancount));
  246. for(u16 i=0; i<ntohs(h.ancount); i++) {
  247. if(!skipName(src, end))
  248. return;
  249. src += 4;
  250. //printf("TTLx: %02x%02x%02x%02x\n", src[0], src[1], src[2], src[3]);
  251. u32 ttl = getU32(src);
  252. printf("TTL %i seconds (0x%x)\n", ttl, ttl);
  253. u16 rdlength = (*src++) << 8;
  254. rdlength |= (*src++);
  255. if(rdlength != 4) {
  256. printf("bad rdlength: 0x%x\n", rdlength);
  257. return;
  258. }
  259. printf("IP: %i.%i.%i.%i\n", src[0], src[1], src[2], src[3]);
  260. }
  261. }
  262. u8 getU8(const u8*& src) {
  263. u8 v = *src++;
  264. //printf("v: 0x%02x\n", v);
  265. return v;
  266. }
  267. u32 getU32(const u8*& src) {
  268. u32 v = 0;
  269. v |= (u32(getU8(src))) << 24;
  270. #if 1
  271. v |= (u32(getU8(src))) << 16;
  272. #else
  273. u8 v8 = getU8(src);
  274. printf("v8: 0x%02x\n", v8);
  275. u32 v32 = v8;
  276. printf("v32: 0x%x\n", v32);
  277. v |= v32 << 16;
  278. printf("v: 0x%x\n", v);
  279. #endif
  280. v |= (u32(getU8(src))) << 8;
  281. v |= (u32(getU8(src)));
  282. return v;
  283. }
  284. bool skipName(const u8*& src, const u8* end) {
  285. do {
  286. if(src >= end) {
  287. printf("Packet too small.\n");
  288. return false;
  289. }
  290. } while(skipLabel(src));
  291. return true;
  292. }
  293. bool skipLabel(const u8*& src) {
  294. u8 len = *src++;
  295. if(len == 0)
  296. return false;
  297. if((len & 0xC0) == 0xC0) { //pointer
  298. src++;
  299. return false;
  300. } else {
  301. src += len;
  302. }
  303. return true;
  304. }
  305. void keyPressEvent(int keyCode, int nativeCode) {
  306. if(keyCode == MAK_0 || keyCode == MAK_SOFTRIGHT || keyCode == MAK_BACK)
  307. maExit(0);
  308. if(keyCode == MAK_FIRE)
  309. start(EXAMPLE_DOMAIN);
  310. if(keyCode == MAK_5) {
  311. mRepeat = !mRepeat;
  312. mCount = 0;
  313. printf("Repeat: %s\n", mRepeat ? "on" : "off");
  314. }
  315. }
  316. /**
  317. * Moblet listener that has been fired when the screen has been pressed.
  318. */
  319. void pointerPressEvent(MAPoint2d p) {
  320. start(EXAMPLE_DOMAIN);
  321. }
  322. };
  323. extern "C" int MAMain() {
  324. InitConsole();
  325. gConsoleLogging = 1;
  326. Moblet::run(new MyMoblet());
  327. return 0;
  328. }