local_recvfrom.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  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 calle.
  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. if (ret < 0)
  236. {
  237. nerr("ERROR: Failed to open FIFO for %s: %d\n",
  238. conn->lc_path, ret);
  239. goto errout_with_halfduplex;
  240. return ret;
  241. }
  242. /* Sync to the start of the next packet in the stream and get the size of
  243. * the next packet.
  244. */
  245. ret = local_sync(&conn->lc_infile);
  246. if (ret < 0)
  247. {
  248. nerr("ERROR: Failed to get packet length: %d\n", ret);
  249. goto errout_with_infd;
  250. }
  251. else if (ret > UINT16_MAX)
  252. {
  253. nerr("ERROR: Packet is too big: %d\n", ret);
  254. goto errout_with_infd;
  255. }
  256. pktlen = ret;
  257. /* Read the packet */
  258. readlen = MIN(pktlen, len);
  259. ret = psock_fifo_read(psock, buf, &readlen);
  260. if (ret < 0)
  261. {
  262. goto errout_with_infd;
  263. }
  264. /* If there are unread bytes remaining in the packet, flush the remainder
  265. * of the packet to the bit bucket.
  266. */
  267. DEBUGASSERT(readlen <= pktlen);
  268. if (readlen < pktlen)
  269. {
  270. uint8_t bitbucket[32];
  271. uint16_t remaining;
  272. size_t tmplen;
  273. remaining = pktlen - readlen;
  274. do
  275. {
  276. /* Read 32 bytes into the bit bucket */
  277. readlen = MIN(remaining, 32);
  278. ret = psock_fifo_read(psock, bitbucket, &tmplen);
  279. if (ret < 0)
  280. {
  281. goto errout_with_infd;
  282. }
  283. /* Adjust the number of bytes remaining to be read from the packet */
  284. DEBUGASSERT(tmplen <= remaining);
  285. remaining -= tmplen;
  286. }
  287. while (remaining > 0);
  288. }
  289. /* Now we can close the read-only file descriptor */
  290. file_close(&conn->lc_infile);
  291. conn->lc_infile.f_inode = NULL;
  292. /* Release our reference to the half duplex FIFO */
  293. (void)local_release_halfduplex(conn);
  294. /* Return the address family */
  295. if (from)
  296. {
  297. ret = local_getaddr(conn, from, fromlen);
  298. if (ret < 0)
  299. {
  300. return ret;
  301. }
  302. }
  303. return readlen;
  304. errout_with_infd:
  305. /* Close the read-only file descriptor */
  306. file_close(&conn->lc_infile);
  307. conn->lc_infile.f_inode = NULL;
  308. errout_with_halfduplex:
  309. /* Release our reference to the half duplex FIFO */
  310. (void)local_release_halfduplex(conn);
  311. return ret;
  312. }
  313. #endif /* CONFIG_NET_LOCAL_STREAM */
  314. /****************************************************************************
  315. * Public Functions
  316. ****************************************************************************/
  317. /****************************************************************************
  318. * Name: local_recvfrom
  319. *
  320. * Description:
  321. * local_recvfrom() receives messages from a local socket and may be used
  322. * to receive data on a socket whether or not it is connection-oriented.
  323. *
  324. * If from is not NULL, and the underlying protocol provides the source
  325. * address, this source address is filled in. The argument fromlen
  326. * initialized to the size of the buffer associated with from, and modified
  327. * on return to indicate the actual size of the address stored there.
  328. *
  329. * Input Parameters:
  330. * psock A pointer to a NuttX-specific, internal socket structure
  331. * buf Buffer to receive data
  332. * len Length of buffer
  333. * flags Receive flags
  334. * from Address of source (may be NULL)
  335. * fromlen The length of the address structure
  336. *
  337. * Returned Value:
  338. * On success, returns the number of characters received. If no data is
  339. * available to be received and the peer has performed an orderly shutdown,
  340. * recv() will return 0. Otherwise, on errors, a negated errno value is
  341. * returned (see recv_from() for the complete list of appropriate error
  342. * values).
  343. *
  344. ****************************************************************************/
  345. ssize_t local_recvfrom(FAR struct socket *psock, FAR void *buf,
  346. size_t len, int flags, FAR struct sockaddr *from,
  347. FAR socklen_t *fromlen)
  348. {
  349. DEBUGASSERT(psock && psock->s_conn && buf);
  350. /* Check for a stream socket */
  351. #ifdef CONFIG_NET_LOCAL_STREAM
  352. if (psock->s_type == SOCK_STREAM)
  353. {
  354. return psock_stream_recvfrom(psock, buf, len, flags, from, fromlen);
  355. }
  356. else
  357. #endif
  358. #ifdef CONFIG_NET_LOCAL_DGRAM
  359. if (psock->s_type == SOCK_DGRAM)
  360. {
  361. return psock_dgram_recvfrom(psock, buf, len, flags, from, fromlen);
  362. }
  363. else
  364. #endif
  365. {
  366. DEBUGPANIC();
  367. nerr("ERROR: Unrecognized socket type: %s\n", psock->s_type);
  368. return -EINVAL;
  369. }
  370. }
  371. #endif /* CONFIG_NET && CONFIG_NET_LOCAL */