iperf.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. /**
  2. * iperf-liked network performance tool
  3. *
  4. */
  5. #include <rtthread.h>
  6. #include <string.h>
  7. #include <stdint.h>
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <fcntl.h>
  11. #include <unistd.h>
  12. #include <sys/time.h>
  13. #include <sys/socket.h>
  14. #include <sys/select.h>
  15. #include <netdb.h>
  16. #define DBG_SECTION_NAME "iperf"
  17. #define DBG_LEVEL DBG_INFO
  18. #include <rtdbg.h>
  19. #define IPERF_PORT 5001
  20. #define IPERF_BUFSZ (4 * 1024)
  21. #define IPERF_MODE_STOP 0
  22. #define IPERF_MODE_SERVER 1
  23. #define IPERF_MODE_CLIENT 2
  24. #if (RT_VER_NUM >= 0x50000)
  25. #define IPERF_GET_THREAD_NAME(th) (th->parent.name)
  26. #else
  27. #define IPERF_GET_THREAD_NAME(th) (th->name)
  28. #endif
  29. typedef struct
  30. {
  31. int mode;
  32. char *host;
  33. int port;
  34. } IPERF_PARAM;
  35. static IPERF_PARAM param = {IPERF_MODE_STOP, NULL, IPERF_PORT};
  36. static void iperf_udp_client(void *thread_param)
  37. {
  38. int sock;
  39. rt_uint32_t *buffer;
  40. struct sockaddr_in server;
  41. rt_uint32_t packet_count = 0;
  42. rt_uint32_t tick, tick1, tick2;
  43. int send_size;
  44. int ret;
  45. rt_uint64_t sentlen = 0;
  46. send_size = IPERF_BUFSZ > 1470 ? 1470 : IPERF_BUFSZ;
  47. buffer = rt_malloc(IPERF_BUFSZ);
  48. if (buffer == NULL)
  49. {
  50. return;
  51. }
  52. rt_memset(buffer, 0x00, IPERF_BUFSZ);
  53. sock = socket(PF_INET, SOCK_DGRAM, 0);
  54. if(sock < 0)
  55. {
  56. LOG_E("can't create socket!");
  57. rt_free(buffer);
  58. return;
  59. }
  60. server.sin_family = PF_INET;
  61. server.sin_port = htons(param.port);
  62. server.sin_addr.s_addr = inet_addr(param.host);
  63. LOG_I("iperf udp mode run...");
  64. tick1 = rt_tick_get();
  65. while (param.mode != IPERF_MODE_STOP)
  66. {
  67. packet_count++;
  68. tick = rt_tick_get();
  69. buffer[0] = htonl(packet_count);
  70. buffer[1] = htonl(tick / RT_TICK_PER_SECOND);
  71. buffer[2] = htonl((tick % RT_TICK_PER_SECOND) * 1000);
  72. ret = sendto(sock, buffer, send_size, 0, (struct sockaddr *)&server, sizeof(struct sockaddr_in));
  73. if (ret > 0)
  74. {
  75. sentlen += ret;
  76. }
  77. if (ret < 0) break;
  78. tick2 = rt_tick_get();
  79. if (tick2 - tick1 >= RT_TICK_PER_SECOND * 5)
  80. {
  81. long data;
  82. int integer, decimal;
  83. rt_thread_t tid;
  84. tid = rt_thread_self();
  85. data = sentlen * RT_TICK_PER_SECOND / 125 / (tick2 - tick1);
  86. integer = data/1000;
  87. decimal = data%1000;
  88. LOG_I("%s: %d.%03d0 Mbps!", IPERF_GET_THREAD_NAME(tid), integer, decimal);
  89. tick1 = tick2;
  90. sentlen = 0;
  91. }
  92. }
  93. closesocket(sock);
  94. rt_free(buffer);
  95. }
  96. static void iperf_udp_server(void *thread_param)
  97. {
  98. int sock;
  99. rt_uint32_t *buffer;
  100. struct sockaddr_in server;
  101. struct sockaddr_in sender;
  102. int sender_len, r_size;
  103. rt_uint64_t sentlen;
  104. rt_uint32_t pcount = 0, last_pcount = 0;
  105. rt_uint32_t lost, total;
  106. rt_tick_t tick1, tick2;
  107. struct timeval timeout;
  108. buffer = rt_malloc(IPERF_BUFSZ);
  109. if (buffer == NULL)
  110. {
  111. return;
  112. }
  113. sock = socket(PF_INET, SOCK_DGRAM, 0);
  114. if(sock < 0)
  115. {
  116. LOG_E("can't create socket! exit!");
  117. return;
  118. }
  119. server.sin_family = PF_INET;
  120. server.sin_port = htons(param.port);
  121. server.sin_addr.s_addr = inet_addr("0.0.0.0");
  122. timeout.tv_sec = 2;
  123. timeout.tv_usec = 0;
  124. if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) == -1)
  125. {
  126. LOG_E("setsockopt failed!");
  127. closesocket(sock);
  128. rt_free(buffer);
  129. return;
  130. }
  131. if (bind(sock, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0)
  132. {
  133. LOG_E("iperf server bind failed! exit!");
  134. closesocket(sock);
  135. rt_free(buffer);
  136. return;
  137. }
  138. while (param.mode != IPERF_MODE_STOP)
  139. {
  140. tick1 = rt_tick_get();
  141. tick2 = tick1;
  142. lost = 0;
  143. total = 0;
  144. sentlen = 0;
  145. while ((tick2 - tick1) < (RT_TICK_PER_SECOND * 5))
  146. {
  147. r_size = recvfrom(sock, buffer, IPERF_BUFSZ, 0, (struct sockaddr *)&sender, (socklen_t*)&sender_len);
  148. if (r_size > 12)
  149. {
  150. pcount = ntohl(buffer[0]);
  151. if (last_pcount < pcount)
  152. {
  153. lost += pcount - last_pcount - 1;
  154. total += pcount - last_pcount;
  155. }
  156. else
  157. {
  158. last_pcount = pcount;
  159. }
  160. last_pcount = pcount;
  161. sentlen += r_size;
  162. }
  163. tick2 = rt_tick_get();
  164. }
  165. if (sentlen > 0)
  166. {
  167. long data;
  168. int integer, decimal;
  169. rt_thread_t tid;
  170. tid = rt_thread_self();
  171. data = sentlen * RT_TICK_PER_SECOND / 125 / (tick2 - tick1);
  172. integer = data/1000;
  173. decimal = data%1000;
  174. LOG_I("%s: %d.%03d0 Mbps! lost:%d total:%d", IPERF_GET_THREAD_NAME(tid), integer, decimal, lost, total);
  175. }
  176. }
  177. rt_free(buffer);
  178. closesocket(sock);
  179. }
  180. static void iperf_client(void *thread_param)
  181. {
  182. int i;
  183. int sock;
  184. int ret;
  185. int tips = 1;
  186. uint8_t *send_buf;
  187. rt_uint64_t sentlen;
  188. rt_tick_t tick1, tick2;
  189. struct sockaddr_in addr;
  190. send_buf = (uint8_t *) rt_malloc(IPERF_BUFSZ);
  191. if (!send_buf) return ;
  192. for (i = 0; i < IPERF_BUFSZ; i ++)
  193. send_buf[i] = i & 0xff;
  194. while (param.mode != IPERF_MODE_STOP)
  195. {
  196. sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  197. if (sock < 0)
  198. {
  199. LOG_E("create socket failed!");
  200. rt_thread_delay(RT_TICK_PER_SECOND);
  201. continue;
  202. }
  203. addr.sin_family = PF_INET;
  204. addr.sin_port = htons(param.port);
  205. addr.sin_addr.s_addr = inet_addr((char *)param.host);
  206. ret = connect(sock, (const struct sockaddr *)&addr, sizeof(addr));
  207. if (ret == -1)
  208. {
  209. if (tips)
  210. {
  211. LOG_E("Connect to iperf server faile, Waiting for the server to open!");
  212. tips = 0;
  213. }
  214. closesocket(sock);
  215. rt_thread_delay(RT_TICK_PER_SECOND);
  216. continue;
  217. }
  218. LOG_I("Connect to iperf server successful!");
  219. {
  220. int flag = 1;
  221. setsockopt(sock,
  222. IPPROTO_TCP, /* set option at TCP level */
  223. TCP_NODELAY, /* name of option */
  224. (void *) &flag, /* the cast is historical cruft */
  225. sizeof(int)); /* length of option value */
  226. }
  227. sentlen = 0;
  228. tick1 = rt_tick_get();
  229. while (param.mode != IPERF_MODE_STOP)
  230. {
  231. tick2 = rt_tick_get();
  232. if (tick2 - tick1 >= RT_TICK_PER_SECOND * 5)
  233. {
  234. long data;
  235. int integer, decimal;
  236. rt_thread_t tid;
  237. tid = rt_thread_self();
  238. data = sentlen * RT_TICK_PER_SECOND / 125 / (tick2 - tick1);
  239. integer = data/1000;
  240. decimal = data%1000;
  241. LOG_I("%s: %d.%03d0 Mbps!", IPERF_GET_THREAD_NAME(tid), integer, decimal);
  242. tick1 = tick2;
  243. sentlen = 0;
  244. }
  245. ret = send(sock, send_buf, IPERF_BUFSZ, 0);
  246. if (ret > 0)
  247. {
  248. sentlen += ret;
  249. }
  250. if (ret < 0) break;
  251. }
  252. closesocket(sock);
  253. rt_thread_delay(RT_TICK_PER_SECOND * 2);
  254. LOG_W("Disconnected, iperf server shut down!");
  255. tips = 1;
  256. }
  257. rt_free(send_buf);
  258. }
  259. void iperf_server(void *thread_param)
  260. {
  261. uint8_t *recv_data;
  262. socklen_t sin_size;
  263. rt_tick_t tick1, tick2;
  264. int sock = -1, connected, bytes_received;
  265. rt_uint64_t recvlen;
  266. struct sockaddr_in server_addr, client_addr;
  267. fd_set readset;
  268. struct timeval timeout;
  269. recv_data = (uint8_t *)rt_malloc(IPERF_BUFSZ);
  270. if (recv_data == RT_NULL)
  271. {
  272. LOG_E("No memory!");
  273. goto __exit;
  274. }
  275. sock = socket(AF_INET, SOCK_STREAM, 0);
  276. if (sock < 0)
  277. {
  278. LOG_E("Socket error!");
  279. goto __exit;
  280. }
  281. server_addr.sin_family = AF_INET;
  282. server_addr.sin_port = htons(param.port);
  283. server_addr.sin_addr.s_addr = INADDR_ANY;
  284. rt_memset(&(server_addr.sin_zero), 0x0, sizeof(server_addr.sin_zero));
  285. if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
  286. {
  287. LOG_E("Unable to bind!");
  288. goto __exit;
  289. }
  290. if (listen(sock, 5) == -1)
  291. {
  292. LOG_E("Listen error!");
  293. goto __exit;
  294. }
  295. timeout.tv_sec = 3;
  296. timeout.tv_usec = 0;
  297. while (param.mode != IPERF_MODE_STOP)
  298. {
  299. FD_ZERO(&readset);
  300. FD_SET(sock, &readset);
  301. if (select(sock + 1, &readset, RT_NULL, RT_NULL, &timeout) == 0)
  302. continue;
  303. sin_size = sizeof(struct sockaddr_in);
  304. connected = accept(sock, (struct sockaddr *)&client_addr, &sin_size);
  305. LOG_I("new client connected from (%s, %d)",
  306. inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
  307. {
  308. int flag = 1;
  309. setsockopt(connected,
  310. IPPROTO_TCP, /* set option at TCP level */
  311. TCP_NODELAY, /* name of option */
  312. (void *) &flag, /* the cast is historical cruft */
  313. sizeof(int)); /* length of option value */
  314. }
  315. recvlen = 0;
  316. tick1 = rt_tick_get();
  317. while (param.mode != IPERF_MODE_STOP)
  318. {
  319. bytes_received = recv(connected, recv_data, IPERF_BUFSZ, 0);
  320. if (bytes_received <= 0) break;
  321. recvlen += bytes_received;
  322. tick2 = rt_tick_get();
  323. if (tick2 - tick1 >= RT_TICK_PER_SECOND * 5)
  324. {
  325. long data;
  326. int integer, decimal;
  327. rt_thread_t tid;
  328. tid = rt_thread_self();
  329. data = recvlen * RT_TICK_PER_SECOND / 125 / (tick2 - tick1);
  330. integer = data/1000;
  331. decimal = data%1000;
  332. LOG_I("%s: %d.%03d0 Mbps!", IPERF_GET_THREAD_NAME(tid), integer, decimal);
  333. tick1 = tick2;
  334. recvlen = 0;
  335. }
  336. }
  337. LOG_W("client disconnected (%s, %d)",
  338. inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
  339. if (connected >= 0) closesocket(connected);
  340. connected = -1;
  341. }
  342. __exit:
  343. if (sock >= 0) closesocket(sock);
  344. if (recv_data) rt_free(recv_data);
  345. }
  346. void iperf_usage(void)
  347. {
  348. rt_kprintf("Usage: iperf [-s|-c host] [options] [multi-threaded]\n");
  349. rt_kprintf(" iperf [-h|--stop]\n");
  350. rt_kprintf("\n");
  351. rt_kprintf("Client/Server:\n");
  352. rt_kprintf(" -p # server port to listen on/connect to\n");
  353. rt_kprintf("\n");
  354. rt_kprintf("Server specific:\n");
  355. rt_kprintf(" -s run in server mode\n");
  356. rt_kprintf("\n");
  357. rt_kprintf("Client specific:\n");
  358. rt_kprintf(" -c <host> run in client mode, connecting to <host>\n");
  359. rt_kprintf("\n");
  360. rt_kprintf("Miscellaneous:\n");
  361. rt_kprintf(" -h print this message and quit\n");
  362. rt_kprintf(" --stop stop iperf program\n");
  363. rt_kprintf(" -u testing UDP protocol\n");
  364. rt_kprintf(" -m <time> the number of multi-threaded\n");
  365. return;
  366. }
  367. int iperf(int argc, char **argv)
  368. {
  369. int mode = 0; /* server mode */
  370. char *host = NULL;
  371. int port = IPERF_PORT;
  372. int numtid = 1;
  373. int use_udp = 0;
  374. int index = 1;
  375. if (argc == 1)
  376. {
  377. goto __usage;
  378. }
  379. if (strcmp(argv[1], "-u") == 0)
  380. {
  381. index = 2;
  382. use_udp = 1;
  383. }
  384. if (strcmp(argv[index], "-h") == 0) goto __usage;
  385. else if (strcmp(argv[index], "--stop") == 0)
  386. {
  387. /* stop iperf */
  388. param.mode = IPERF_MODE_STOP;
  389. return 0;
  390. }
  391. else if (strcmp(argv[index], "-s") == 0)
  392. {
  393. mode = IPERF_MODE_SERVER; /* server mode */
  394. /* iperf -s -p 5000 */
  395. if (argc >= 4)
  396. {
  397. if (strcmp(argv[index + 1], "-p") == 0)
  398. {
  399. port = atoi(argv[index + 2]);
  400. }
  401. else goto __usage;
  402. }
  403. }
  404. else if (strcmp(argv[index], "-c") == 0)
  405. {
  406. mode = IPERF_MODE_CLIENT; /* client mode */
  407. if (argc < 3) goto __usage;
  408. host = argv[index + 1];
  409. if (argc >= 5)
  410. {
  411. /* iperf -c host -p port */
  412. if (strcmp(argv[index + 2], "-p") == 0)
  413. {
  414. port = atoi(argv[index + 3]);
  415. }
  416. else goto __usage;
  417. }
  418. }
  419. else goto __usage;
  420. if (argc >= 7)
  421. {
  422. if(strcmp(argv[argc - 2], "-m") == 0)
  423. {
  424. numtid = atoi(argv[argc - 1]);
  425. }
  426. else goto __usage;
  427. }
  428. /* start iperf */
  429. if (param.mode == IPERF_MODE_STOP)
  430. {
  431. int i = 0;
  432. char tid_name[RT_NAME_MAX + 1] = {0};
  433. param.mode = mode;
  434. param.port = port;
  435. if (param.host)
  436. {
  437. rt_free(param.host);
  438. param.host = NULL;
  439. }
  440. if (host) param.host = rt_strdup(host);
  441. for (i = 0; i < numtid; i++)
  442. {
  443. rt_thread_t tid = RT_NULL;
  444. void (*function)(void *parameter);
  445. if (use_udp)
  446. {
  447. if (mode == IPERF_MODE_CLIENT)
  448. {
  449. rt_snprintf(tid_name, sizeof(tid_name), "iperfc%02d", i + 1);
  450. function = iperf_udp_client;
  451. }
  452. else if (mode == IPERF_MODE_SERVER)
  453. {
  454. rt_snprintf(tid_name, sizeof(tid_name), "iperfd%02d", i + 1);
  455. function = iperf_udp_server;
  456. }
  457. }
  458. else
  459. {
  460. if (mode == IPERF_MODE_CLIENT)
  461. {
  462. rt_snprintf(tid_name, sizeof(tid_name), "iperfc%02d", i + 1);
  463. function = iperf_client;
  464. }
  465. else if (mode == IPERF_MODE_SERVER)
  466. {
  467. rt_snprintf(tid_name, sizeof(tid_name), "iperfd%02d", i + 1);
  468. function = iperf_server;
  469. }
  470. }
  471. tid = rt_thread_create(tid_name, function, RT_NULL, IPERF_THREAD_STACK_SIZE, 20, 100);
  472. if (tid) rt_thread_startup(tid);
  473. }
  474. }
  475. else
  476. {
  477. rt_kprintf("Please stop iperf firstly, by:\n");
  478. rt_kprintf("iperf --stop\n");
  479. }
  480. return 0;
  481. __usage:
  482. iperf_usage();
  483. return 0;
  484. }
  485. #ifdef FINSH_USING_MSH
  486. #include <finsh.h>
  487. MSH_CMD_EXPORT(iperf, the network bandwidth measurement tool);
  488. #endif