tcp_netpoll.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. /****************************************************************************
  2. * net/tcp/tcp_netpoll.c
  3. *
  4. * Copyright (C) 2008-2009, 2011-2016, 2018 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/config.h>
  40. #include <stdint.h>
  41. #include <poll.h>
  42. #include <debug.h>
  43. #include <nuttx/kmalloc.h>
  44. #include <nuttx/wqueue.h>
  45. #include <nuttx/mm/iob.h>
  46. #include <nuttx/net/net.h>
  47. #include "devif/devif.h"
  48. #include "netdev/netdev.h"
  49. #include "socket/socket.h"
  50. #include "inet/inet.h"
  51. #include "tcp/tcp.h"
  52. #ifdef HAVE_TCP_POLL
  53. /****************************************************************************
  54. * Private Types
  55. ****************************************************************************/
  56. /* This is an allocated container that holds the poll-related information */
  57. struct tcp_poll_s
  58. {
  59. FAR struct socket *psock; /* Needed to handle loss of connection */
  60. struct pollfd *fds; /* Needed to handle poll events */
  61. FAR struct devif_callback_s *cb; /* Needed to teardown the poll */
  62. #if defined(CONFIG_NET_TCP_WRITE_BUFFERS) && defined(CONFIG_IOB_NOTIFIER)
  63. int16_t key; /* Needed to cancel pending notification */
  64. #endif
  65. };
  66. /****************************************************************************
  67. * Private Functions
  68. ****************************************************************************/
  69. /****************************************************************************
  70. * Name: tcp_poll_eventhandler
  71. *
  72. * Description:
  73. * This function is called to perform the actual TCP receive operation via
  74. * the device interface layer.
  75. *
  76. * Input Parameters:
  77. * dev The structure of the network driver that caused the event
  78. * conn The connection structure associated with the socket
  79. * flags Set of events describing why the callback was invoked
  80. *
  81. * Returned Value:
  82. * None
  83. *
  84. * Assumptions:
  85. * The network is locked
  86. *
  87. ****************************************************************************/
  88. static uint16_t tcp_poll_eventhandler(FAR struct net_driver_s *dev,
  89. FAR void *conn,
  90. FAR void *pvpriv, uint16_t flags)
  91. {
  92. FAR struct tcp_poll_s *info = (FAR struct tcp_poll_s *)pvpriv;
  93. ninfo("flags: %04x\n", flags);
  94. DEBUGASSERT(info == NULL || (info->psock != NULL && info->fds != NULL));
  95. /* 'priv' might be null in some race conditions (?) */
  96. if (info != NULL)
  97. {
  98. pollevent_t eventset = 0;
  99. /* Check for data or connection availability events. */
  100. if ((flags & (TCP_NEWDATA | TCP_BACKLOG)) != 0)
  101. {
  102. eventset |= POLLIN & info->fds->events;
  103. }
  104. /* A poll is a sign that we are free to send data.
  105. * REVISIT: This is bogus: If CONFIG_TCP_WRITE_BUFFERS=y then
  106. * we never have to wait to send; otherwise, we always have to
  107. * wait to send. Receiving a poll is irrelevant.
  108. */
  109. if ((flags & TCP_POLL) != 0)
  110. {
  111. eventset |= (POLLOUT & info->fds->events);
  112. }
  113. /* Check for a loss of connection events. */
  114. if ((flags & TCP_DISCONN_EVENTS) != 0)
  115. {
  116. /* Mark that the connection has been lost */
  117. tcp_lost_connection(info->psock, info->cb, flags);
  118. eventset |= (POLLERR | POLLHUP);
  119. }
  120. /* Awaken the caller of poll() if requested event occurred. */
  121. if (eventset != 0)
  122. {
  123. /* Stop further callbacks */
  124. info->cb->flags = 0;
  125. info->cb->priv = NULL;
  126. info->cb->event = NULL;
  127. info->fds->revents |= eventset;
  128. nxsem_post(info->fds->sem);
  129. }
  130. }
  131. return flags;
  132. }
  133. /****************************************************************************
  134. * Name: tcp_iob_work
  135. *
  136. * Description:
  137. * Work thread callback function execute when an IOB because available.
  138. *
  139. * Input Parameters:
  140. * psock - Socket state structure
  141. *
  142. * Returned Value:
  143. * None
  144. *
  145. ****************************************************************************/
  146. #if defined(CONFIG_NET_TCP_WRITE_BUFFERS) && defined(CONFIG_IOB_NOTIFIER)
  147. static inline void tcp_iob_work(FAR void *arg)
  148. {
  149. FAR struct work_notifier_entry_s *entry;
  150. FAR struct work_notifier_s *ninfo;
  151. FAR struct tcp_poll_s *pinfo;
  152. FAR struct socket *psock;
  153. FAR struct pollfd *fds;
  154. entry = (FAR struct work_notifier_entry_s *)arg;
  155. DEBUGASSERT(entry != NULL);
  156. ninfo = &entry->info;
  157. DEBUGASSERT(ninfo->arg != NULL);
  158. pinfo = (FAR struct tcp_poll_s *)ninfo->arg;
  159. DEBUGASSERT(pinfo->psock != NULL && pinfo->fds != NULL);
  160. psock = pinfo->psock;
  161. fds = pinfo->fds;
  162. /* Verify that we still have a connection */
  163. if (!_SS_ISCONNECTED(psock->s_flags) && !_SS_ISLISTENING(psock->s_flags))
  164. {
  165. /* Don't report more than once. Might happen in a race condition */
  166. if ((fds->revents & (POLLERR | POLLHUP)) == 0)
  167. {
  168. /* We were previously connected but lost the connection either due
  169. * to a graceful shutdown by the remote peer or because of some
  170. * exceptional event.
  171. */
  172. fds->revents |= (POLLERR | POLLHUP);
  173. nxsem_post(fds->sem);
  174. }
  175. }
  176. /* Handle a race condition. Check if we have already posted the POLLOUT
  177. * event. If so, don't do it again and don't setup notification again.
  178. */
  179. else if ((fds->events && POLLWRNORM) == 0 ||
  180. (fds->revents && POLLWRNORM) != 0)
  181. {
  182. /* Check if we are now able to send */
  183. if (psock_tcp_cansend(psock) >= 0)
  184. {
  185. /* Yes.. then signal the poll logic */
  186. fds->revents |= POLLWRNORM;
  187. nxsem_post(fds->sem);
  188. }
  189. else
  190. {
  191. /* No.. ask for the IOB free notification again */
  192. pinfo->key = iob_notifier_setup(LPWORK, tcp_iob_work, pinfo);
  193. }
  194. }
  195. /* Protocol for the use of the IOB notifier is that we free the argument
  196. * after the notification has been processed.
  197. */
  198. kmm_free(arg);
  199. }
  200. #endif
  201. /****************************************************************************
  202. * Name: tcp_poll_txnotify
  203. *
  204. * Description:
  205. * Notify the appropriate device driver that we are have data ready to
  206. * be sent (TCP)
  207. *
  208. * Input Parameters:
  209. * psock - Socket state structure
  210. *
  211. * Returned Value:
  212. * None
  213. *
  214. ****************************************************************************/
  215. #if !defined(CONFIG_NET_TCP_WRITE_BUFFERS) || !defined(CONFIG_IOB_NOTIFIER)
  216. static inline void tcp_poll_txnotify(FAR struct socket *psock)
  217. {
  218. FAR struct tcp_conn_s *conn = psock->s_conn;
  219. #ifdef CONFIG_NET_IPv4
  220. #ifdef CONFIG_NET_IPv6
  221. /* If both IPv4 and IPv6 support are enabled, then we will need to select
  222. * the device driver using the appropriate IP domain.
  223. */
  224. if (psock->s_domain == PF_INET)
  225. #endif
  226. {
  227. /* Notify the device driver that send data is available */
  228. netdev_ipv4_txnotify(conn->u.ipv4.laddr, conn->u.ipv4.raddr);
  229. }
  230. #endif /* CONFIG_NET_IPv4 */
  231. #ifdef CONFIG_NET_IPv6
  232. #ifdef CONFIG_NET_IPv4
  233. else /* if (psock->s_domain == PF_INET6) */
  234. #endif /* CONFIG_NET_IPv4 */
  235. {
  236. /* Notify the device driver that send data is available */
  237. DEBUGASSERT(psock->s_domain == PF_INET6);
  238. netdev_ipv6_txnotify(conn->u.ipv6.laddr, conn->u.ipv6.raddr);
  239. }
  240. #endif /* CONFIG_NET_IPv6 */
  241. }
  242. #endif
  243. /****************************************************************************
  244. * Public Functions
  245. ****************************************************************************/
  246. /****************************************************************************
  247. * Name: tcp_pollsetup
  248. *
  249. * Description:
  250. * Setup to monitor events on one TCP/IP socket
  251. *
  252. * Input Parameters:
  253. * psock - The TCP/IP socket of interest
  254. * fds - The structure describing the events to be monitored, OR NULL if
  255. * this is a request to stop monitoring events.
  256. *
  257. * Returned Value:
  258. * 0: Success; Negated errno on failure
  259. *
  260. ****************************************************************************/
  261. int tcp_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
  262. {
  263. FAR struct tcp_conn_s *conn = psock->s_conn;
  264. FAR struct tcp_poll_s *info;
  265. FAR struct devif_callback_s *cb;
  266. int ret;
  267. /* Sanity check */
  268. #ifdef CONFIG_DEBUG_FEATURES
  269. if (!conn || !fds)
  270. {
  271. return -EINVAL;
  272. }
  273. #endif
  274. /* Allocate a container to hold the poll information */
  275. info = (FAR struct tcp_poll_s *)kmm_malloc(sizeof(struct tcp_poll_s));
  276. if (!info)
  277. {
  278. return -ENOMEM;
  279. }
  280. /* Some of the following must be atomic */
  281. net_lock();
  282. /* Allocate a TCP/IP callback structure */
  283. cb = tcp_callback_alloc(conn);
  284. if (!cb)
  285. {
  286. ret = -EBUSY;
  287. goto errout_with_lock;
  288. }
  289. /* Initialize the poll info container */
  290. info->psock = psock;
  291. info->fds = fds;
  292. info->cb = cb;
  293. #if defined(CONFIG_NET_TCP_WRITE_BUFFERS) && defined(CONFIG_IOB_NOTIFIER)
  294. info->key = 0;
  295. #endif
  296. /* Initialize the callback structure. Save the reference to the info
  297. * structure as callback private data so that it will be available during
  298. * callback processing.
  299. */
  300. cb->flags = (TCP_NEWDATA | TCP_BACKLOG | TCP_POLL | TCP_DISCONN_EVENTS);
  301. cb->priv = (FAR void *)info;
  302. cb->event = tcp_poll_eventhandler;
  303. /* Save the reference in the poll info structure as fds private as well
  304. * for use during poll teardown as well.
  305. */
  306. fds->priv = (FAR void *)info;
  307. #ifdef CONFIG_NET_TCPBACKLOG
  308. /* Check for read data or backlogged connection availability now */
  309. if (!IOB_QEMPTY(&conn->readahead) || tcp_backlogavailable(conn))
  310. #else
  311. /* Check for read data availability now */
  312. if (!IOB_QEMPTY(&conn->readahead))
  313. #endif
  314. {
  315. /* Normal data may be read without blocking. */
  316. fds->revents |= (POLLRDNORM & fds->events);
  317. }
  318. /* Check for a loss of connection events. We need to be careful here.
  319. * There are four possibilities:
  320. *
  321. * 1) The socket is connected and we are waiting for data availability
  322. * events.
  323. *
  324. * __SS_ISCONNECTED(f) == true
  325. * __SS_ISLISTENING(f) == false
  326. * __SS_ISCLOSED(f) == false
  327. *
  328. * Action: Wait for data availability events
  329. *
  330. * 2) This is a listener socket that was never connected and we are
  331. * waiting for connection events.
  332. *
  333. * __SS_ISCONNECTED(f) == false
  334. * __SS_ISLISTENING(f) == true
  335. * __SS_ISCLOSED(f) == false
  336. *
  337. * Action: Wait for connection events
  338. *
  339. * 3) This socket was previously connected, but the peer has gracefully
  340. * closed the connection.
  341. *
  342. * __SS_ISCONNECTED(f) == false
  343. * __SS_ISLISTENING(f) == false
  344. * __SS_ISCLOSED(f) == true
  345. *
  346. * Action: Return with POLLHUP|POLLERR events
  347. *
  348. * 4) This socket was previously connected, but we lost the connection
  349. * due to some exceptional event.
  350. *
  351. * __SS_ISCONNECTED(f) == false
  352. * __SS_ISLISTENING(f) == false
  353. * __SS_ISCLOSED(f) == false
  354. *
  355. * Action: Return with POLLHUP|POLLERR events
  356. */
  357. if (!_SS_ISCONNECTED(psock->s_flags) && !_SS_ISLISTENING(psock->s_flags))
  358. {
  359. /* We were previously connected but lost the connection either due
  360. * to a graceful shutdown by the remote peer or because of some
  361. * exceptional event.
  362. */
  363. fds->revents |= (POLLERR | POLLHUP);
  364. }
  365. else if (_SS_ISCONNECTED(psock->s_flags) && psock_tcp_cansend(psock) >= 0)
  366. {
  367. fds->revents |= (POLLWRNORM & fds->events);
  368. }
  369. /* Check if any requested events are already in effect */
  370. if (fds->revents != 0)
  371. {
  372. /* Yes.. then signal the poll logic */
  373. nxsem_post(fds->sem);
  374. }
  375. #if defined(CONFIG_NET_TCP_WRITE_BUFFERS) && defined(CONFIG_IOB_NOTIFIER)
  376. /* If (1) revents == 0, (2) write buffering is enabled, and (3) the
  377. * POLLOUT event is needed, then setup to receive a notification an IOB
  378. * is freed.
  379. */
  380. else if ((fds->events & POLLOUT) != 0)
  381. {
  382. /* Ask for the IOB free notification */
  383. info->key = iob_notifier_setup(LPWORK, tcp_iob_work, info);
  384. }
  385. #else
  386. /* If (1) the socket is in a bound state, (2) revents == 0, (3) write
  387. * buffering is not enabled (determined by a configuration setting), and
  388. * (4) the POLLOUT event is needed then request an immediate Tx poll from
  389. * the device associated with the binding.
  390. */
  391. else if (_SS_ISBOUND(psock->s_flags) && (fds->events & POLLOUT) != 0)
  392. {
  393. /* Note that the notification will fail if the socket is bound to
  394. * INADDR_ANY or the IPv6 unspecified address! In that case the
  395. * notification will fail.
  396. */
  397. tcp_poll_txnotify(psock);
  398. }
  399. #endif
  400. net_unlock();
  401. return OK;
  402. errout_with_lock:
  403. kmm_free(info);
  404. net_unlock();
  405. return ret;
  406. }
  407. /****************************************************************************
  408. * Name: tcp_pollteardown
  409. *
  410. * Description:
  411. * Teardown monitoring of events on an TCP/IP socket
  412. *
  413. * Input Parameters:
  414. * psock - The TCP/IP socket of interest
  415. * fds - The structure describing the events to be monitored, OR NULL if
  416. * this is a request to stop monitoring events.
  417. *
  418. * Returned Value:
  419. * 0: Success; Negated errno on failure
  420. *
  421. ****************************************************************************/
  422. int tcp_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds)
  423. {
  424. FAR struct tcp_conn_s *conn = psock->s_conn;
  425. FAR struct tcp_poll_s *info;
  426. /* Sanity check */
  427. #ifdef CONFIG_DEBUG_FEATURES
  428. if (!conn || !fds->priv)
  429. {
  430. return -EINVAL;
  431. }
  432. #endif
  433. /* Recover the socket descriptor poll state info from the poll structure */
  434. info = (FAR struct tcp_poll_s *)fds->priv;
  435. DEBUGASSERT(info != NULL && info->fds != NULL && info->cb != NULL);
  436. if (info != NULL)
  437. {
  438. #if defined(CONFIG_NET_TCP_WRITE_BUFFERS) && defined(CONFIG_IOB_NOTIFIER)
  439. /* Cancel any pending IOB free notification */
  440. if (info->key > 0)
  441. {
  442. /* Ask for the IOB free notification */
  443. iob_notifier_teardown(info->key);
  444. }
  445. #endif
  446. /* Release the callback */
  447. net_lock();
  448. tcp_callback_free(conn, info->cb);
  449. net_unlock();
  450. /* Release the poll/select data slot */
  451. info->fds->priv = NULL;
  452. /* Then free the poll info container */
  453. kmm_free(info);
  454. }
  455. return OK;
  456. }
  457. #endif /* HAVE_TCP_POLL */