usrsock_recvfrom.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. /****************************************************************************
  2. * net/usrsock/usrsock_recvfrom.c
  3. *
  4. * Copyright (C) 2015, 2017 Haltian Ltd. All rights reserved.
  5. * Author: Jussi Kivilinna <jussi.kivilinna@haltian.com>
  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/config.h>
  39. #if defined(CONFIG_NET) && defined(CONFIG_NET_USRSOCK)
  40. #include <stdint.h>
  41. #include <string.h>
  42. #include <assert.h>
  43. #include <errno.h>
  44. #include <debug.h>
  45. #include <arch/irq.h>
  46. #include <sys/socket.h>
  47. #include <nuttx/semaphore.h>
  48. #include <nuttx/net/net.h>
  49. #include <nuttx/net/usrsock.h>
  50. #include "usrsock/usrsock.h"
  51. /****************************************************************************
  52. * Private Functions
  53. ****************************************************************************/
  54. static uint16_t recvfrom_event(FAR struct net_driver_s *dev, FAR void *pvconn,
  55. FAR void *pvpriv, uint16_t flags)
  56. {
  57. FAR struct usrsock_data_reqstate_s *pstate = pvpriv;
  58. FAR struct usrsock_conn_s *conn = pvconn;
  59. if (flags & USRSOCK_EVENT_ABORT)
  60. {
  61. ninfo("socket aborted.\n");
  62. pstate->reqstate.result = -ECONNABORTED;
  63. pstate->valuelen = 0;
  64. pstate->valuelen_nontrunc = 0;
  65. /* Stop further callbacks */
  66. pstate->reqstate.cb->flags = 0;
  67. pstate->reqstate.cb->priv = NULL;
  68. pstate->reqstate.cb->event = NULL;
  69. /* Wake up the waiting thread */
  70. nxsem_post(&pstate->reqstate.recvsem);
  71. }
  72. else if (flags & USRSOCK_EVENT_REQ_COMPLETE)
  73. {
  74. ninfo("request completed.\n");
  75. pstate->reqstate.result = conn->resp.result;
  76. if (pstate->reqstate.result < 0)
  77. {
  78. pstate->valuelen = 0;
  79. pstate->valuelen_nontrunc = 0;
  80. }
  81. else
  82. {
  83. pstate->valuelen = conn->resp.valuelen;
  84. pstate->valuelen_nontrunc = conn->resp.valuelen_nontrunc;
  85. }
  86. if (pstate->reqstate.result >= 0 ||
  87. pstate->reqstate.result == -EAGAIN)
  88. {
  89. /* After reception of data, mark input not ready. Daemon will
  90. * send event to restore this flag. */
  91. conn->flags &= ~USRSOCK_EVENT_RECVFROM_AVAIL;
  92. }
  93. /* Stop further callbacks */
  94. pstate->reqstate.cb->flags = 0;
  95. pstate->reqstate.cb->priv = NULL;
  96. pstate->reqstate.cb->event = NULL;
  97. /* Wake up the waiting thread */
  98. nxsem_post(&pstate->reqstate.recvsem);
  99. }
  100. else if (flags & USRSOCK_EVENT_REMOTE_CLOSED)
  101. {
  102. ninfo("remote closed.\n");
  103. pstate->reqstate.result = -EPIPE;
  104. /* Stop further callbacks */
  105. pstate->reqstate.cb->flags = 0;
  106. pstate->reqstate.cb->priv = NULL;
  107. pstate->reqstate.cb->event = NULL;
  108. /* Wake up the waiting thread */
  109. nxsem_post(&pstate->reqstate.recvsem);
  110. }
  111. else if (flags & USRSOCK_EVENT_RECVFROM_AVAIL)
  112. {
  113. ninfo("recvfrom avail.\n");
  114. flags &= ~USRSOCK_EVENT_RECVFROM_AVAIL;
  115. /* Stop further callbacks */
  116. pstate->reqstate.cb->flags = 0;
  117. pstate->reqstate.cb->priv = NULL;
  118. pstate->reqstate.cb->event = NULL;
  119. /* Wake up the waiting thread */
  120. nxsem_post(&pstate->reqstate.recvsem);
  121. }
  122. return flags;
  123. }
  124. /****************************************************************************
  125. * Name: do_recvfrom_request
  126. ****************************************************************************/
  127. static int do_recvfrom_request(FAR struct usrsock_conn_s *conn, size_t buflen,
  128. socklen_t addrlen)
  129. {
  130. struct usrsock_request_recvfrom_s req = {};
  131. struct iovec bufs[1];
  132. if (addrlen > UINT16_MAX)
  133. {
  134. addrlen = UINT16_MAX;
  135. }
  136. if (buflen > UINT16_MAX)
  137. {
  138. buflen = UINT16_MAX;
  139. }
  140. /* Prepare request for daemon to read. */
  141. req.head.reqid = USRSOCK_REQUEST_RECVFROM;
  142. req.usockid = conn->usockid;
  143. req.max_addrlen = addrlen;
  144. req.max_buflen = buflen;
  145. bufs[0].iov_base = (FAR void *)&req;
  146. bufs[0].iov_len = sizeof(req);
  147. return usrsockdev_do_request(conn, bufs, ARRAY_SIZE(bufs));
  148. }
  149. /****************************************************************************
  150. * Name: usrsock_recvfrom
  151. *
  152. * Description:
  153. * recvfrom() receives messages from a socket, and may be used to receive
  154. * data on a socket whether or not it is connection-oriented.
  155. *
  156. * If from is not NULL, and the underlying protocol provides the source
  157. * address, this source address is filled in. The argument fromlen
  158. * initialized to the size of the buffer associated with from, and modified
  159. * on return to indicate the actual size of the address stored there.
  160. *
  161. * Input Parameters:
  162. * psock A pointer to a NuttX-specific, internal socket structure
  163. * buf Buffer to receive data
  164. * len Length of buffer
  165. * flags Receive flags (ignored)
  166. * from Address of source (may be NULL)
  167. * fromlen The length of the address structure
  168. *
  169. ****************************************************************************/
  170. ssize_t usrsock_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
  171. int flags, FAR struct sockaddr *from,
  172. FAR socklen_t *fromlen)
  173. {
  174. FAR struct usrsock_conn_s *conn = psock->s_conn;
  175. struct usrsock_data_reqstate_s state = {};
  176. struct iovec inbufs[2];
  177. socklen_t addrlen = 0;
  178. socklen_t outaddrlen = 0;
  179. ssize_t ret;
  180. #ifdef CONFIG_NET_SOCKOPTS
  181. struct timespec abstime;
  182. #endif
  183. struct timespec *ptimeo = NULL;
  184. DEBUGASSERT(conn);
  185. if (fromlen)
  186. {
  187. if (*fromlen > 0 && from == NULL)
  188. {
  189. return -EINVAL;
  190. }
  191. addrlen = *fromlen;
  192. }
  193. net_lock();
  194. if (conn->state == USRSOCK_CONN_STATE_UNINITIALIZED ||
  195. conn->state == USRSOCK_CONN_STATE_ABORTED)
  196. {
  197. /* Invalid state or closed by daemon. */
  198. ninfo("usockid=%d; connect() with uninitialized usrsock.\n",
  199. conn->usockid);
  200. ret = (conn->state == USRSOCK_CONN_STATE_ABORTED) ? -EPIPE : -ECONNRESET;
  201. goto errout_unlock;
  202. }
  203. if (conn->type == SOCK_STREAM || conn->type == SOCK_SEQPACKET)
  204. {
  205. if (!conn->connected)
  206. {
  207. if (conn->state == USRSOCK_CONN_STATE_CONNECTING)
  208. {
  209. /* Connecting. */
  210. ninfo("usockid=%d; socket still connecting.\n",
  211. conn->usockid);
  212. ret = -EAGAIN;
  213. goto errout_unlock;
  214. }
  215. else
  216. {
  217. /* Not connected. */
  218. ninfo("usockid=%d; socket not connected.\n",
  219. conn->usockid);
  220. ret = -ENOTCONN;
  221. goto errout_unlock;
  222. }
  223. }
  224. }
  225. if (conn->state == USRSOCK_CONN_STATE_CONNECTING)
  226. {
  227. /* Non-blocking connecting. */
  228. ninfo("usockid=%d; socket still connecting.\n",
  229. conn->usockid);
  230. ret = -EAGAIN;
  231. goto errout_unlock;
  232. }
  233. #ifdef CONFIG_NET_SOCKOPTS
  234. if (psock->s_rcvtimeo != 0)
  235. {
  236. DEBUGVERIFY(clock_gettime(CLOCK_REALTIME, &abstime));
  237. /* Prepare timeout value for recvfrom. */
  238. abstime.tv_sec += psock->s_rcvtimeo / DSEC_PER_SEC;
  239. abstime.tv_nsec += (psock->s_rcvtimeo % DSEC_PER_SEC) * NSEC_PER_DSEC;
  240. if (abstime.tv_nsec >= NSEC_PER_SEC)
  241. {
  242. abstime.tv_sec++;
  243. abstime.tv_nsec -= NSEC_PER_SEC;
  244. }
  245. ptimeo = &abstime;
  246. }
  247. #endif
  248. do
  249. {
  250. /* Check if remote end has closed connection. */
  251. if (conn->flags & USRSOCK_EVENT_REMOTE_CLOSED)
  252. {
  253. ninfo("usockid=%d; remote closed (EOF).\n", conn->usockid);
  254. ret = 0;
  255. goto errout_unlock;
  256. }
  257. /* Check if need to wait for receive data to become available. */
  258. if (!(conn->flags & USRSOCK_EVENT_RECVFROM_AVAIL))
  259. {
  260. if (_SS_ISNONBLOCK(psock->s_flags))
  261. {
  262. /* Nothing to receive from daemon side. */
  263. ret = -EAGAIN;
  264. goto errout_unlock;
  265. }
  266. /* Wait recv to become avail. */
  267. ret = usrsock_setup_data_request_callback(
  268. conn, &state, recvfrom_event,
  269. USRSOCK_EVENT_ABORT | USRSOCK_EVENT_RECVFROM_AVAIL |
  270. USRSOCK_EVENT_REMOTE_CLOSED);
  271. if (ret < 0)
  272. {
  273. nwarn("usrsock_setup_request_callback failed: %d\n", ret);
  274. goto errout_unlock;
  275. }
  276. /* Wait for receive-avail (or abort, or timeout, or signal). */
  277. ret = net_timedwait(&state.reqstate.recvsem, ptimeo);
  278. if (ret < 0)
  279. {
  280. if (ret == -ETIMEDOUT)
  281. {
  282. ninfo("recvfrom timedout\n");
  283. ret = -EAGAIN;
  284. }
  285. else if (ret == -EINTR)
  286. {
  287. ninfo("recvfrom interrupted\n");
  288. }
  289. else
  290. {
  291. nerr("net_timedwait errno: %d\n", ret);
  292. DEBUGASSERT(false);
  293. }
  294. }
  295. usrsock_teardown_data_request_callback(&state);
  296. /* Did wait timeout or got signal? */
  297. if (ret != 0)
  298. {
  299. goto errout_unlock;
  300. }
  301. /* Was socket aborted? */
  302. if (conn->state == USRSOCK_CONN_STATE_ABORTED)
  303. {
  304. ret = -EPIPE;
  305. goto errout_unlock;
  306. }
  307. /* Did remote disconnect? */
  308. if (conn->flags & USRSOCK_EVENT_REMOTE_CLOSED)
  309. {
  310. ret = 0;
  311. goto errout_unlock;
  312. }
  313. DEBUGASSERT(conn->flags & USRSOCK_EVENT_RECVFROM_AVAIL);
  314. }
  315. /* Set up event callback for usrsock. */
  316. ret = usrsock_setup_data_request_callback(
  317. conn, &state, recvfrom_event,
  318. USRSOCK_EVENT_ABORT | USRSOCK_EVENT_REQ_COMPLETE);
  319. if (ret < 0)
  320. {
  321. nwarn("usrsock_setup_request_callback failed: %d\n", ret);
  322. goto errout_unlock;
  323. }
  324. inbufs[0].iov_base = (FAR void *)from;
  325. inbufs[0].iov_len = addrlen;
  326. inbufs[1].iov_base = (FAR void *)buf;
  327. inbufs[1].iov_len = len;
  328. usrsock_setup_datain(conn, inbufs, ARRAY_SIZE(inbufs));
  329. /* Request user-space daemon to close socket. */
  330. ret = do_recvfrom_request(conn, len, addrlen);
  331. if (ret >= 0)
  332. {
  333. /* Wait for completion of request. */
  334. while ((ret = net_lockedwait(&state.reqstate.recvsem)) < 0)
  335. {
  336. DEBUGASSERT(ret == -EINTR || ret == -ECANCELED);
  337. }
  338. ret = state.reqstate.result;
  339. DEBUGASSERT(ret <= (ssize_t)len);
  340. DEBUGASSERT(state.valuelen <= addrlen);
  341. DEBUGASSERT(state.valuelen <= state.valuelen_nontrunc);
  342. if (ret >= 0)
  343. {
  344. /* Store length of 'from' address that was available at
  345. * daemon-side. */
  346. outaddrlen = state.valuelen_nontrunc;
  347. }
  348. }
  349. usrsock_teardown_datain(conn);
  350. usrsock_teardown_data_request_callback(&state);
  351. }
  352. while (ret == -EAGAIN);
  353. errout_unlock:
  354. net_unlock();
  355. if (fromlen)
  356. {
  357. *fromlen = outaddrlen;
  358. }
  359. return ret;
  360. }
  361. #endif /* CONFIG_NET && CONFIG_NET_USRSOCK */