tcp_backlog.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. /****************************************************************************
  2. * net/tcp/tcp_backlog.c
  3. *
  4. * Copyright (C) 2008-2009, 2011-2013, 2020 Gregory Nutt. All rights
  5. * reserved.
  6. * Author: Gregory Nutt <gnutt@nuttx.org>
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. * 3. Neither the name NuttX nor the names of its contributors may be
  19. * used to endorse or promote products derived from this software
  20. * without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  23. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  25. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  26. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  27. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  28. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  29. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  30. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  32. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  33. * POSSIBILITY OF SUCH DAMAGE.
  34. *
  35. ****************************************************************************/
  36. /****************************************************************************
  37. * Included Files
  38. ****************************************************************************/
  39. #include <nuttx/net/netconfig.h>
  40. #if defined(CONFIG_NET) && defined(CONFIG_NET_TCP) && defined(CONFIG_NET_TCPBACKLOG)
  41. #include <stdint.h>
  42. #include <stdbool.h>
  43. #include <stdlib.h>
  44. #include <queue.h>
  45. #include <debug.h>
  46. #include <nuttx/kmalloc.h>
  47. #include <nuttx/net/net.h>
  48. #include "devif/devif.h"
  49. #include "tcp/tcp.h"
  50. /****************************************************************************
  51. * Public Functions
  52. ****************************************************************************/
  53. /****************************************************************************
  54. * Name: tcp_backlogcreate
  55. *
  56. * Description:
  57. * Called from the listen() logic to setup the backlog as specified in the
  58. * the listen arguments.
  59. *
  60. * Assumptions:
  61. * Called from normal task logic. The network may or may not be locked.
  62. *
  63. ****************************************************************************/
  64. int tcp_backlogcreate(FAR struct tcp_conn_s *conn, int nblg)
  65. {
  66. FAR struct tcp_backlog_s *bls = NULL;
  67. FAR struct tcp_blcontainer_s *blc;
  68. int size;
  69. int offset;
  70. int i;
  71. ninfo("conn=%p nblg=%d\n", conn, nblg);
  72. #ifdef CONFIG_DEBUG_FEATURES
  73. if (!conn)
  74. {
  75. return -EINVAL;
  76. }
  77. #endif
  78. /* Then allocate the backlog as requested */
  79. if (nblg > 0)
  80. {
  81. /* nblog value must less than SOMAXCONN */
  82. if (nblg > SOMAXCONN)
  83. {
  84. nblg = SOMAXCONN;
  85. }
  86. /* Align the list of backlog structures to 32-bit boundaries. This
  87. * may be excessive on 24-16-bit address machines; and insufficient
  88. * on 64-bit address machines -- REVISIT
  89. */
  90. offset = (sizeof(struct tcp_backlog_s) + 3) & ~3;
  91. /* Then determine the full size of the allocation include the
  92. * tcp_backlog_s, a pre-allocated array of struct tcp_blcontainer_s
  93. * and alignment padding
  94. */
  95. size = offset + nblg * sizeof(struct tcp_blcontainer_s);
  96. /* Then allocate that much */
  97. bls = (FAR struct tcp_backlog_s *)kmm_zalloc(size);
  98. if (!bls)
  99. {
  100. nerr("ERROR: Failed to allocate backlog\n");
  101. return -ENOMEM;
  102. }
  103. /* Then add all of the pre-allocated containers to the free list */
  104. blc = (FAR struct tcp_blcontainer_s *)(((FAR uint8_t *)bls) + offset);
  105. for (i = 0; i < nblg; i++)
  106. {
  107. sq_addfirst(&blc->bc_node, &bls->bl_free);
  108. blc++;
  109. }
  110. }
  111. /* Destroy any existing backlog (shouldn't be any) */
  112. net_lock();
  113. tcp_backlogdestroy(conn);
  114. /* Now install the backlog tear-off in the connection. NOTE that bls may
  115. * actually be NULL if nblg is <= 0; In that case, we are disabling backlog
  116. * support. Since the network is locked, destroying the old backlog and
  117. * replace it with the new is an atomic operation
  118. */
  119. conn->backlog = bls;
  120. net_unlock();
  121. return OK;
  122. }
  123. /****************************************************************************
  124. * Name: tcp_backlogdestroy
  125. *
  126. * Description:
  127. * (1) Called from tcp_free() whenever a connection is freed.
  128. * (2) Called from tcp_backlogcreate() to destroy any old backlog
  129. *
  130. * NOTE: This function may re-enter tcp_free when a connection that
  131. * is freed that has pending connections.
  132. *
  133. * Assumptions:
  134. * Called from network socket logic with the network locked
  135. *
  136. ****************************************************************************/
  137. int tcp_backlogdestroy(FAR struct tcp_conn_s *conn)
  138. {
  139. FAR struct tcp_backlog_s *blg;
  140. FAR struct tcp_blcontainer_s *blc;
  141. FAR struct tcp_conn_s *blconn;
  142. ninfo("conn=%p\n", conn);
  143. #ifdef CONFIG_DEBUG_FEATURES
  144. if (!conn)
  145. {
  146. return -EINVAL;
  147. }
  148. #endif
  149. /* Make sure that the connection has a backlog to be destroyed */
  150. if (conn->backlog)
  151. {
  152. /* Remove the backlog structure reference from the connection */
  153. blg = conn->backlog;
  154. conn->backlog = NULL;
  155. /* Handle any pending connections in the backlog */
  156. while ((blc = (FAR struct tcp_blcontainer_s *)
  157. sq_remfirst(&blg->bl_pending)) != NULL)
  158. {
  159. blconn = blc->bc_conn;
  160. if (blconn)
  161. {
  162. /* REVISIT -- such connections really need to be gracefully closed */
  163. blconn->blparent = NULL;
  164. blconn->backlog = NULL;
  165. blconn->crefs = 0;
  166. tcp_free(blconn);
  167. }
  168. }
  169. /* Then free the entire backlog structure */
  170. kmm_free(blg);
  171. }
  172. return OK;
  173. }
  174. /****************************************************************************
  175. * Name: tcp_backlogadd
  176. *
  177. * Description:
  178. * Called tcp_listen when a new connection is made with a listener socket
  179. * but when there is no accept() in place to receive the connection. This
  180. * function adds the new connection to the backlog.
  181. *
  182. * Assumptions:
  183. * Called from network socket logic with the network locked
  184. *
  185. ****************************************************************************/
  186. int tcp_backlogadd(FAR struct tcp_conn_s *conn, FAR struct tcp_conn_s *blconn)
  187. {
  188. FAR struct tcp_backlog_s *bls;
  189. FAR struct tcp_blcontainer_s *blc;
  190. int ret = -EINVAL;
  191. ninfo("conn=%p blconn=%p\n", conn, blconn);
  192. #ifdef CONFIG_DEBUG_FEATURES
  193. if (!conn)
  194. {
  195. return -EINVAL;
  196. }
  197. #endif
  198. bls = conn->backlog;
  199. if (bls && blconn)
  200. {
  201. /* Get a container for the connection from the free list */
  202. blc = (FAR struct tcp_blcontainer_s *)sq_remfirst(&bls->bl_free);
  203. if (!blc)
  204. {
  205. nerr("ERROR: There are no free containers for TCP BACKLOG!\n");
  206. ret = -ENOMEM;
  207. }
  208. else
  209. {
  210. /* Save the connection reference in the container and put the
  211. * container at the end of the pending connection list (FIFO).
  212. */
  213. blc->bc_conn = blconn;
  214. sq_addlast(&blc->bc_node, &bls->bl_pending);
  215. ret = OK;
  216. }
  217. }
  218. return ret;
  219. }
  220. /****************************************************************************
  221. * Name: tcp_backlogremove
  222. *
  223. * Description:
  224. * Called from poll(). Before waiting for a new connection, poll will
  225. * call this API to see if there are pending connections in the backlog.
  226. *
  227. * Assumptions:
  228. * Called from network socket logic with the network locked
  229. *
  230. ****************************************************************************/
  231. bool tcp_backlogavailable(FAR struct tcp_conn_s *conn)
  232. {
  233. return (conn && conn->backlog && !sq_empty(&conn->backlog->bl_pending));
  234. }
  235. /****************************************************************************
  236. * Name: tcp_backlogremove
  237. *
  238. * Description:
  239. * Called from accept(). Before waiting for a new connection, accept will
  240. * call this API to see if there are pending connections in the backlog.
  241. *
  242. * Assumptions:
  243. * Called from network socket logic with the network locked
  244. *
  245. ****************************************************************************/
  246. FAR struct tcp_conn_s *tcp_backlogremove(FAR struct tcp_conn_s *conn)
  247. {
  248. FAR struct tcp_backlog_s *bls;
  249. FAR struct tcp_blcontainer_s *blc;
  250. FAR struct tcp_conn_s *blconn = NULL;
  251. #ifdef CONFIG_DEBUG_FEATURES
  252. if (!conn)
  253. {
  254. return NULL;
  255. }
  256. #endif
  257. bls = conn->backlog;
  258. if (bls)
  259. {
  260. /* Remove the a container at the head of the pending connection list
  261. * (FIFO)
  262. */
  263. blc = (FAR struct tcp_blcontainer_s *)sq_remfirst(&bls->bl_pending);
  264. if (blc)
  265. {
  266. /* Extract the connection reference from the container and put
  267. * container in the free list
  268. */
  269. blconn = blc->bc_conn;
  270. blc->bc_conn = NULL;
  271. sq_addlast(&blc->bc_node, &bls->bl_free);
  272. }
  273. }
  274. ninfo("conn=%p, returning %p\n", conn, blconn);
  275. return blconn;
  276. }
  277. /****************************************************************************
  278. * Name: tcp_backlogdelete
  279. *
  280. * Description:
  281. * Called from tcp_free() when a connection is freed that this also
  282. * retained in the pending connection list of a listener. We simply need
  283. * to remove the defunct connection from the list.
  284. *
  285. * Assumptions:
  286. * Called from network socket logic with the network locked
  287. *
  288. ****************************************************************************/
  289. int tcp_backlogdelete(FAR struct tcp_conn_s *conn,
  290. FAR struct tcp_conn_s *blconn)
  291. {
  292. FAR struct tcp_backlog_s *bls;
  293. FAR struct tcp_blcontainer_s *blc;
  294. FAR struct tcp_blcontainer_s *prev;
  295. ninfo("conn=%p blconn=%p\n", conn, blconn);
  296. #ifdef CONFIG_DEBUG_FEATURES
  297. if (!conn)
  298. {
  299. return -EINVAL;
  300. }
  301. #endif
  302. bls = conn->backlog;
  303. if (bls)
  304. {
  305. /* Find the container hold the connection */
  306. for (blc = (FAR struct tcp_blcontainer_s *)sq_peek(&bls->bl_pending),
  307. prev = NULL;
  308. blc;
  309. prev = blc, blc = (FAR struct tcp_blcontainer_s *)sq_next(&blc->bc_node))
  310. {
  311. if (blc->bc_conn == blconn)
  312. {
  313. if (prev)
  314. {
  315. /* Remove the a container from the middle of the list of
  316. * pending connections
  317. */
  318. sq_remafter(&prev->bc_node, &bls->bl_pending);
  319. }
  320. else
  321. {
  322. /* Remove the a container from the head of the list of
  323. * pending connections
  324. */
  325. sq_remfirst(&bls->bl_pending);
  326. }
  327. /* Put container in the free list */
  328. blc->bc_conn = NULL;
  329. sq_addlast(&blc->bc_node, &bls->bl_free);
  330. return OK;
  331. }
  332. }
  333. nerr("ERROR: Failed to find pending connection\n");
  334. return -EINVAL;
  335. }
  336. return OK;
  337. }
  338. #endif /* CONFIG_NET && CONFIG_NET_TCP && CONFIG_NET_TCPBACKLOG */