netio.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /**
  2. * @file
  3. * MetIO Server
  4. *
  5. */
  6. /*
  7. * Redistribution and use in source and binary forms, with or without modification,
  8. * are permitted provided that the following conditions are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright notice,
  11. * this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright notice,
  13. * this list of conditions and the following disclaimer in the documentation
  14. * and/or other materials provided with the distribution.
  15. * 3. The name of the author may not be used to endorse or promote products
  16. * derived from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
  19. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  20. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
  21. * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  22. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
  23. * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  24. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  25. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  26. * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
  27. * OF SUCH DAMAGE.
  28. *
  29. * This file is part of the lwIP TCP/IP stack.
  30. *
  31. */
  32. #include "lwip/opt.h"
  33. #if LWIP_TCP
  34. #include "lwip/tcp.h"
  35. /*
  36. * This implements a netio server.
  37. * The client sends a command word (4 bytes) then a data length word (4 bytes).
  38. * If the command is "receive", the server is to consume "data length" bytes into
  39. * a circular buffer until the first byte is non-zero, then it is to consume
  40. * another command/data pair.
  41. * If the command is "send", the server is to send "data length" bytes from a circular
  42. * buffer with the first byte being zero, until "some time" (6 seconds in the
  43. * current netio126.zip download) has passed and then send one final buffer with
  44. * the first byte being non-zero. Then it is to consume another command/data pair.
  45. */
  46. /* See http://www.nwlab.net/art/netio/netio.html to get the netio tool */
  47. /* implementation options */
  48. #define NETIO_BUF_SIZE (4 * 1024)
  49. #define NETIO_USE_STATIC_BUF 0
  50. /* NetIO server state definition */
  51. #define NETIO_STATE_WAIT_FOR_CMD 0
  52. #define NETIO_STATE_RECV_DATA 1
  53. #define NETIO_STATE_SEND_DATA 2
  54. #define NETIO_STATE_SEND_DATA_LAST 3
  55. #define NETIO_STATE_DONE 4
  56. struct netio_state {
  57. u32_t state;
  58. u32_t cmd;
  59. u32_t data_len;
  60. u32_t cntr;
  61. u8_t * buf_ptr;
  62. u32_t buf_pos;
  63. u32_t first_byte;
  64. u32_t time_stamp;
  65. };
  66. /* NetIO command protocol definition */
  67. #define NETIO_CMD_QUIT 0
  68. #define NETIO_CMD_C2S 1
  69. #define NETIO_CMD_S2C 2
  70. #define NETIO_CMD_RES 3
  71. static err_t netio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
  72. static void
  73. netio_close(void *arg, struct tcp_pcb *pcb)
  74. {
  75. err_t err;
  76. struct netio_state *ns = arg;
  77. ns->state = NETIO_STATE_DONE;
  78. tcp_recv(pcb, NULL);
  79. err = tcp_close(pcb);
  80. if (err != ERR_OK) {
  81. /* closing failed, try again later */
  82. tcp_recv(pcb, netio_recv);
  83. } else {
  84. /* closing succeeded */
  85. #if NETIO_USE_STATIC_BUF != 1
  86. if(ns->buf_ptr != NULL){
  87. mem_free(ns->buf_ptr);
  88. }
  89. #endif
  90. tcp_arg(pcb, NULL);
  91. tcp_poll(pcb, NULL, 0);
  92. tcp_sent(pcb, NULL);
  93. if (arg != NULL) {
  94. mem_free(arg);
  95. }
  96. }
  97. }
  98. static err_t
  99. netio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
  100. {
  101. struct netio_state *ns = arg;
  102. u8_t * data_ptr;
  103. u32_t data_cntr;
  104. struct pbuf *q = p;
  105. u16_t len;
  106. if (p != NULL) {
  107. tcp_recved(pcb, p->tot_len);
  108. }
  109. if (err == ERR_OK && q != NULL) {
  110. while (q != NULL) {
  111. data_cntr = q->len;
  112. data_ptr = q->payload;
  113. while (data_cntr--) {
  114. if (ns->state == NETIO_STATE_DONE){
  115. netio_close(ns, pcb);
  116. break;
  117. } else if (ns->state == NETIO_STATE_WAIT_FOR_CMD) {
  118. if (ns->cntr < 4) {
  119. /* build up the CMD field */
  120. ns->cmd <<= 8;
  121. ns->cmd |= *data_ptr++;
  122. ns->cntr++;
  123. } else if (ns->cntr < 8) {
  124. /* build up the DATA field */
  125. ns->data_len <<= 8;
  126. ns->data_len |= *data_ptr++;
  127. ns->cntr++;
  128. if (ns->cntr == 8) {
  129. /* now we have full command and data words */
  130. ns->cntr = 0;
  131. ns->buf_pos = 0;
  132. ns->buf_ptr[0] = 0;
  133. if (ns->cmd == NETIO_CMD_C2S) {
  134. ns->state = NETIO_STATE_RECV_DATA;
  135. } else if (ns->cmd == NETIO_CMD_S2C) {
  136. ns->state = NETIO_STATE_SEND_DATA;
  137. /* start timer */
  138. ns->time_stamp = rt_tick_get();
  139. /* send first round of data */
  140. len = tcp_sndbuf(pcb);
  141. len = LWIP_MIN(len, ns->data_len - ns->cntr);
  142. len = LWIP_MIN(len, NETIO_BUF_SIZE - ns->buf_pos);
  143. do {
  144. err = tcp_write(pcb, ns->buf_ptr + ns->buf_pos, len, TCP_WRITE_FLAG_COPY);
  145. if (err == ERR_MEM) {
  146. len /= 2;
  147. }
  148. } while ((err == ERR_MEM) && (len > 1));
  149. ns->buf_pos += len;
  150. ns->cntr += len;
  151. } else {
  152. /* unrecognized command, punt */
  153. ns->cntr = 0;
  154. ns->buf_pos = 0;
  155. ns->buf_ptr[0] = 0;
  156. netio_close(ns, pcb);
  157. break;
  158. }
  159. }
  160. } else {
  161. /* in trouble... shouldn't be in this state! */
  162. }
  163. } else if (ns->state == NETIO_STATE_RECV_DATA) {
  164. int chunk_length;
  165. if(ns->cntr == 0){
  166. /* save the first byte of this new round of data
  167. * this will not match ns->buf_ptr[0] in the case that
  168. * NETIO_BUF_SIZE is less than ns->data_len.
  169. */
  170. ns->first_byte = *data_ptr;
  171. }
  172. if (ns->cntr + (data_cntr + 1) < ns->data_len) chunk_length = data_cntr + 1;
  173. else chunk_length = (ns->data_len - ns->cntr);
  174. ns->buf_pos += chunk_length;
  175. data_ptr += chunk_length;
  176. ns->cntr += chunk_length;
  177. data_cntr -= (chunk_length - 1);
  178. if (ns->buf_pos >= NETIO_BUF_SIZE) {
  179. /* circularize the buffer */
  180. ns->buf_pos %= NETIO_BUF_SIZE;
  181. }
  182. if(ns->cntr == ns->data_len){
  183. ns->cntr = 0;
  184. if (ns->first_byte != 0) {
  185. /* if this last round did not start with 0,
  186. * go look for another command */
  187. ns->state = NETIO_STATE_WAIT_FOR_CMD;
  188. ns->data_len = 0;
  189. ns->cmd = 0;
  190. /* TODO LWIP_DEBUGF( print out some throughput calculation results... ); */
  191. } else {
  192. /* stay here and wait on more data */
  193. }
  194. }
  195. } else if (ns->state == NETIO_STATE_SEND_DATA
  196. || ns->state == NETIO_STATE_SEND_DATA_LAST) {
  197. /* I don't think this should happen... */
  198. } else {
  199. /* done / quit */
  200. netio_close(ns, pcb);
  201. break;
  202. } /* end of ns->state condition */
  203. } /* end of while data still in this pbuf */
  204. q = q->next;
  205. }
  206. pbuf_free(p);
  207. } else {
  208. /* error or closed by other side */
  209. if (p != NULL) {
  210. pbuf_free(p);
  211. }
  212. /* close the connection */
  213. netio_close(ns, pcb);
  214. }
  215. return ERR_OK;
  216. }
  217. static err_t
  218. netio_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
  219. {
  220. struct netio_state *ns = arg;
  221. err_t err = ERR_OK;
  222. if (ns->cntr >= ns->data_len && ns->state == NETIO_STATE_SEND_DATA) {
  223. /* done with this round of sending */
  224. ns->buf_pos = 0;
  225. ns->cntr = 0;
  226. /* check if timer expired */
  227. if (rt_tick_get() - ns->time_stamp > 600) {
  228. ns->buf_ptr[0] = 1;
  229. ns->state = NETIO_STATE_SEND_DATA_LAST;
  230. } else {
  231. ns->buf_ptr[0] = 0;
  232. }
  233. }
  234. if(ns->state == NETIO_STATE_SEND_DATA_LAST || ns->state == NETIO_STATE_SEND_DATA){
  235. len = tcp_sndbuf(pcb);
  236. len = LWIP_MIN(len, ns->data_len - ns->cntr);
  237. len = LWIP_MIN(len, NETIO_BUF_SIZE - ns->buf_pos);
  238. if(ns->cntr < ns->data_len){
  239. do {
  240. err = tcp_write(pcb, ns->buf_ptr + ns->buf_pos, len, TCP_WRITE_FLAG_COPY);
  241. if (err == ERR_MEM) {
  242. len /= 2;
  243. }
  244. } while ((err == ERR_MEM) && (len > 1));
  245. ns->buf_pos += len;
  246. if(ns->buf_pos >= NETIO_BUF_SIZE){
  247. ns->buf_pos = 0;
  248. }
  249. ns->cntr += len;
  250. }
  251. }
  252. if(ns->cntr >= ns->data_len && ns->state == NETIO_STATE_SEND_DATA_LAST){
  253. /* we have buffered up all our data to send this last round, go look for a command */
  254. ns->state = NETIO_STATE_WAIT_FOR_CMD;
  255. ns->cntr = 0;
  256. /* TODO LWIP_DEBUGF( print out some throughput calculation results... ); */
  257. }
  258. return ERR_OK;
  259. }
  260. static err_t
  261. netio_poll(void *arg, struct tcp_pcb *pcb)
  262. {
  263. struct netio_state * ns = arg;
  264. if(ns->state == NETIO_STATE_SEND_DATA){
  265. } else if(ns->state == NETIO_STATE_DONE){
  266. netio_close(ns, pcb);
  267. }
  268. return ERR_OK;
  269. }
  270. #if NETIO_USE_STATIC_BUF == 1
  271. static u8_t netio_buf[NETIO_BUF_SIZE];
  272. #endif
  273. static err_t
  274. netio_accept(void *arg, struct tcp_pcb *pcb, err_t err)
  275. {
  276. struct netio_state * ns;
  277. LWIP_UNUSED_ARG(err);
  278. ns = mem_malloc(sizeof(struct netio_state));
  279. if(ns == NULL){
  280. return ERR_MEM;
  281. }
  282. ns->state = NETIO_STATE_WAIT_FOR_CMD;
  283. ns->data_len = 0;
  284. ns->cmd = 0;
  285. ns->cntr = 0;
  286. ns->buf_pos = 0;
  287. #if NETIO_USE_STATIC_BUF == 1
  288. ns->buf_ptr = netio_buf;
  289. #else
  290. ns->buf_ptr = mem_malloc(NETIO_BUF_SIZE);
  291. if(ns->buf_ptr == NULL){
  292. mem_free(ns);
  293. return ERR_MEM;
  294. }
  295. #endif
  296. ns->buf_ptr[0] = 0;
  297. tcp_arg(pcb, ns);
  298. tcp_sent(pcb, netio_sent);
  299. tcp_recv(pcb, netio_recv);
  300. tcp_poll(pcb, netio_poll, 4); /* every 2 seconds */
  301. return ERR_OK;
  302. }
  303. void netio_init(void)
  304. {
  305. struct tcp_pcb *pcb;
  306. pcb = tcp_new();
  307. tcp_bind(pcb, IP_ADDR_ANY, 18767);
  308. pcb = tcp_listen(pcb);
  309. tcp_accept(pcb, netio_accept);
  310. }
  311. #endif /* LWIP_TCP */
  312. #ifdef RT_USING_FINSH
  313. #include <finsh.h>
  314. FINSH_FUNCTION_EXPORT(netio_init, netio server);
  315. #endif