socket_examples.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. #include "socket_examples.h"
  2. #include "lwip/opt.h"
  3. #if LWIP_SOCKET && (LWIP_IPV4 || LWIP_IPV6)
  4. #include "lwip/sockets.h"
  5. #include "lwip/sys.h"
  6. #include <string.h>
  7. #include <stdio.h>
  8. #ifndef SOCK_TARGET_HOST4
  9. #define SOCK_TARGET_HOST4 "192.168.0.1"
  10. #endif
  11. #ifndef SOCK_TARGET_HOST6
  12. #define SOCK_TARGET_HOST6 "FE80::12:34FF:FE56:78AB"
  13. #endif
  14. #ifndef SOCK_TARGET_PORT
  15. #define SOCK_TARGET_PORT 80
  16. #endif
  17. #ifndef SOCK_TARGET_MAXHTTPPAGESIZE
  18. #define SOCK_TARGET_MAXHTTPPAGESIZE 1024
  19. #endif
  20. #ifndef SOCKET_EXAMPLES_RUN_PARALLEL
  21. #define SOCKET_EXAMPLES_RUN_PARALLEL 0
  22. #endif
  23. static const u8_t cmpbuf[8] = {0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab};
  24. /* a helper struct to ensure memory before/after fd_set is not touched */
  25. typedef struct _xx
  26. {
  27. u8_t buf1[8];
  28. fd_set readset;
  29. u8_t buf2[8];
  30. fd_set writeset;
  31. u8_t buf3[8];
  32. fd_set errset;
  33. u8_t buf4[8];
  34. } fdsets;
  35. #define INIT_FDSETS(sets) do { \
  36. memset((sets)->buf1, 0xab, 8); \
  37. memset((sets)->buf2, 0xab, 8); \
  38. memset((sets)->buf3, 0xab, 8); \
  39. memset((sets)->buf4, 0xab, 8); \
  40. }while(0)
  41. #define CHECK_FDSETS(sets) do { \
  42. LWIP_ASSERT("buf1 fail", !memcmp((sets)->buf1, cmpbuf, 8)); \
  43. LWIP_ASSERT("buf2 fail", !memcmp((sets)->buf2, cmpbuf, 8)); \
  44. LWIP_ASSERT("buf3 fail", !memcmp((sets)->buf3, cmpbuf, 8)); \
  45. LWIP_ASSERT("buf4 fail", !memcmp((sets)->buf4, cmpbuf, 8)); \
  46. }while(0)
  47. static ip_addr_t dstaddr;
  48. /** This is an example function that tests
  49. blocking- and nonblocking connect. */
  50. static void
  51. sockex_nonblocking_connect(void *arg)
  52. {
  53. #if LWIP_SOCKET_SELECT
  54. int s;
  55. int ret;
  56. int opt;
  57. #if LWIP_IPV6
  58. struct sockaddr_in6 addr;
  59. #else /* LWIP_IPV6 */
  60. struct sockaddr_in addr;
  61. #endif /* LWIP_IPV6 */
  62. fdsets sets;
  63. struct timeval tv;
  64. u32_t ticks_a, ticks_b;
  65. int err;
  66. const ip_addr_t *ipaddr = (const ip_addr_t*)arg;
  67. struct pollfd fds;
  68. INIT_FDSETS(&sets);
  69. /* set up address to connect to */
  70. memset(&addr, 0, sizeof(addr));
  71. #if LWIP_IPV6
  72. addr.sin6_len = sizeof(addr);
  73. addr.sin6_family = AF_INET6;
  74. addr.sin6_port = PP_HTONS(SOCK_TARGET_PORT);
  75. inet6_addr_from_ip6addr(&addr.sin6_addr, ip_2_ip6(ipaddr));
  76. #else /* LWIP_IPV6 */
  77. addr.sin_len = sizeof(addr);
  78. addr.sin_family = AF_INET;
  79. addr.sin_port = PP_HTONS(SOCK_TARGET_PORT);
  80. inet_addr_from_ip4addr(&addr.sin_addr, ip_2_ip4(ipaddr));
  81. #endif /* LWIP_IPV6 */
  82. /* first try blocking: */
  83. /* create the socket */
  84. #if LWIP_IPV6
  85. s = lwip_socket(AF_INET6, SOCK_STREAM, 0);
  86. #else /* LWIP_IPV6 */
  87. s = lwip_socket(AF_INET, SOCK_STREAM, 0);
  88. #endif /* LWIP_IPV6 */
  89. LWIP_ASSERT("s >= 0", s >= 0);
  90. /* connect */
  91. ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr));
  92. /* should succeed */
  93. LWIP_ASSERT("ret == 0", ret == 0);
  94. /* write something */
  95. ret = lwip_write(s, "test", 4);
  96. LWIP_ASSERT("ret == 4", ret == 4);
  97. /* close */
  98. ret = lwip_close(s);
  99. LWIP_ASSERT("ret == 0", ret == 0);
  100. /* now try nonblocking and close before being connected */
  101. /* create the socket */
  102. #if LWIP_IPV6
  103. s = lwip_socket(AF_INET6, SOCK_STREAM, 0);
  104. #else /* LWIP_IPV6 */
  105. s = lwip_socket(AF_INET, SOCK_STREAM, 0);
  106. #endif /* LWIP_IPV6 */
  107. LWIP_ASSERT("s >= 0", s >= 0);
  108. /* nonblocking */
  109. opt = lwip_fcntl(s, F_GETFL, 0);
  110. LWIP_ASSERT("ret != -1", ret != -1);
  111. opt |= O_NONBLOCK;
  112. ret = lwip_fcntl(s, F_SETFL, opt);
  113. LWIP_ASSERT("ret != -1", ret != -1);
  114. /* connect */
  115. ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr));
  116. /* should have an error: "inprogress" */
  117. LWIP_ASSERT("ret == -1", ret == -1);
  118. err = errno;
  119. LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS);
  120. /* close */
  121. ret = lwip_close(s);
  122. LWIP_ASSERT("ret == 0", ret == 0);
  123. /* try to close again, should fail with EBADF */
  124. ret = lwip_close(s);
  125. LWIP_ASSERT("ret == -1", ret == -1);
  126. err = errno;
  127. LWIP_ASSERT("errno == EBADF", err == EBADF);
  128. printf("closing socket in nonblocking connect succeeded\n");
  129. /* now try nonblocking, connect should succeed:
  130. this test only works if it is fast enough, i.e. no breakpoints, please! */
  131. /* create the socket */
  132. #if LWIP_IPV6
  133. s = lwip_socket(AF_INET6, SOCK_STREAM, 0);
  134. #else /* LWIP_IPV6 */
  135. s = lwip_socket(AF_INET, SOCK_STREAM, 0);
  136. #endif /* LWIP_IPV6 */
  137. LWIP_ASSERT("s >= 0", s >= 0);
  138. /* nonblocking */
  139. opt = 1;
  140. ret = lwip_ioctl(s, FIONBIO, &opt);
  141. LWIP_ASSERT("ret == 0", ret == 0);
  142. /* connect */
  143. ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr));
  144. /* should have an error: "inprogress" */
  145. LWIP_ASSERT("ret == -1", ret == -1);
  146. err = errno;
  147. LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS);
  148. /* write should fail, too */
  149. ret = lwip_write(s, "test", 4);
  150. LWIP_ASSERT("ret == -1", ret == -1);
  151. err = errno;
  152. LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS);
  153. CHECK_FDSETS(&sets);
  154. FD_ZERO(&sets.readset);
  155. CHECK_FDSETS(&sets);
  156. FD_SET(s, &sets.readset);
  157. CHECK_FDSETS(&sets);
  158. FD_ZERO(&sets.writeset);
  159. CHECK_FDSETS(&sets);
  160. FD_SET(s, &sets.writeset);
  161. CHECK_FDSETS(&sets);
  162. FD_ZERO(&sets.errset);
  163. CHECK_FDSETS(&sets);
  164. FD_SET(s, &sets.errset);
  165. CHECK_FDSETS(&sets);
  166. tv.tv_sec = 0;
  167. tv.tv_usec = 0;
  168. /* select without waiting should fail */
  169. ret = lwip_select(s + 1, &sets.readset, &sets.writeset, &sets.errset, &tv);
  170. CHECK_FDSETS(&sets);
  171. LWIP_ASSERT("ret == 0", ret == 0);
  172. LWIP_ASSERT("!FD_ISSET(s, &writeset)", !FD_ISSET(s, &sets.writeset));
  173. LWIP_ASSERT("!FD_ISSET(s, &readset)", !FD_ISSET(s, &sets.readset));
  174. LWIP_ASSERT("!FD_ISSET(s, &errset)", !FD_ISSET(s, &sets.errset));
  175. fds.fd = s;
  176. fds.events = POLLIN|POLLOUT;
  177. fds.revents = 0;
  178. ret = lwip_poll(&fds, 1, 0);
  179. LWIP_ASSERT("ret == 0", ret == 0);
  180. LWIP_ASSERT("fds.revents == 0", fds.revents == 0);
  181. FD_ZERO(&sets.readset);
  182. FD_SET(s, &sets.readset);
  183. FD_ZERO(&sets.writeset);
  184. FD_SET(s, &sets.writeset);
  185. FD_ZERO(&sets.errset);
  186. FD_SET(s, &sets.errset);
  187. ticks_a = sys_now();
  188. /* select with waiting should succeed */
  189. ret = lwip_select(s + 1, &sets.readset, &sets.writeset, &sets.errset, NULL);
  190. ticks_b = sys_now();
  191. LWIP_ASSERT("ret == 1", ret == 1);
  192. LWIP_ASSERT("FD_ISSET(s, &writeset)", FD_ISSET(s, &sets.writeset));
  193. LWIP_ASSERT("!FD_ISSET(s, &readset)", !FD_ISSET(s, &sets.readset));
  194. LWIP_ASSERT("!FD_ISSET(s, &errset)", !FD_ISSET(s, &sets.errset));
  195. fds.fd = s;
  196. fds.events = POLLIN|POLLOUT;
  197. fds.revents = 0;
  198. ret = lwip_poll(&fds, 1, 0);
  199. LWIP_ASSERT("ret == 1", ret == 1);
  200. LWIP_ASSERT("fds.revents & POLLOUT", fds.revents & POLLOUT);
  201. /* now write should succeed */
  202. ret = lwip_write(s, "test", 4);
  203. LWIP_ASSERT("ret == 4", ret == 4);
  204. /* close */
  205. ret = lwip_close(s);
  206. LWIP_ASSERT("ret == 0", ret == 0);
  207. printf("select() needed %d ticks to return writable\n", (int)(ticks_b - ticks_a));
  208. /* now try nonblocking to invalid address:
  209. this test only works if it is fast enough, i.e. no breakpoints, please! */
  210. /* create the socket */
  211. #if LWIP_IPV6
  212. s = lwip_socket(AF_INET6, SOCK_STREAM, 0);
  213. #else /* LWIP_IPV6 */
  214. s = lwip_socket(AF_INET, SOCK_STREAM, 0);
  215. #endif /* LWIP_IPV6 */
  216. LWIP_ASSERT("s >= 0", s >= 0);
  217. /* nonblocking */
  218. opt = 1;
  219. ret = lwip_ioctl(s, FIONBIO, &opt);
  220. LWIP_ASSERT("ret == 0", ret == 0);
  221. #if LWIP_IPV6
  222. addr.sin6_addr.un.u8_addr[0]++; /* this should result in an invalid address */
  223. #else /* LWIP_IPV6 */
  224. addr.sin_addr.s_addr++; /* this should result in an invalid address */
  225. #endif /* LWIP_IPV6 */
  226. /* connect */
  227. ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr));
  228. /* should have an error: "inprogress" */
  229. LWIP_ASSERT("ret == -1", ret == -1);
  230. err = errno;
  231. LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS);
  232. /* write should fail, too */
  233. ret = lwip_write(s, "test", 4);
  234. LWIP_ASSERT("ret == -1", ret == -1);
  235. err = errno;
  236. LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS);
  237. LWIP_UNUSED_ARG(err);
  238. FD_ZERO(&sets.readset);
  239. FD_SET(s, &sets.readset);
  240. FD_ZERO(&sets.writeset);
  241. FD_SET(s, &sets.writeset);
  242. FD_ZERO(&sets.errset);
  243. FD_SET(s, &sets.errset);
  244. tv.tv_sec = 0;
  245. tv.tv_usec = 0;
  246. /* select without waiting should fail */
  247. ret = lwip_select(s + 1, &sets.readset, &sets.writeset, &sets.errset, &tv);
  248. LWIP_ASSERT("ret == 0", ret == 0);
  249. FD_ZERO(&sets.readset);
  250. FD_SET(s, &sets.readset);
  251. FD_ZERO(&sets.writeset);
  252. FD_SET(s, &sets.writeset);
  253. FD_ZERO(&sets.errset);
  254. FD_SET(s, &sets.errset);
  255. ticks_a = sys_now();
  256. /* select with waiting should eventually succeed and return errset! */
  257. ret = lwip_select(s + 1, &sets.readset, &sets.writeset, &sets.errset, NULL);
  258. ticks_b = sys_now();
  259. LWIP_ASSERT("ret > 0", ret > 0);
  260. LWIP_ASSERT("FD_ISSET(s, &errset)", FD_ISSET(s, &sets.errset));
  261. /*LWIP_ASSERT("!FD_ISSET(s, &readset)", !FD_ISSET(s, &sets.readset));
  262. LWIP_ASSERT("!FD_ISSET(s, &writeset)", !FD_ISSET(s, &sets.writeset));*/
  263. /* close */
  264. ret = lwip_close(s);
  265. LWIP_ASSERT("ret == 0", ret == 0);
  266. LWIP_UNUSED_ARG(ret);
  267. printf("select() needed %d ticks to return error\n", (int)(ticks_b - ticks_a));
  268. printf("sockex_nonblocking_connect finished successfully\n");
  269. #else
  270. LWIP_UNUSED_ARG(arg);
  271. #endif
  272. }
  273. /** This is an example function that tests
  274. the recv function (timeout etc.). */
  275. static void
  276. sockex_testrecv(void *arg)
  277. {
  278. int s;
  279. int ret;
  280. int err;
  281. #if LWIP_SO_SNDRCVTIMEO_NONSTANDARD
  282. int opt, opt2;
  283. #else
  284. struct timeval opt, opt2;
  285. #endif
  286. socklen_t opt2size;
  287. #if LWIP_IPV6
  288. struct sockaddr_in6 addr;
  289. #else /* LWIP_IPV6 */
  290. struct sockaddr_in addr;
  291. #endif /* LWIP_IPV6 */
  292. size_t len;
  293. char rxbuf[SOCK_TARGET_MAXHTTPPAGESIZE];
  294. #if LWIP_SOCKET_SELECT
  295. fd_set readset;
  296. fd_set errset;
  297. struct timeval tv;
  298. #endif
  299. const ip_addr_t *ipaddr = (const ip_addr_t*)arg;
  300. /* set up address to connect to */
  301. memset(&addr, 0, sizeof(addr));
  302. #if LWIP_IPV6
  303. addr.sin6_len = sizeof(addr);
  304. addr.sin6_family = AF_INET6;
  305. addr.sin6_port = PP_HTONS(SOCK_TARGET_PORT);
  306. inet6_addr_from_ip6addr(&addr.sin6_addr, ip_2_ip6(ipaddr));
  307. #else /* LWIP_IPV6 */
  308. addr.sin_len = sizeof(addr);
  309. addr.sin_family = AF_INET;
  310. addr.sin_port = PP_HTONS(SOCK_TARGET_PORT);
  311. inet_addr_from_ip4addr(&addr.sin_addr, ip_2_ip4(ipaddr));
  312. #endif /* LWIP_IPV6 */
  313. /* first try blocking: */
  314. /* create the socket */
  315. #if LWIP_IPV6
  316. s = lwip_socket(AF_INET6, SOCK_STREAM, 0);
  317. #else /* LWIP_IPV6 */
  318. s = lwip_socket(AF_INET, SOCK_STREAM, 0);
  319. #endif /* LWIP_IPV6 */
  320. LWIP_ASSERT("s >= 0", s >= 0);
  321. /* connect */
  322. ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr));
  323. /* should succeed */
  324. LWIP_ASSERT("ret == 0", ret == 0);
  325. /* set recv timeout (100 ms) */
  326. #if LWIP_SO_SNDRCVTIMEO_NONSTANDARD
  327. opt = 100;
  328. #else
  329. opt.tv_sec = 0;
  330. opt.tv_usec = 100 * 1000;
  331. #endif
  332. ret = lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &opt, sizeof(opt));
  333. LWIP_ASSERT("ret == 0", ret == 0);
  334. #if LWIP_SO_SNDRCVTIMEO_NONSTANDARD
  335. opt2 = 0;
  336. #else
  337. opt2.tv_sec = 0;
  338. opt2.tv_usec = 0;
  339. #endif
  340. opt2size = sizeof(opt2);
  341. ret = lwip_getsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &opt2, &opt2size);
  342. LWIP_ASSERT("ret == 0", ret == 0);
  343. LWIP_ASSERT("opt2size == sizeof(opt2)", opt2size == sizeof(opt2));
  344. #if LWIP_SO_SNDRCVTIMEO_NONSTANDARD
  345. LWIP_ASSERT("opt == opt2", opt == opt2);
  346. #else
  347. LWIP_ASSERT("opt == opt2", opt.tv_sec == opt2.tv_sec);
  348. LWIP_ASSERT("opt == opt2", opt.tv_usec == opt2.tv_usec);
  349. #endif
  350. /* write the start of a GET request */
  351. #define SNDSTR1 "G"
  352. len = strlen(SNDSTR1);
  353. ret = lwip_write(s, SNDSTR1, len);
  354. LWIP_ASSERT("ret == len", ret == (int)len);
  355. /* should time out if the other side is a good HTTP server */
  356. ret = lwip_read(s, rxbuf, 1);
  357. LWIP_ASSERT("ret == -1", ret == -1);
  358. err = errno;
  359. LWIP_ASSERT("errno == EAGAIN", err == EAGAIN);
  360. LWIP_UNUSED_ARG(err);
  361. /* write the rest of a GET request */
  362. #define SNDSTR2 "ET / HTTP_1.1\r\n\r\n"
  363. len = strlen(SNDSTR2);
  364. ret = lwip_write(s, SNDSTR2, len);
  365. LWIP_ASSERT("ret == len", ret == (int)len);
  366. /* wait a while: should be enough for the server to send a response */
  367. sys_msleep(1000);
  368. /* should not time out but receive a response */
  369. ret = lwip_read(s, rxbuf, SOCK_TARGET_MAXHTTPPAGESIZE);
  370. LWIP_ASSERT("ret > 0", ret > 0);
  371. #if LWIP_SOCKET_SELECT
  372. /* now select should directly return because the socket is readable */
  373. FD_ZERO(&readset);
  374. FD_ZERO(&errset);
  375. FD_SET(s, &readset);
  376. FD_SET(s, &errset);
  377. tv.tv_sec = 10;
  378. tv.tv_usec = 0;
  379. ret = lwip_select(s + 1, &readset, NULL, &errset, &tv);
  380. LWIP_ASSERT("ret == 1", ret == 1);
  381. LWIP_ASSERT("!FD_ISSET(s, &errset)", !FD_ISSET(s, &errset));
  382. LWIP_ASSERT("FD_ISSET(s, &readset)", FD_ISSET(s, &readset));
  383. #endif
  384. /* should not time out but receive a response */
  385. ret = lwip_read(s, rxbuf, SOCK_TARGET_MAXHTTPPAGESIZE);
  386. /* might receive a second packet for HTTP/1.1 servers */
  387. if (ret > 0) {
  388. /* should return 0: closed */
  389. ret = lwip_read(s, rxbuf, SOCK_TARGET_MAXHTTPPAGESIZE);
  390. LWIP_ASSERT("ret == 0", ret == 0);
  391. }
  392. /* close */
  393. ret = lwip_close(s);
  394. LWIP_ASSERT("ret == 0", ret == 0);
  395. LWIP_UNUSED_ARG(ret);
  396. printf("sockex_testrecv finished successfully\n");
  397. }
  398. #if LWIP_SOCKET_SELECT
  399. /** helper struct for the 2 functions below (multithreaded: thread-argument) */
  400. struct sockex_select_helper {
  401. int socket;
  402. int wait_read;
  403. int expect_read;
  404. int wait_write;
  405. int expect_write;
  406. int wait_err;
  407. int expect_err;
  408. int wait_ms;
  409. sys_sem_t sem;
  410. };
  411. /** helper thread to wait for socket events using select */
  412. static void
  413. sockex_select_waiter(void *arg)
  414. {
  415. struct sockex_select_helper *helper = (struct sockex_select_helper *)arg;
  416. int ret;
  417. fd_set readset;
  418. fd_set writeset;
  419. fd_set errset;
  420. struct timeval tv;
  421. LWIP_ASSERT("helper != NULL", helper != NULL);
  422. FD_ZERO(&readset);
  423. FD_ZERO(&writeset);
  424. FD_ZERO(&errset);
  425. if (helper->wait_read) {
  426. FD_SET(helper->socket, &readset);
  427. }
  428. if (helper->wait_write) {
  429. FD_SET(helper->socket, &writeset);
  430. }
  431. if (helper->wait_err) {
  432. FD_SET(helper->socket, &errset);
  433. }
  434. tv.tv_sec = helper->wait_ms / 1000;
  435. tv.tv_usec = (helper->wait_ms % 1000) * 1000;
  436. ret = lwip_select(helper->socket, &readset, &writeset, &errset, &tv);
  437. if (helper->expect_read || helper->expect_write || helper->expect_err) {
  438. LWIP_ASSERT("ret > 0", ret > 0);
  439. } else {
  440. LWIP_ASSERT("ret == 0", ret == 0);
  441. }
  442. LWIP_UNUSED_ARG(ret);
  443. if (helper->expect_read) {
  444. LWIP_ASSERT("FD_ISSET(helper->socket, &readset)", FD_ISSET(helper->socket, &readset));
  445. } else {
  446. LWIP_ASSERT("!FD_ISSET(helper->socket, &readset)", !FD_ISSET(helper->socket, &readset));
  447. }
  448. if (helper->expect_write) {
  449. LWIP_ASSERT("FD_ISSET(helper->socket, &writeset)", FD_ISSET(helper->socket, &writeset));
  450. } else {
  451. LWIP_ASSERT("!FD_ISSET(helper->socket, &writeset)", !FD_ISSET(helper->socket, &writeset));
  452. }
  453. if (helper->expect_err) {
  454. LWIP_ASSERT("FD_ISSET(helper->socket, &errset)", FD_ISSET(helper->socket, &errset));
  455. } else {
  456. LWIP_ASSERT("!FD_ISSET(helper->socket, &errset)", !FD_ISSET(helper->socket, &errset));
  457. }
  458. sys_sem_signal(&helper->sem);
  459. }
  460. /** This is an example function that tests
  461. more than one thread being active in select. */
  462. static void
  463. sockex_testtwoselects(void *arg)
  464. {
  465. int s1;
  466. int s2;
  467. int ret;
  468. #if LWIP_IPV6
  469. struct sockaddr_in6 addr;
  470. #else /* LWIP_IPV6 */
  471. struct sockaddr_in addr;
  472. #endif /* LWIP_IPV6 */
  473. size_t len;
  474. err_t lwiperr;
  475. struct sockex_select_helper h1, h2, h3, h4;
  476. const ip_addr_t *ipaddr = (const ip_addr_t*)arg;
  477. /* set up address to connect to */
  478. memset(&addr, 0, sizeof(addr));
  479. #if LWIP_IPV6
  480. addr.sin6_len = sizeof(addr);
  481. addr.sin6_family = AF_INET6;
  482. addr.sin6_port = PP_HTONS(SOCK_TARGET_PORT);
  483. inet6_addr_from_ip6addr(&addr.sin6_addr, ip_2_ip6(ipaddr));
  484. #else /* LWIP_IPV6 */
  485. addr.sin_len = sizeof(addr);
  486. addr.sin_family = AF_INET;
  487. addr.sin_port = PP_HTONS(SOCK_TARGET_PORT);
  488. inet_addr_from_ip4addr(&addr.sin_addr, ip_2_ip4(ipaddr));
  489. #endif /* LWIP_IPV6 */
  490. /* create the sockets */
  491. #if LWIP_IPV6
  492. s1 = lwip_socket(AF_INET6, SOCK_STREAM, 0);
  493. s2 = lwip_socket(AF_INET6, SOCK_STREAM, 0);
  494. #else /* LWIP_IPV6 */
  495. s1 = lwip_socket(AF_INET, SOCK_STREAM, 0);
  496. s2 = lwip_socket(AF_INET, SOCK_STREAM, 0);
  497. #endif /* LWIP_IPV6 */
  498. LWIP_ASSERT("s1 >= 0", s1 >= 0);
  499. LWIP_ASSERT("s2 >= 0", s2 >= 0);
  500. /* connect, should succeed */
  501. ret = lwip_connect(s1, (struct sockaddr*)&addr, sizeof(addr));
  502. LWIP_ASSERT("ret == 0", ret == 0);
  503. ret = lwip_connect(s2, (struct sockaddr*)&addr, sizeof(addr));
  504. LWIP_ASSERT("ret == 0", ret == 0);
  505. /* write the start of a GET request */
  506. #define SNDSTR1 "G"
  507. len = strlen(SNDSTR1);
  508. ret = lwip_write(s1, SNDSTR1, len);
  509. LWIP_ASSERT("ret == len", ret == (int)len);
  510. ret = lwip_write(s2, SNDSTR1, len);
  511. LWIP_ASSERT("ret == len", ret == (int)len);
  512. LWIP_UNUSED_ARG(ret);
  513. h1.wait_read = 1;
  514. h1.wait_write = 1;
  515. h1.wait_err = 1;
  516. h1.expect_read = 0;
  517. h1.expect_write = 0;
  518. h1.expect_err = 0;
  519. lwiperr = sys_sem_new(&h1.sem, 0);
  520. LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK);
  521. h1.socket = s1;
  522. h1.wait_ms = 500;
  523. h2 = h1;
  524. lwiperr = sys_sem_new(&h2.sem, 0);
  525. LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK);
  526. h2.socket = s2;
  527. h2.wait_ms = 1000;
  528. h3 = h1;
  529. lwiperr = sys_sem_new(&h3.sem, 0);
  530. LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK);
  531. h3.socket = s2;
  532. h3.wait_ms = 1500;
  533. h4 = h1;
  534. lwiperr = sys_sem_new(&h4.sem, 0);
  535. LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK);
  536. LWIP_UNUSED_ARG(lwiperr);
  537. h4.socket = s2;
  538. h4.wait_ms = 2000;
  539. /* select: all sockets should time out if the other side is a good HTTP server */
  540. sys_thread_new("sockex_select_waiter1", sockex_select_waiter, &h2, 0, 0);
  541. sys_msleep(100);
  542. sys_thread_new("sockex_select_waiter2", sockex_select_waiter, &h1, 0, 0);
  543. sys_msleep(100);
  544. sys_thread_new("sockex_select_waiter2", sockex_select_waiter, &h4, 0, 0);
  545. sys_msleep(100);
  546. sys_thread_new("sockex_select_waiter2", sockex_select_waiter, &h3, 0, 0);
  547. sys_sem_wait(&h1.sem);
  548. sys_sem_wait(&h2.sem);
  549. sys_sem_wait(&h3.sem);
  550. sys_sem_wait(&h4.sem);
  551. /* close */
  552. ret = lwip_close(s1);
  553. LWIP_ASSERT("ret == 0", ret == 0);
  554. ret = lwip_close(s2);
  555. LWIP_ASSERT("ret == 0", ret == 0);
  556. printf("sockex_testtwoselects finished successfully\n");
  557. }
  558. #else
  559. static void
  560. sockex_testtwoselects(void *arg)
  561. {
  562. LWIP_UNUSED_ARG(arg);
  563. }
  564. #endif
  565. #if !SOCKET_EXAMPLES_RUN_PARALLEL
  566. static void
  567. socket_example_test(void* arg)
  568. {
  569. sys_msleep(1000);
  570. sockex_nonblocking_connect(arg);
  571. sockex_testrecv(arg);
  572. sockex_testtwoselects(arg);
  573. printf("all tests done, thread ending\n");
  574. }
  575. #endif
  576. void socket_examples_init(void)
  577. {
  578. int addr_ok;
  579. #if LWIP_IPV6
  580. IP_SET_TYPE_VAL(dstaddr, IPADDR_TYPE_V6);
  581. addr_ok = ip6addr_aton(SOCK_TARGET_HOST6, ip_2_ip6(&dstaddr));
  582. #else /* LWIP_IPV6 */
  583. IP_SET_TYPE_VAL(dstaddr, IPADDR_TYPE_V4);
  584. addr_ok = ip4addr_aton(SOCK_TARGET_HOST4, ip_2_ip4(&dstaddr));
  585. #endif /* LWIP_IPV6 */
  586. LWIP_ASSERT("invalid address", addr_ok);
  587. #if SOCKET_EXAMPLES_RUN_PARALLEL
  588. sys_thread_new("sockex_nonblocking_connect", sockex_nonblocking_connect, &dstaddr, 0, 0);
  589. sys_thread_new("sockex_testrecv", sockex_testrecv, &dstaddr, 0, 0);
  590. sys_thread_new("sockex_testtwoselects", sockex_testtwoselects, &dstaddr, 0, 0);
  591. #else
  592. sys_thread_new("socket_example_test", socket_example_test, &dstaddr, 0, 0);
  593. #endif
  594. }
  595. #endif /* LWIP_SOCKET */