PageRenderTime 44ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/core/net/ip/tcp-socket.c

https://gitlab.com/F34140r/contiki
C | 367 lines | 275 code | 31 blank | 61 comment | 64 complexity | a1bb181f11d2f1c1f3b7d89c009debd0 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. /*
  2. * Copyright (c) 2012-2014, Thingsquare, http://www.thingsquare.com/.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the copyright holder nor the names of its
  14. * contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  24. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  25. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  26. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  27. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  28. * OF THE POSSIBILITY OF SUCH DAMAGE.
  29. *
  30. */
  31. #include "contiki.h"
  32. #include "contiki-net.h"
  33. #include "lib/list.h"
  34. #include "tcp-socket.h"
  35. #include <stdio.h>
  36. #include <string.h>
  37. #define MIN(a, b) ((a) < (b) ? (a) : (b))
  38. LIST(socketlist);
  39. /*---------------------------------------------------------------------------*/
  40. PROCESS(tcp_socket_process, "TCP socket process");
  41. /*---------------------------------------------------------------------------*/
  42. static void
  43. call_event(struct tcp_socket *s, tcp_socket_event_t event)
  44. {
  45. if(s != NULL && s->event_callback != NULL) {
  46. s->event_callback(s, s->ptr, event);
  47. }
  48. }
  49. /*---------------------------------------------------------------------------*/
  50. static void
  51. senddata(struct tcp_socket *s)
  52. {
  53. int len = MIN(s->output_data_max_seg, uip_mss());
  54. if(s->output_data_len > 0) {
  55. len = MIN(s->output_data_len, len);
  56. s->output_data_send_nxt = len;
  57. uip_send(s->output_data_ptr, len);
  58. }
  59. }
  60. /*---------------------------------------------------------------------------*/
  61. static void
  62. acked(struct tcp_socket *s)
  63. {
  64. if(s->output_data_len > 0) {
  65. /* Copy the data in the outputbuf down and update outputbufptr and
  66. outputbuf_lastsent */
  67. if(s->output_data_send_nxt > 0) {
  68. memcpy(&s->output_data_ptr[0],
  69. &s->output_data_ptr[s->output_data_send_nxt],
  70. s->output_data_maxlen - s->output_data_send_nxt);
  71. }
  72. if(s->output_data_len < s->output_data_send_nxt) {
  73. printf("tcp: acked assertion failed s->output_data_len (%d) < s->output_data_send_nxt (%d)\n",
  74. s->output_data_len,
  75. s->output_data_send_nxt);
  76. }
  77. s->output_data_len -= s->output_data_send_nxt;
  78. s->output_data_send_nxt = 0;
  79. call_event(s, TCP_SOCKET_DATA_SENT);
  80. }
  81. }
  82. /*---------------------------------------------------------------------------*/
  83. static void
  84. newdata(struct tcp_socket *s)
  85. {
  86. uint16_t len, copylen, bytesleft;
  87. uint8_t *dataptr;
  88. len = uip_datalen();
  89. dataptr = uip_appdata;
  90. /* We have a segment with data coming in. We copy as much data as
  91. possible into the input buffer and call the input callback
  92. function. The input callback returns the number of bytes that
  93. should be retained in the buffer, or zero if all data should be
  94. consumed. If there is data to be retained, the highest bytes of
  95. data are copied down into the input buffer. */
  96. do {
  97. copylen = MIN(len, s->input_data_maxlen);
  98. memcpy(s->input_data_ptr, dataptr, copylen);
  99. if(s->input_callback) {
  100. bytesleft = s->input_callback(s, s->ptr,
  101. s->input_data_ptr, copylen);
  102. } else {
  103. bytesleft = 0;
  104. }
  105. if(bytesleft > 0) {
  106. printf("tcp: newdata, bytesleft > 0 (%d) not implemented\n", bytesleft);
  107. }
  108. dataptr += copylen;
  109. len -= copylen;
  110. } while(len > 0);
  111. }
  112. /*---------------------------------------------------------------------------*/
  113. static void
  114. relisten(struct tcp_socket *s)
  115. {
  116. if(s != NULL && s->listen_port != 0) {
  117. s->flags |= TCP_SOCKET_FLAGS_LISTENING;
  118. }
  119. }
  120. /*---------------------------------------------------------------------------*/
  121. static void
  122. appcall(void *state)
  123. {
  124. struct tcp_socket *s = state;
  125. if(uip_connected()) {
  126. /* Check if this connection originated in a local listen
  127. socket. We do this by checking the state pointer - if NULL,
  128. this is an incoming listen connection. If so, we need to
  129. connect the socket to the uip_conn and call the event
  130. function. */
  131. if(s == NULL) {
  132. for(s = list_head(socketlist);
  133. s != NULL;
  134. s = list_item_next(s)) {
  135. if((s->flags & TCP_SOCKET_FLAGS_LISTENING) != 0 &&
  136. s->listen_port != 0 &&
  137. s->listen_port == uip_htons(uip_conn->lport)) {
  138. s->flags &= ~TCP_SOCKET_FLAGS_LISTENING;
  139. s->output_data_max_seg = uip_mss();
  140. tcp_markconn(uip_conn, s);
  141. call_event(s, TCP_SOCKET_CONNECTED);
  142. break;
  143. }
  144. }
  145. } else {
  146. s->output_data_max_seg = uip_mss();
  147. call_event(s, TCP_SOCKET_CONNECTED);
  148. }
  149. if(s == NULL) {
  150. uip_abort();
  151. } else {
  152. if(uip_newdata()) {
  153. newdata(s);
  154. }
  155. senddata(s);
  156. }
  157. return;
  158. }
  159. if(uip_timedout()) {
  160. call_event(s, TCP_SOCKET_TIMEDOUT);
  161. relisten(s);
  162. }
  163. if(uip_aborted()) {
  164. call_event(s, TCP_SOCKET_ABORTED);
  165. relisten(s);
  166. }
  167. if(s == NULL) {
  168. uip_abort();
  169. return;
  170. }
  171. if(uip_acked()) {
  172. acked(s);
  173. }
  174. if(uip_newdata()) {
  175. newdata(s);
  176. }
  177. if(uip_rexmit() ||
  178. uip_newdata() ||
  179. uip_acked()) {
  180. senddata(s);
  181. } else if(uip_poll()) {
  182. senddata(s);
  183. }
  184. if(s->output_data_len == 0 && s->flags & TCP_SOCKET_FLAGS_CLOSING) {
  185. s->flags &= ~TCP_SOCKET_FLAGS_CLOSING;
  186. uip_close();
  187. tcp_markconn(uip_conn, NULL);
  188. call_event(s, TCP_SOCKET_CLOSED);
  189. relisten(s);
  190. }
  191. if(uip_closed()) {
  192. tcp_markconn(uip_conn, NULL);
  193. call_event(s, TCP_SOCKET_CLOSED);
  194. relisten(s);
  195. }
  196. }
  197. /*---------------------------------------------------------------------------*/
  198. PROCESS_THREAD(tcp_socket_process, ev, data)
  199. {
  200. PROCESS_BEGIN();
  201. while(1) {
  202. PROCESS_WAIT_EVENT();
  203. if(ev == tcpip_event) {
  204. appcall(data);
  205. }
  206. }
  207. PROCESS_END();
  208. }
  209. /*---------------------------------------------------------------------------*/
  210. static void
  211. init(void)
  212. {
  213. static uint8_t inited = 0;
  214. if(!inited) {
  215. list_init(socketlist);
  216. process_start(&tcp_socket_process, NULL);
  217. inited = 1;
  218. }
  219. }
  220. /*---------------------------------------------------------------------------*/
  221. int
  222. tcp_socket_register(struct tcp_socket *s, void *ptr,
  223. uint8_t *input_databuf, int input_databuf_len,
  224. uint8_t *output_databuf, int output_databuf_len,
  225. tcp_socket_data_callback_t input_callback,
  226. tcp_socket_event_callback_t event_callback)
  227. {
  228. init();
  229. if(s == NULL) {
  230. return -1;
  231. }
  232. s->ptr = ptr;
  233. s->input_data_ptr = input_databuf;
  234. s->input_data_maxlen = input_databuf_len;
  235. s->output_data_ptr = output_databuf;
  236. s->output_data_maxlen = output_databuf_len;
  237. s->input_callback = input_callback;
  238. s->event_callback = event_callback;
  239. list_add(socketlist, s);
  240. s->listen_port = 0;
  241. s->flags = TCP_SOCKET_FLAGS_NONE;
  242. return 1;
  243. }
  244. /*---------------------------------------------------------------------------*/
  245. int
  246. tcp_socket_connect(struct tcp_socket *s,
  247. uip_ipaddr_t *ipaddr,
  248. uint16_t port)
  249. {
  250. if(s == NULL) {
  251. return -1;
  252. }
  253. PROCESS_CONTEXT_BEGIN(&tcp_socket_process);
  254. s->c = tcp_connect(ipaddr, uip_htons(port), s);
  255. PROCESS_CONTEXT_END();
  256. if(s->c == NULL) {
  257. return -1;
  258. } else {
  259. return 1;
  260. }
  261. }
  262. /*---------------------------------------------------------------------------*/
  263. int
  264. tcp_socket_listen(struct tcp_socket *s,
  265. uint16_t port)
  266. {
  267. if(s == NULL) {
  268. return -1;
  269. }
  270. s->listen_port = port;
  271. PROCESS_CONTEXT_BEGIN(&tcp_socket_process);
  272. tcp_listen(uip_htons(port));
  273. PROCESS_CONTEXT_END();
  274. s->flags |= TCP_SOCKET_FLAGS_LISTENING;
  275. return 1;
  276. }
  277. /*---------------------------------------------------------------------------*/
  278. int
  279. tcp_socket_unlisten(struct tcp_socket *s)
  280. {
  281. if(s == NULL) {
  282. return -1;
  283. }
  284. PROCESS_CONTEXT_BEGIN(&tcp_socket_process);
  285. tcp_unlisten(uip_htons(s->listen_port));
  286. PROCESS_CONTEXT_END();
  287. s->listen_port = 0;
  288. s->flags &= ~TCP_SOCKET_FLAGS_LISTENING;
  289. return 1;
  290. }
  291. /*---------------------------------------------------------------------------*/
  292. int
  293. tcp_socket_send(struct tcp_socket *s,
  294. const uint8_t *data, int datalen)
  295. {
  296. int len;
  297. if(s == NULL) {
  298. return -1;
  299. }
  300. len = MIN(datalen, s->output_data_maxlen - s->output_data_len);
  301. memcpy(&s->output_data_ptr[s->output_data_len], data, len);
  302. s->output_data_len += len;
  303. return len;
  304. }
  305. /*---------------------------------------------------------------------------*/
  306. int
  307. tcp_socket_send_str(struct tcp_socket *s,
  308. const char *str)
  309. {
  310. return tcp_socket_send(s, (const uint8_t *)str, strlen(str));
  311. }
  312. /*---------------------------------------------------------------------------*/
  313. int
  314. tcp_socket_close(struct tcp_socket *s)
  315. {
  316. if(s == NULL) {
  317. return -1;
  318. }
  319. s->flags |= TCP_SOCKET_FLAGS_CLOSING;
  320. return 1;
  321. }
  322. /*---------------------------------------------------------------------------*/
  323. int
  324. tcp_socket_unregister(struct tcp_socket *s)
  325. {
  326. if(s == NULL) {
  327. return -1;
  328. }
  329. tcp_socket_unlisten(s);
  330. if(s->c != NULL) {
  331. tcp_attach(s->c, NULL);
  332. }
  333. list_remove(socketlist, s);
  334. return 1;
  335. }
  336. /*---------------------------------------------------------------------------*/