local_fifo.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. /****************************************************************************
  2. * net/local/local_fifo.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/stat.h>
  41. #include <sys/ioctl.h>
  42. #include <stdbool.h>
  43. #include <stdio.h>
  44. #include <unistd.h>
  45. #include <fcntl.h>
  46. #include <string.h>
  47. #include <errno.h>
  48. #include <assert.h>
  49. #include "local/local.h"
  50. /****************************************************************************
  51. * Pre-processor Definitions
  52. ****************************************************************************/
  53. #define LOCAL_CS_SUFFIX "CS" /* Name of the client-to-server FIFO */
  54. #define LOCAL_SC_SUFFIX "SC" /* Name of the server-to-client FIFO */
  55. #define LOCAL_HD_SUFFIX "HD" /* Name of the half duplex datagram FIFO */
  56. #define LOCAL_SUFFIX_LEN 2
  57. #define LOCAL_FULLPATH_LEN (UNIX_PATH_MAX + LOCAL_SUFFIX_LEN)
  58. /****************************************************************************
  59. * Private Functions
  60. ****************************************************************************/
  61. /****************************************************************************
  62. * Name: local_cs_name
  63. *
  64. * Description:
  65. * Create the name of the client-to-server FIFO.
  66. *
  67. ****************************************************************************/
  68. #ifdef CONFIG_NET_LOCAL_STREAM
  69. static inline void local_cs_name(FAR struct local_conn_s *conn,
  70. FAR char *path)
  71. {
  72. if (conn->lc_instance_id < 0)
  73. {
  74. snprintf(path, LOCAL_FULLPATH_LEN - 1, "%s" LOCAL_CS_SUFFIX,
  75. conn->lc_path);
  76. }
  77. else
  78. {
  79. snprintf(path, LOCAL_FULLPATH_LEN - 1, "%s" LOCAL_CS_SUFFIX "%x",
  80. conn->lc_path, conn->lc_instance_id);
  81. }
  82. path[LOCAL_FULLPATH_LEN - 1] = '\0';
  83. }
  84. #endif /* CONFIG_NET_LOCAL_STREAM */
  85. /****************************************************************************
  86. * Name: local_sc_name
  87. *
  88. * Description:
  89. * Create the name of the server-to-client FIFO.
  90. *
  91. ****************************************************************************/
  92. #ifdef CONFIG_NET_LOCAL_STREAM
  93. static inline void local_sc_name(FAR struct local_conn_s *conn,
  94. FAR char *path)
  95. {
  96. if (conn->lc_instance_id < 0)
  97. {
  98. snprintf(path, LOCAL_FULLPATH_LEN - 1, "%s" LOCAL_SC_SUFFIX,
  99. conn->lc_path);
  100. }
  101. else
  102. {
  103. snprintf(path, LOCAL_FULLPATH_LEN - 1, "%s" LOCAL_SC_SUFFIX "%x",
  104. conn->lc_path, conn->lc_instance_id);
  105. }
  106. path[LOCAL_FULLPATH_LEN - 1] = '\0';
  107. }
  108. #endif /* CONFIG_NET_LOCAL_STREAM */
  109. /****************************************************************************
  110. * Name: local_hd_name
  111. *
  112. * Description:
  113. * Create the name of the half duplex, datagram FIFO.
  114. *
  115. ****************************************************************************/
  116. #ifdef CONFIG_NET_LOCAL_DGRAM
  117. static inline void local_hd_name(FAR const char *inpath, FAR char *outpath)
  118. {
  119. snprintf(outpath, LOCAL_FULLPATH_LEN - 1, "%s" LOCAL_HD_SUFFIX,
  120. inpath);
  121. outpath[LOCAL_FULLPATH_LEN - 1] = '\0';
  122. }
  123. #endif /* CONFIG_NET_LOCAL_DGRAM */
  124. /****************************************************************************
  125. * Name: local_fifo_exists
  126. *
  127. * Description:
  128. * Check if a FIFO exists.
  129. *
  130. ****************************************************************************/
  131. static bool local_fifo_exists(FAR const char *path)
  132. {
  133. struct stat buf;
  134. int ret;
  135. /* Create the client-to-server FIFO */
  136. ret = stat(path, &buf);
  137. if (ret < 0)
  138. {
  139. return false;
  140. }
  141. /* FIFOs are character devices in NuttX. Return true if what we found
  142. * is a FIFO. What if it is something else? In that case, we will
  143. * return false and mkfifo() will fail.
  144. */
  145. return (bool)S_ISCHR(buf.st_mode);
  146. }
  147. /****************************************************************************
  148. * Name: local_create_fifo
  149. *
  150. * Description:
  151. * Create the one FIFO.
  152. *
  153. ****************************************************************************/
  154. static int local_create_fifo(FAR const char *path)
  155. {
  156. int ret;
  157. /* Create the client-to-server FIFO if it does not already exist. */
  158. if (!local_fifo_exists(path))
  159. {
  160. ret = mkfifo(path, 0644);
  161. if (ret < 0)
  162. {
  163. int errcode = get_errno();
  164. DEBUGASSERT(errcode > 0);
  165. nerr("ERROR: Failed to create FIFO %s: %d\n", path, errcode);
  166. return -errcode;
  167. }
  168. }
  169. /* The FIFO (or some character driver) exists at PATH or we successfully
  170. * created the FIFO at that location.
  171. */
  172. return OK;
  173. }
  174. /****************************************************************************
  175. * Name: local_release_fifo
  176. *
  177. * Description:
  178. * Release a reference from one of the FIFOs used in a connection.
  179. *
  180. ****************************************************************************/
  181. #ifdef CONFIG_NET_LOCAL_STREAM /* Currently not used by datagram code */
  182. static int local_release_fifo(FAR const char *path)
  183. {
  184. int ret;
  185. /* Unlink the client-to-server FIFO if it exists. */
  186. if (local_fifo_exists(path))
  187. {
  188. /* Un-linking the FIFO removes the FIFO from the namespace. It will
  189. * also mark the FIFO device "unlinked". When all of the open
  190. * references to the FIFO device are closed, the resources consumed
  191. * by the device instance will also be freed.
  192. */
  193. ret = unlink(path);
  194. if (ret < 0)
  195. {
  196. int errcode = get_errno();
  197. DEBUGASSERT(errcode > 0);
  198. nerr("ERROR: Failed to unlink FIFO %s: %d\n", path, errcode);
  199. return -errcode;
  200. }
  201. }
  202. /* The FIFO does not exist or we successfully unlinked it. */
  203. return OK;
  204. }
  205. #endif
  206. /****************************************************************************
  207. * Name: local_rx_open
  208. *
  209. * Description:
  210. * Open a FIFO for read-only access.
  211. *
  212. ****************************************************************************/
  213. static int local_rx_open(FAR struct local_conn_s *conn, FAR const char *path,
  214. bool nonblock)
  215. {
  216. int oflags = nonblock ? O_RDONLY | O_NONBLOCK : O_RDONLY;
  217. int ret;
  218. ret = file_open(&conn->lc_infile, path, oflags);
  219. if (ret < 0)
  220. {
  221. nerr("ERROR: Failed on open %s for reading: %d\n",
  222. path, ret);
  223. /* Map the error code to something consistent with the return
  224. * error codes from connect():
  225. *
  226. * If error is ENOENT, meaning that the FIFO does exist,
  227. * return EFAULT meaning that the socket structure address is
  228. * outside the user's address space.
  229. */
  230. return ret == -ENOENT ? -EFAULT : ret;
  231. }
  232. return OK;
  233. }
  234. /****************************************************************************
  235. * Name: local_tx_open
  236. *
  237. * Description:
  238. * Open a FIFO for write-only access.
  239. *
  240. ****************************************************************************/
  241. static int local_tx_open(FAR struct local_conn_s *conn, FAR const char *path,
  242. bool nonblock)
  243. {
  244. int oflags = nonblock ? O_WRONLY | O_NONBLOCK : O_WRONLY;
  245. int ret;
  246. ret = file_open(&conn->lc_outfile, path, oflags);
  247. if (ret < 0)
  248. {
  249. nerr("ERROR: Failed on open %s for writing: %d\n",
  250. path, ret);
  251. /* Map the error code to something consistent with the return
  252. * error codes from connect():
  253. *
  254. * If error is ENOENT, meaning that the FIFO does exist,
  255. * return EFAULT meaning that the socket structure address is
  256. * outside the user's address space.
  257. */
  258. return ret == -ENOENT ? -EFAULT : ret;
  259. }
  260. return OK;
  261. }
  262. /****************************************************************************
  263. * Name: local_set_policy
  264. *
  265. * Description:
  266. * Set the FIFO buffer policy:
  267. *
  268. * 0=Free FIFO resources when the last reference is closed
  269. * 1=Free FIFO resources when the buffer is empty.
  270. *
  271. ****************************************************************************/
  272. static int local_set_policy(FAR struct file *filep, unsigned long policy)
  273. {
  274. int ret;
  275. /* Set the buffer policy */
  276. ret = file_ioctl(filep, PIPEIOC_POLICY, policy);
  277. if (ret < 0)
  278. {
  279. nerr("ERROR: Failed to set FIFO buffer policy: %d\n", ret);
  280. }
  281. return ret;
  282. }
  283. /****************************************************************************
  284. * Public Functions
  285. ****************************************************************************/
  286. /****************************************************************************
  287. * Name: local_create_fifos
  288. *
  289. * Description:
  290. * Create the FIFO pair needed for a SOCK_STREAM connection.
  291. *
  292. ****************************************************************************/
  293. #ifdef CONFIG_NET_LOCAL_STREAM
  294. int local_create_fifos(FAR struct local_conn_s *conn)
  295. {
  296. char path[LOCAL_FULLPATH_LEN];
  297. int ret;
  298. /* Create the client-to-server FIFO if it does not already exist. */
  299. local_cs_name(conn, path);
  300. ret = local_create_fifo(path);
  301. if (ret >= 0)
  302. {
  303. /* Create the server-to-client FIFO if it does not already exist. */
  304. local_sc_name(conn, path);
  305. ret = local_create_fifo(path);
  306. }
  307. return ret;
  308. }
  309. #endif /* CONFIG_NET_LOCAL_STREAM */
  310. /****************************************************************************
  311. * Name: local_create_halfduplex
  312. *
  313. * Description:
  314. * Create the half-duplex FIFO needed for SOCK_DGRAM communication.
  315. *
  316. ****************************************************************************/
  317. #ifdef CONFIG_NET_LOCAL_DGRAM
  318. int local_create_halfduplex(FAR struct local_conn_s *conn, FAR const char *path)
  319. {
  320. char fullpath[LOCAL_FULLPATH_LEN];
  321. /* Create the half duplex FIFO if it does not already exist. */
  322. local_hd_name(path, fullpath);
  323. return local_create_fifo(fullpath);
  324. }
  325. #endif /* CONFIG_NET_LOCAL_DGRAM */
  326. /****************************************************************************
  327. * Name: local_release_fifos
  328. *
  329. * Description:
  330. * Release references to the FIFO pair used for a SOCK_STREAM connection.
  331. *
  332. ****************************************************************************/
  333. #ifdef CONFIG_NET_LOCAL_STREAM
  334. int local_release_fifos(FAR struct local_conn_s *conn)
  335. {
  336. char path[LOCAL_FULLPATH_LEN];
  337. int ret1;
  338. int ret2;
  339. /* Destroy the client-to-server FIFO if it exists. */
  340. local_sc_name(conn, path);
  341. ret1 = local_release_fifo(path);
  342. /* Destroy the server-to-client FIFO if it exists. */
  343. local_cs_name(conn, path);
  344. ret2 = local_release_fifo(path);
  345. /* Return a failure if one occurred. */
  346. return ret1 < 0 ? ret1 : ret2;
  347. }
  348. #endif /* CONFIG_NET_LOCAL_STREAM */
  349. /****************************************************************************
  350. * Name: local_release_halfduplex
  351. *
  352. * Description:
  353. * Release a reference to the FIFO used for SOCK_DGRAM communication
  354. *
  355. ****************************************************************************/
  356. #ifdef CONFIG_NET_LOCAL_DGRAM
  357. int local_release_halfduplex(FAR struct local_conn_s *conn)
  358. {
  359. #if 1
  360. /* REVIST: We need to think about this carefully. Unlike the connection-
  361. * oriented Unix domain socket, we don't really know the best time to
  362. * release the FIFO resource. It would be extremely inefficient to create
  363. * and destroy the FIFO on each packet. But, on the other hand, failing
  364. * to destroy the FIFO will leave the FIFO resources in place after the
  365. * communications have completed.
  366. *
  367. * I am thinking that there should be something like a timer. The timer
  368. * would be started at the completion of each transfer and cancelled at
  369. * the beginning of each transfer. If the timer expires, then the FIFO
  370. * would be destroyed.
  371. */
  372. # warning Missing logic
  373. return OK;
  374. #else
  375. char path[LOCAL_FULLPATH_LEN];
  376. /* Destroy the half duplex FIFO if it exists. */
  377. local_hd_name(conn->lc_path, path);
  378. return local_release_fifo(path);
  379. #endif
  380. }
  381. #endif /* CONFIG_NET_LOCAL_DGRAM */
  382. /****************************************************************************
  383. * Name: local_open_client_rx
  384. *
  385. * Description:
  386. * Open the client-side of the server-to-client FIFO.
  387. *
  388. ****************************************************************************/
  389. #ifdef CONFIG_NET_LOCAL_STREAM
  390. int local_open_client_rx(FAR struct local_conn_s *client, bool nonblock)
  391. {
  392. char path[LOCAL_FULLPATH_LEN];
  393. int ret;
  394. /* Get the server-to-client path name */
  395. local_sc_name(client, path);
  396. /* Then open the file for read-only access */
  397. ret = local_rx_open(client, path, nonblock);
  398. if (ret == OK)
  399. {
  400. /* Policy: Free FIFO resources when the last reference is closed */
  401. ret = local_set_policy(&client->lc_infile, 0);
  402. }
  403. return ret;
  404. }
  405. #endif /* CONFIG_NET_LOCAL_STREAM */
  406. /****************************************************************************
  407. * Name: local_open_client_tx
  408. *
  409. * Description:
  410. * Open the client-side of the client-to-server FIFO.
  411. *
  412. ****************************************************************************/
  413. #ifdef CONFIG_NET_LOCAL_STREAM
  414. int local_open_client_tx(FAR struct local_conn_s *client, bool nonblock)
  415. {
  416. char path[LOCAL_FULLPATH_LEN];
  417. int ret;
  418. /* Get the client-to-server path name */
  419. local_cs_name(client, path);
  420. /* Then open the file for write-only access */
  421. ret = local_tx_open(client, path, nonblock);
  422. if (ret == OK)
  423. {
  424. /* Policy: Free FIFO resources when the last reference is closed */
  425. ret = local_set_policy(&client->lc_outfile, 0);
  426. }
  427. return ret;
  428. }
  429. #endif /* CONFIG_NET_LOCAL_STREAM */
  430. /****************************************************************************
  431. * Name: local_open_server_rx
  432. *
  433. * Description:
  434. * Open the server-side of the client-to-server FIFO.
  435. *
  436. ****************************************************************************/
  437. #ifdef CONFIG_NET_LOCAL_STREAM
  438. int local_open_server_rx(FAR struct local_conn_s *server, bool nonblock)
  439. {
  440. char path[LOCAL_FULLPATH_LEN];
  441. int ret;
  442. /* Get the client-to-server path name */
  443. local_cs_name(server, path);
  444. /* Then open the file for write-only access */
  445. ret = local_rx_open(server, path, nonblock);
  446. if (ret == OK)
  447. {
  448. /* Policy: Free FIFO resources when the last reference is closed */
  449. ret = local_set_policy(&server->lc_infile, 0);
  450. }
  451. return ret;
  452. }
  453. #endif /* CONFIG_NET_LOCAL_STREAM */
  454. /****************************************************************************
  455. * Name: local_open_server_tx
  456. *
  457. * Description:
  458. * Only the server-side of the server-to-client FIFO.
  459. *
  460. ****************************************************************************/
  461. #ifdef CONFIG_NET_LOCAL_STREAM
  462. int local_open_server_tx(FAR struct local_conn_s *server, bool nonblock)
  463. {
  464. char path[LOCAL_FULLPATH_LEN];
  465. int ret;
  466. /* Get the server-to-client path name */
  467. local_sc_name(server, path);
  468. /* Then open the file for read-only access */
  469. ret = local_tx_open(server, path, nonblock);
  470. if (ret == OK)
  471. {
  472. /* Policy: Free FIFO resources when the last reference is closed */
  473. ret = local_set_policy(&server->lc_outfile, 0);
  474. }
  475. return ret;
  476. }
  477. #endif /* CONFIG_NET_LOCAL_STREAM */
  478. /****************************************************************************
  479. * Name: local_open_receiver
  480. *
  481. * Description:
  482. * Only the receiving side of the half duplex FIFO.
  483. *
  484. ****************************************************************************/
  485. #ifdef CONFIG_NET_LOCAL_DGRAM
  486. int local_open_receiver(FAR struct local_conn_s *conn, bool nonblock)
  487. {
  488. char path[LOCAL_FULLPATH_LEN];
  489. int ret;
  490. /* Get the server-to-client path name */
  491. local_hd_name(conn->lc_path, path);
  492. /* Then open the file for read-only access */
  493. ret = local_rx_open(conn, path, nonblock);
  494. if (ret == OK)
  495. {
  496. /* Policy: Free FIFO resources when the buffer is empty. */
  497. ret = local_set_policy(&conn->lc_infile, 1);
  498. }
  499. return ret;
  500. }
  501. #endif /* CONFIG_NET_LOCAL_DGRAM */
  502. /****************************************************************************
  503. * Name: local_open_sender
  504. *
  505. * Description:
  506. * Only the sending side of the half duplex FIFO.
  507. *
  508. ****************************************************************************/
  509. #ifdef CONFIG_NET_LOCAL_DGRAM
  510. int local_open_sender(FAR struct local_conn_s *conn, FAR const char *path,
  511. bool nonblock)
  512. {
  513. char fullpath[LOCAL_FULLPATH_LEN];
  514. int ret;
  515. /* Get the server-to-client path name */
  516. local_hd_name(path, fullpath);
  517. /* Then open the file for read-only access */
  518. ret = local_tx_open(conn, fullpath, nonblock);
  519. if (ret == OK)
  520. {
  521. /* Policy: Free FIFO resources when the buffer is empty. */
  522. ret = local_set_policy(&conn->lc_outfile, 1);
  523. }
  524. return ret;
  525. }
  526. #endif /* CONFIG_NET_LOCAL_DGRAM */
  527. #endif /* CONFIG_NET && CONFIG_NET_LOCAL */