tcp_backlog.c 12 KB

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