local_recvfrom.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. /****************************************************************************
  2. * net/local/local_recvfrom.c
  3. *
  4. * Copyright (C) 2015 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/config.h>
  39. #if defined(CONFIG_NET) && defined(CONFIG_NET_LOCAL)
  40. #include <sys/types.h>
  41. #include <sys/socket.h>
  42. #include <unistd.h>
  43. #include <errno.h>
  44. #include <assert.h>
  45. #include <debug.h>
  46. #include <nuttx/net/net.h>
  47. #include "socket/socket.h"
  48. #include "local/local.h"
  49. /****************************************************************************
  50. * Pre-processor Definitions
  51. ****************************************************************************/
  52. #ifndef MIN
  53. # define MIN(a,b) ((a) < (b) ? (a) : (b))
  54. #endif
  55. /****************************************************************************
  56. * Private Functions
  57. ****************************************************************************/
  58. /****************************************************************************
  59. * Name: psock_fifo_read
  60. *
  61. * Description:
  62. * A thin layer around local_fifo_read that handles socket-related loss-of-
  63. * connection events.
  64. *
  65. ****************************************************************************/
  66. static int psock_fifo_read(FAR struct socket *psock, FAR void *buf,
  67. FAR size_t *readlen)
  68. {
  69. FAR struct local_conn_s *conn = (FAR struct local_conn_s *)psock->s_conn;
  70. int ret;
  71. ret = local_fifo_read(&conn->lc_infile, buf, readlen);
  72. if (ret < 0)
  73. {
  74. /* -ECONNRESET is a special case. We may or not have received
  75. * data, then the peer closed the connection.
  76. */
  77. if (ret == -ECONNRESET)
  78. {
  79. nerr("ERROR: Lost connection: %d\n", ret);
  80. /* Report an ungraceful loss of connection. This should
  81. * eventually be reported as ENOTCONN.
  82. */
  83. psock->s_flags &= ~(_SF_CONNECTED | _SF_CLOSED);
  84. conn->lc_state = LOCAL_STATE_DISCONNECTED;
  85. /* Did we receive any data? */
  86. if (*readlen <= 0)
  87. {
  88. /* No.. return the ECONNRESET error now. Otherwise,
  89. * process the received data and return ENOTCONN the
  90. * next time that psock_recvfrom() is called.
  91. */
  92. return ret;
  93. }
  94. }
  95. else
  96. {
  97. nerr("ERROR: Failed to read packet: %d\n", ret);
  98. return ret;
  99. }
  100. }
  101. return OK;
  102. }
  103. /****************************************************************************
  104. * Name: psock_stream_recvfrom
  105. *
  106. * Description:
  107. * psock_stream_recvfrom() receives messages from a local stream socket.
  108. *
  109. * Input Parameters:
  110. * psock A pointer to a NuttX-specific, internal socket structure
  111. * buf Buffer to receive data
  112. * len Length of buffer
  113. * flags Receive flags
  114. * from Address of source (may be NULL)
  115. * fromlen The length of the address structure
  116. *
  117. * Returned Value:
  118. * On success, returns the number of characters received. If no data is
  119. * available to be received and the peer has performed an orderly shutdown,
  120. * recv() will return 0. Otherwise, on errors, -1 is returned, and errno
  121. * is set appropriately (see receive from for the complete list).
  122. *
  123. ****************************************************************************/
  124. #ifdef CONFIG_NET_LOCAL_STREAM
  125. static inline ssize_t
  126. psock_stream_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
  127. int flags, FAR struct sockaddr *from,
  128. FAR socklen_t *fromlen)
  129. {
  130. FAR struct local_conn_s *conn = (FAR struct local_conn_s *)psock->s_conn;
  131. size_t readlen;
  132. int ret;
  133. /* Verify that this is a connected peer socket */
  134. if (conn->lc_state != LOCAL_STATE_CONNECTED)
  135. {
  136. nerr("ERROR: not connected\n");
  137. return -ENOTCONN;
  138. }
  139. /* The incoming FIFO should be open */
  140. DEBUGASSERT(conn->lc_infile.f_inode != NULL);
  141. /* Are there still bytes in the FIFO from the last packet? */
  142. if (conn->u.peer.lc_remaining == 0)
  143. {
  144. /* No.. Sync to the start of the next packet in the stream and get
  145. * the size of the next packet.
  146. */
  147. ret = local_sync(&conn->lc_infile);
  148. if (ret < 0)
  149. {
  150. nerr("ERROR: Failed to get packet length: %d\n", ret);
  151. return ret;
  152. }
  153. else if (ret > UINT16_MAX)
  154. {
  155. nerr("ERROR: Packet is too big: %d\n", ret);
  156. return -E2BIG;
  157. }
  158. conn->u.peer.lc_remaining = (uint16_t)ret;
  159. }
  160. /* Read the packet */
  161. readlen = MIN(conn->u.peer.lc_remaining, len);
  162. ret = psock_fifo_read(psock, buf, &readlen);
  163. if (ret < 0)
  164. {
  165. return ret;
  166. }
  167. /* Adjust the number of bytes remaining to be read from the packet */
  168. DEBUGASSERT(readlen <= conn->u.peer.lc_remaining);
  169. conn->u.peer.lc_remaining -= readlen;
  170. /* Return the address family */
  171. if (from)
  172. {
  173. ret = local_getaddr(conn, from, fromlen);
  174. if (ret < 0)
  175. {
  176. return ret;
  177. }
  178. }
  179. return readlen;
  180. }
  181. #endif /* CONFIG_NET_LOCAL_STREAM */
  182. /****************************************************************************
  183. * Name: psock_dgram_recvfrom
  184. *
  185. * Description:
  186. * psock_dgram_recvfrom() receives messages from a local datagram socket.
  187. *
  188. * Input Parameters:
  189. * psock A pointer to a NuttX-specific, internal socket structure
  190. * buf Buffer to receive data
  191. * len Length of buffer
  192. * flags Receive flags
  193. * from Address of source (may be NULL)
  194. * fromlen The length of the address structure
  195. *
  196. * Returned Value:
  197. * On success, returns the number of characters received. Otherwise, on
  198. * errors, -1 is returned, and errno is set appropriately (see receive
  199. * from for the complete list).
  200. *
  201. ****************************************************************************/
  202. #ifdef CONFIG_NET_LOCAL_DGRAM
  203. static inline ssize_t
  204. psock_dgram_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
  205. int flags, FAR struct sockaddr *from,
  206. FAR socklen_t *fromlen)
  207. {
  208. FAR struct local_conn_s *conn = (FAR struct local_conn_s *)psock->s_conn;
  209. uint16_t pktlen;
  210. size_t readlen;
  211. int ret;
  212. /* We keep packet sizes in a uint16_t, so there is a upper limit to the
  213. * 'len' that can be supported.
  214. */
  215. DEBUGASSERT(len <= UINT16_MAX);
  216. /* Verify that this is a bound, un-connected peer socket */
  217. if (conn->lc_state != LOCAL_STATE_BOUND)
  218. {
  219. /* Either not bound to address or it is connected */
  220. nerr("ERROR: Connected or not bound\n");
  221. return -EISCONN;
  222. }
  223. /* The incoming FIFO should not be open */
  224. DEBUGASSERT(conn->lc_infile.f_inode == NULL);
  225. /* Make sure that half duplex FIFO has been created */
  226. ret = local_create_halfduplex(conn, conn->lc_path);
  227. if (ret < 0)
  228. {
  229. nerr("ERROR: Failed to create FIFO for %s: %d\n",
  230. conn->lc_path, ret);
  231. return ret;
  232. }
  233. /* Open the receiving side of the transfer */
  234. ret = local_open_receiver(conn, _SS_ISNONBLOCK(psock->s_flags) ||
  235. (flags & MSG_DONTWAIT) != 0);
  236. if (ret < 0)
  237. {
  238. nerr("ERROR: Failed to open FIFO for %s: %d\n",
  239. conn->lc_path, ret);
  240. goto errout_with_halfduplex;
  241. return ret;
  242. }
  243. /* Sync to the start of the next packet in the stream and get the size of
  244. * the next packet.
  245. */
  246. ret = local_sync(&conn->lc_infile);
  247. if (ret < 0)
  248. {
  249. nerr("ERROR: Failed to get packet length: %d\n", ret);
  250. goto errout_with_infd;
  251. }
  252. else if (ret > UINT16_MAX)
  253. {
  254. nerr("ERROR: Packet is too big: %d\n", ret);
  255. goto errout_with_infd;
  256. }
  257. pktlen = ret;
  258. /* Read the packet */
  259. readlen = MIN(pktlen, len);
  260. ret = psock_fifo_read(psock, buf, &readlen);
  261. if (ret < 0)
  262. {
  263. goto errout_with_infd;
  264. }
  265. /* If there are unread bytes remaining in the packet, flush the remainder
  266. * of the packet to the bit bucket.
  267. */
  268. DEBUGASSERT(readlen <= pktlen);
  269. if (readlen < pktlen)
  270. {
  271. uint8_t bitbucket[32];
  272. uint16_t remaining;
  273. size_t tmplen;
  274. remaining = pktlen - readlen;
  275. do
  276. {
  277. /* Read 32 bytes into the bit bucket */
  278. readlen = MIN(remaining, 32);
  279. ret = psock_fifo_read(psock, bitbucket, &tmplen);
  280. if (ret < 0)
  281. {
  282. goto errout_with_infd;
  283. }
  284. /* Adjust the number of bytes remaining to be read from the packet */
  285. DEBUGASSERT(tmplen <= remaining);
  286. remaining -= tmplen;
  287. }
  288. while (remaining > 0);
  289. }
  290. /* Now we can close the read-only file descriptor */
  291. file_close(&conn->lc_infile);
  292. conn->lc_infile.f_inode = NULL;
  293. /* Release our reference to the half duplex FIFO */
  294. local_release_halfduplex(conn);
  295. /* Return the address family */
  296. if (from)
  297. {
  298. ret = local_getaddr(conn, from, fromlen);
  299. if (ret < 0)
  300. {
  301. return ret;
  302. }
  303. }
  304. return readlen;
  305. errout_with_infd:
  306. /* Close the read-only file descriptor */
  307. file_close(&conn->lc_infile);
  308. conn->lc_infile.f_inode = NULL;
  309. errout_with_halfduplex:
  310. /* Release our reference to the half duplex FIFO */
  311. local_release_halfduplex(conn);
  312. return ret;
  313. }
  314. #endif /* CONFIG_NET_LOCAL_STREAM */
  315. /****************************************************************************
  316. * Public Functions
  317. ****************************************************************************/
  318. /****************************************************************************
  319. * Name: local_recvfrom
  320. *
  321. * Description:
  322. * local_recvfrom() receives messages from a local socket and may be used
  323. * to receive data on a socket whether or not it is connection-oriented.
  324. *
  325. * If from is not NULL, and the underlying protocol provides the source
  326. * address, this source address is filled in. The argument fromlen
  327. * initialized to the size of the buffer associated with from, and modified
  328. * on return to indicate the actual size of the address stored there.
  329. *
  330. * Input Parameters:
  331. * psock A pointer to a NuttX-specific, internal socket structure
  332. * buf Buffer to receive data
  333. * len Length of buffer
  334. * flags Receive flags
  335. * from Address of source (may be NULL)
  336. * fromlen The length of the address structure
  337. *
  338. * Returned Value:
  339. * On success, returns the number of characters received. If no data is
  340. * available to be received and the peer has performed an orderly shutdown,
  341. * recv() will return 0. Otherwise, on errors, a negated errno value is
  342. * returned (see recv_from() for the complete list of appropriate error
  343. * values).
  344. *
  345. ****************************************************************************/
  346. ssize_t local_recvfrom(FAR struct socket *psock, FAR void *buf,
  347. size_t len, int flags, FAR struct sockaddr *from,
  348. FAR socklen_t *fromlen)
  349. {
  350. DEBUGASSERT(psock && psock->s_conn && buf);
  351. /* Check for a stream socket */
  352. #ifdef CONFIG_NET_LOCAL_STREAM
  353. if (psock->s_type == SOCK_STREAM)
  354. {
  355. return psock_stream_recvfrom(psock, buf, len, flags, from, fromlen);
  356. }
  357. else
  358. #endif
  359. #ifdef CONFIG_NET_LOCAL_DGRAM
  360. if (psock->s_type == SOCK_DGRAM)
  361. {
  362. return psock_dgram_recvfrom(psock, buf, len, flags, from, fromlen);
  363. }
  364. else
  365. #endif
  366. {
  367. DEBUGPANIC();
  368. nerr("ERROR: Unrecognized socket type: %s\n", psock->s_type);
  369. return -EINVAL;
  370. }
  371. }
  372. #endif /* CONFIG_NET && CONFIG_NET_LOCAL */