net_sockets.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839
  1. /*
  2. * Copyright (c) 2006-2024 RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2015-02-17 Bernard First version
  9. * 2018-05-17 ChenYong Add socket abstraction layer
  10. */
  11. #include <dfs.h>
  12. #include <dfs_file.h>
  13. #include <poll.h>
  14. #include <dfs_net.h>
  15. #include <sys/errno.h>
  16. #include <sys/socket.h>
  17. /**
  18. * @brief Accepts an incoming connection on a listening socket.
  19. *
  20. * This function extracts the first connection request from the queue of pending connections for
  21. * the listening socket specified by 's' and creates a new socket for the connection.
  22. *
  23. * @param s The file descriptor of the listening socket. This socket must be created with
  24. * 'socket()', bound with 'bind()', and set to listen with 'listen()'.
  25. * @param addr A pointer to a 'sockaddr' structure that will receive the address of the connecting entity.
  26. * This structure is filled with the address of the client once the connection is accepted.
  27. * Can be 'NULL' if the address is not needed.
  28. * @param addrlen A pointer to a variable containing the size of 'addr'. When the function returns, this
  29. * variable will hold the actual size of the address returned. Can be 'NULL' if 'addr' is 'NULL'.
  30. *
  31. * @return On success, returns a new file descriptor for the accepted connection. On failure, returns '-1'
  32. * and sets errno to indicate the error.
  33. *
  34. * @note The original socket 's' remains open and continues to listen for additional incoming connections.
  35. * The returned file descriptor is used for communication with the connected client.
  36. *
  37. * @see socket() Creates a socket for accepting connections.
  38. * @see bind() Binds the socket to a local address.
  39. * @see listen() Sets the socket to listen for incoming connections.
  40. * @see close()/closesocket() Closes a socket when it is no longer needed.
  41. */
  42. int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
  43. {
  44. int new_socket = -1;
  45. int socket = dfs_net_getsocket(s);
  46. new_socket = sal_accept(socket, addr, addrlen);
  47. if (new_socket != -1)
  48. {
  49. /* this is a new socket, create it in file system fd */
  50. int fd;
  51. struct dfs_file *d;
  52. /* allocate a fd */
  53. fd = fd_new();
  54. if (fd < 0)
  55. {
  56. rt_set_errno(-ENOMEM);
  57. sal_closesocket(new_socket);
  58. return -1;
  59. }
  60. d = fd_get(fd);
  61. if(d)
  62. {
  63. #ifdef RT_USING_DFS_V2
  64. d->fops = dfs_net_get_fops();
  65. #endif
  66. /* this is a socket fd */
  67. d->vnode = (struct dfs_vnode *)rt_malloc(sizeof(struct dfs_vnode));
  68. if (!d->vnode)
  69. {
  70. /* release fd */
  71. fd_release(fd);
  72. rt_set_errno(-ENOMEM);
  73. return -1;
  74. }
  75. dfs_vnode_init(d->vnode, FT_SOCKET, dfs_net_get_fops());
  76. d->flags = O_RDWR; /* set flags as read and write */
  77. /* set socket to the data of dfs_file */
  78. d->vnode->data = (void *)(size_t)new_socket;
  79. return fd;
  80. }
  81. rt_set_errno(-ENOMEM);
  82. sal_closesocket(new_socket);
  83. return -1;
  84. }
  85. return -1;
  86. }
  87. RTM_EXPORT(accept);
  88. /**
  89. * @brief Binds a socket to a specific local address and port.
  90. *
  91. * This function assigns a local address to a socket, defined by the 'name' parameter.
  92. * The address allows the socket to receive data sent to this address.
  93. *
  94. * @param s The file descriptor of the socket to bind.
  95. * @param name A pointer to a 'sockaddr' structure that specifies the address to bind to.
  96. * The structure varies based on the address family, such as 'sockaddr_in' for IPv4.
  97. * @param namelen The length of the 'sockaddr' structure pointed to by 'name', in bytes.
  98. *
  99. * @return Returns '0' on success. On failure, returns '-1' and sets errno to indicate the error.
  100. *
  101. * @note The socket must be created with 'socket()' before calling 'bind()'.
  102. * Binding is typically used for server sockets, specifying the local IP and port to listen on.
  103. * If the port is set to '0', the system assigns an available port automatically.
  104. *
  105. * @see socket() Creates a socket for binding.
  106. * @see listen() Prepares the socket to listen for incoming connections after binding.
  107. * @see accept() Accepts connections on a bound and listening socket.
  108. */
  109. int bind(int s, const struct sockaddr *name, socklen_t namelen)
  110. {
  111. int socket = dfs_net_getsocket(s);
  112. return sal_bind(socket, name, namelen);
  113. }
  114. RTM_EXPORT(bind);
  115. /**
  116. * @brief Shuts down part of a full-duplex connection on a socket.
  117. *
  118. * This function disables further sends or receives on the specified socket, depending on the value
  119. * of the 'how' parameter. It does not close the socket, which must still be closed separately using
  120. * 'close()' or 'closesocket()'.
  121. *
  122. * @param s The file descriptor of the socket to shut down.
  123. * @param how Specifies the type of shutdown to perform. The 'how' parameter can be one of the following:
  124. * - 'SHUT_RD': Disables further reading on the socket. The socket will not receive data.
  125. * - 'SHUT_WR': Disables further writing on the socket. The socket will not send data.
  126. * - 'SHUT_RDWR': Disables both reading and writing on the socket. The socket will be fully shut down.
  127. *
  128. * @return Returns '0' on success. On failure, returns '-1' and sets errno to indicate the error.
  129. *
  130. * @note The 'shutdown()' function is used to gracefully close a socket in one or both directions
  131. * (read/write). It is commonly used in scenarios like closing the write side of a TCP connection
  132. * when a server has finished sending data but still expects to receive data.
  133. *
  134. * @see socket() Creates the socket used for communication.
  135. * @see close()/closesocket() Closes the socket after the shutdown is complete.
  136. * @see recv() Receives data on a socket.
  137. * @see send() Sends data on a socket.
  138. */
  139. int shutdown(int s, int how)
  140. {
  141. int error = 0;
  142. int socket = -1;
  143. struct dfs_file *d;
  144. socket = dfs_net_getsocket(s);
  145. if (socket < 0)
  146. {
  147. rt_set_errno(-ENOTSOCK);
  148. return -1;
  149. }
  150. d = fd_get(s);
  151. if (d == NULL)
  152. {
  153. rt_set_errno(-EBADF);
  154. return -1;
  155. }
  156. if (sal_shutdown(socket, how) == 0)
  157. {
  158. error = 0;
  159. }
  160. else
  161. {
  162. rt_set_errno(-ENOTSOCK);
  163. error = -1;
  164. }
  165. return error;
  166. }
  167. RTM_EXPORT(shutdown);
  168. /**
  169. * @brief Retrieves the address of the peer connected to a socket.
  170. *
  171. * This function obtains the address of the peer (remote end) connected to the socket 's'.
  172. * It is typically used on connected sockets (e.g., TCP) to retrieve information about the peer.
  173. *
  174. * @param s The file descriptor of the connected socket.
  175. * @param name A pointer to a 'sockaddr' structure that will be filled with the address of the peer.
  176. * The structure type (e.g., 'sockaddr_in' for IPv4) depends on the address family of the socket.
  177. * @param namelen A pointer to a variable that initially specifies the size of the 'name' structure.
  178. * On return, it contains the actual size of the address returned.
  179. *
  180. * @return Returns '0' on success. On failure, returns '-1' and sets errno to indicate the error.
  181. *
  182. * @note The 'getpeername()' function is useful for retrieving information about the remote end of a connection,
  183. * such as the IP address and port of a peer in a TCP connection. This function is only valid for sockets
  184. * that are in a connected state.
  185. *
  186. * @see socket() Creates the socket used for the connection.
  187. * @see connect() Connects the socket to a remote address.
  188. * @see getsockname() Retrieves the local address of a socket.
  189. */
  190. int getpeername(int s, struct sockaddr *name, socklen_t *namelen)
  191. {
  192. int socket = dfs_net_getsocket(s);
  193. return sal_getpeername(socket, name, namelen);
  194. }
  195. RTM_EXPORT(getpeername);
  196. /**
  197. * @brief Retrieves the local address of a socket.
  198. *
  199. * This function obtains the local address (IP address and port) associated with the socket 's'.
  200. * It is typically used to determine the local address and port of a bound or connected socket.
  201. *
  202. * @param s The file descriptor of the socket.
  203. * @param name A pointer to a 'sockaddr' structure that will be filled with the local address
  204. * of the socket. The structure type (e.g., 'sockaddr_in' for IPv4) depends on the
  205. * address family of the socket.
  206. * @param namelen A pointer to a variable that initially specifies the size of the 'name' structure.
  207. * Upon return, this variable contains the actual size of the address returned.
  208. *
  209. * @return Returns '0' on success. On failure, returns '-1' and sets errno to indicate the error.
  210. *
  211. * @note The 'getsockname()' function is useful for retrieving the local address information of a socket,
  212. * which can be especially useful in cases where the socket was bound with an ephemeral port (port 0),
  213. * allowing you to discover the actual port number assigned by the system.
  214. *
  215. * @see socket() Creates the socket for communication.
  216. * @see bind() Binds the socket to a specific local address.
  217. * @see getpeername() Retrieves the address of the peer connected to a socket.
  218. */
  219. int getsockname(int s, struct sockaddr *name, socklen_t *namelen)
  220. {
  221. int socket = dfs_net_getsocket(s);
  222. return sal_getsockname(socket, name, namelen);
  223. }
  224. RTM_EXPORT(getsockname);
  225. /**
  226. * @brief Retrieves options for a socket.
  227. *
  228. * This function retrieves the current value for a specified option on a socket, identified
  229. * by the file descriptor 's'. The option is specified by the 'level' and 'optname' parameters.
  230. *
  231. * @param s The file descriptor of the socket from which to retrieve the option.
  232. * @param level The protocol level at which the option resides. Common levels include:
  233. * - 'SOL_SOCKET': To retrieve socket-level options.
  234. * - 'IPPROTO_IP': To retrieve IPv4 options.
  235. * - 'IPPROTO_TCP': To retrieve TCP options.
  236. * @param optname The name of the option to retrieve. Some common options include:
  237. * - 'SO_REUSEADDR': Checks if address reuse is enabled.
  238. * - 'SO_RCVBUF': Retrieves the receive buffer size.
  239. * - 'TCP_NODELAY': Checks if Nagle's algorithm is disabled for TCP sockets.
  240. * @param optval A pointer to a buffer where the value of the option will be stored.
  241. * The buffer must be large enough to hold the option value.
  242. * @param optlen A pointer to a variable that initially specifies the size of 'optval'.
  243. * On return, it contains the actual size of the option value returned.
  244. *
  245. * @return Returns '0' on success. On failure, returns '-1' and sets errno to indicate the error.
  246. *
  247. * @note The 'getsockopt()' function is useful for inspecting socket configuration and current settings.
  248. * It can provide information about options such as buffer sizes, timeouts, and protocol-specific features.
  249. *
  250. * @see socket() Creates the socket to retrieve options from.
  251. * @see setsockopt() Sets options for the socket.
  252. */
  253. int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
  254. {
  255. int socket = dfs_net_getsocket(s);
  256. return sal_getsockopt(socket, level, optname, optval, optlen);
  257. }
  258. RTM_EXPORT(getsockopt);
  259. /**
  260. * @brief Sets options on a socket.
  261. *
  262. * This function sets the specified option for the socket referenced by the file descriptor 's'.
  263. * Socket options affect the behavior of the socket and are specified by the 'level' and 'optname' parameters.
  264. *
  265. * @param s The file descriptor of the socket on which to set the option.
  266. * @param level The protocol level at which the option resides. Common levels include:
  267. * - 'SOL_SOCKET': To configure socket-level options.
  268. * - 'IPPROTO_IP': To configure IPv4 options.
  269. * - 'IPPROTO_TCP': To configure TCP options.
  270. * @param optname The name of the option to set. Some common options include:
  271. * - 'SO_REUSEADDR': Allows reuse of local addresses.
  272. * - 'SO_RCVBUF': Sets the receive buffer size.
  273. * - 'TCP_NODELAY': Disables Nagle's algorithm for TCP sockets.
  274. * @param optval A pointer to the buffer containing the value to set for the specified option.
  275. * The type of data in this buffer depends on the option being set.
  276. * @param optlen The size, in bytes, of the option value pointed to by 'optval'.
  277. *
  278. * @return Returns '0' on success. On failure, returns '-1' and sets errno to indicate the error.
  279. *
  280. * @note The 'setsockopt()' function is useful for configuring various socket behaviors, such as
  281. * setting timeouts, buffer sizes, and enabling or disabling certain protocol features.
  282. * The changes may affect socket performance and resource usage.
  283. *
  284. * @see socket() Creates the socket to configure.
  285. * @see getsockopt() Retrieves options set on the socket.
  286. * @see bind() Binds the socket to a local address.
  287. */
  288. int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
  289. {
  290. int socket = dfs_net_getsocket(s);
  291. return sal_setsockopt(socket, level, optname, optval, optlen);
  292. }
  293. RTM_EXPORT(setsockopt);
  294. /**
  295. * @brief Initiates a connection on a socket.
  296. *
  297. * This function connects the socket specified by 's' to the server address specified by 'name'.
  298. * The socket must have been created with 'socket()' and, for some types of sockets, may need
  299. * to be bound to a local address with 'bind()' before calling 'connect()'.
  300. *
  301. * @param s The file descriptor of the socket to connect.
  302. * @param name A pointer to a 'sockaddr' structure that specifies the address of the server to connect to.
  303. * The specific structure (e.g., 'sockaddr_in' for IPv4) depends on the address family.
  304. * @param namelen The length, in bytes, of the address structure pointed to by 'name'.
  305. *
  306. * @return Returns '0' on success. On failure, returns '-1' and sets errno to indicate the error.
  307. *
  308. * @note 'connect()' is typically used by client sockets to establish a connection with a server.
  309. * For connection-oriented protocols (e.g., TCP), this initiates the connection handshake.
  310. * For connectionless protocols (e.g., UDP), it defines a fixed peer address.
  311. *
  312. * @see socket() Creates the socket to be connected.
  313. * @see bind() Binds the socket to a local address (optional for client sockets).
  314. * @see accept() Used by server sockets to accept incoming connections.
  315. * @see close()/closesocket() Closes the socket when done.
  316. */
  317. int connect(int s, const struct sockaddr *name, socklen_t namelen)
  318. {
  319. int socket = dfs_net_getsocket(s);
  320. return sal_connect(socket, name, namelen);
  321. }
  322. RTM_EXPORT(connect);
  323. /**
  324. * @brief Marks a socket as a passive socket, ready to accept incoming connections.
  325. *
  326. * This function prepares a socket to accept incoming connection requests. The socket
  327. * must first be created with 'socket()' and bound to a local address with 'bind()'.
  328. *
  329. * @param s The file descriptor of the socket to set to listening mode.
  330. * @param backlog The maximum number of pending connections that can be queued for acceptance.
  331. * If more incoming connections arrive than the backlog limit, they may be rejected
  332. * or ignored until the server accepts some of the pending connections.
  333. *
  334. * @return Returns '0' on success. On failure, returns '-1' and sets errno to indicate the error.
  335. *
  336. * @note After calling 'listen()', the socket can be used with 'accept()' to handle connection requests.
  337. * The backlog size affects how many connections can wait to be accepted before being rejected.
  338. *
  339. * @see socket() Creates the socket.
  340. * @see bind() Binds the socket to a specific address.
  341. * @see accept() Accepts a pending connection request on the listening socket.
  342. */
  343. int listen(int s, int backlog)
  344. {
  345. int socket = dfs_net_getsocket(s);
  346. return sal_listen(socket, backlog);
  347. }
  348. RTM_EXPORT(listen);
  349. /**
  350. * @brief Receives data from a connected socket.
  351. *
  352. * This function reads data from a connected socket and stores it in the specified buffer.
  353. * It is typically used with connection-oriented protocols (e.g., TCP).
  354. *
  355. * @param s The file descriptor of the connected socket to receive data from.
  356. * @param mem A pointer to the buffer where the received data will be stored.
  357. * @param len The maximum number of bytes to read into the buffer.
  358. * @param flags Specifies the behavior of the receive operation. Common flags include:
  359. * - '0': Default operation.
  360. * - 'MSG_DONTWAIT': Non-blocking operation.
  361. * - 'MSG_PEEK': Peeks at the incoming data without removing it from the queue.
  362. *
  363. * @return Returns the number of bytes received on success. On failure, returns '-1' and sets errno to indicate the error.
  364. * A return value of '0' indicates that the connection has been closed by the remote peer.
  365. *
  366. * @note The 'recv()' function may not receive all the requested bytes in a single call.
  367. * Multiple calls to 'recv()' may be needed to read the complete data.
  368. *
  369. * @see socket() Creates the socket to be used for receiving data.
  370. * @see connect() Connects the socket to a remote address (for connection-oriented protocols).
  371. * @see recvfrom() Receives data from a specific address, typically used with connectionless sockets.
  372. * @see send() Sends data on a connected socket.
  373. */
  374. int recv(int s, void *mem, size_t len, int flags)
  375. {
  376. int socket = dfs_net_getsocket(s);
  377. return sal_recvfrom(socket, mem, len, flags, NULL, NULL);
  378. }
  379. RTM_EXPORT(recv);
  380. /**
  381. * @brief Sends a message on a socket.
  382. *
  383. * The 'sendmsg()' function sends data on the socket 's' using the structured data in the 'msghdr'
  384. * structure. This function is commonly used for sending complex messages with multiple buffers,
  385. * control information, or for working with datagram sockets.
  386. *
  387. * @param s The file descriptor of the socket to send the message on.
  388. * @param message A pointer to an 'msghdr' structure, which contains the data, address, and control information:
  389. * - 'msg_name': Optional destination address (used for connectionless sockets).
  390. * - 'msg_namelen': Size of the destination address.
  391. * - 'msg_iov': An array of 'iovec' structures that point to the data buffers to be sent.
  392. * - 'msg_iovlen': The number of elements in the 'msg_iov' array.
  393. * - 'msg_control': Optional ancillary data, such as file descriptors for UNIX domain sockets.
  394. * - 'msg_controllen': The size of the ancillary data buffer.
  395. * - 'msg_flags': Flags related to the message.
  396. * @param flags Specifies how the message should be sent. Common flags include:
  397. * - 'MSG_DONTWAIT': Sends the message in non-blocking mode.
  398. * - 'MSG_EOR': Indicates the end of a record (for record-oriented sockets).
  399. *
  400. * @return Returns the number of bytes sent on success. On failure, returns '-1' and sets errno to indicate the error.
  401. *
  402. * @note The 'sendmsg()' function is useful for sending messages with multiple buffers or ancillary data,
  403. * allowing flexible communication options such as attaching file descriptors. This function can be
  404. * used with both connection-oriented and connectionless sockets.
  405. *
  406. * @see recvmsg() Receives a message from a socket.
  407. * @see send() Sends data on a socket.
  408. * @see socket() Creates the socket to use with 'sendmsg()'.
  409. */
  410. int sendmsg(int s, const struct msghdr *message, int flags)
  411. {
  412. int socket = dfs_net_getsocket(s);
  413. return sal_sendmsg(socket, message, flags);
  414. }
  415. RTM_EXPORT(sendmsg);
  416. /**
  417. * @brief Receives a message from a socket.
  418. *
  419. * The 'recvmsg()' function receives data from the socket 's' into the buffers described by
  420. * the 'msghdr' structure. This function allows for complex data structures, including multiple
  421. * data buffers and optional control information.
  422. *
  423. * @param s The file descriptor of the socket to receive data from.
  424. * @param message A pointer to an 'msghdr' structure, which will be filled with the received data and
  425. * information. The structure contains:
  426. * - 'msg_name': A buffer for the source address (used for connectionless sockets).
  427. * - 'msg_namelen': Specifies the size of the 'msg_name' buffer.
  428. * - 'msg_iov': An array of 'iovec' structures that point to the buffers to store received data.
  429. * - 'msg_iovlen': The number of elements in the 'msg_iov' array.
  430. * - 'msg_control': A buffer for ancillary data, such as received file descriptors.
  431. * - 'msg_controllen': The size of the ancillary data buffer.
  432. * - 'msg_flags': Flags set by the 'recvmsg()' call to indicate the message status.
  433. * @param flags Specifies how the message should be received. Common flags include:
  434. * - 'MSG_DONTWAIT': Receives the message in non-blocking mode.
  435. * - 'MSG_PEEK': Peeks at the incoming message without removing it from the queue.
  436. * - 'MSG_WAITALL': Waits for the full amount of data to be received.
  437. *
  438. * @return Returns the number of bytes received on success. On failure, returns '-1' and sets errno to indicate the error.
  439. *
  440. * @note The 'recvmsg()' function is useful for receiving messages with multiple buffers or ancillary data.
  441. * It can be used with both connection-oriented and connectionless sockets, making it versatile for
  442. * different communication needs.
  443. *
  444. * @see sendmsg() Sends a message on a socket.
  445. * @see recv() Receives data on a socket.
  446. * @see socket() Creates the socket used with 'recvmsg()'.
  447. */
  448. int recvmsg(int s, struct msghdr *message, int flags)
  449. {
  450. int socket = dfs_net_getsocket(s);
  451. return sal_recvmsg(socket, message, flags);
  452. }
  453. RTM_EXPORT(recvmsg);
  454. /**
  455. * @brief Receives data from a specific address using an unconnected socket.
  456. *
  457. * This function reads data from a socket and stores it in the specified buffer. It is commonly used
  458. * with connectionless protocols (e.g., UDP) to receive data from a specific source address.
  459. *
  460. * @param s The file descriptor of the socket to receive data from.
  461. * @param mem A pointer to the buffer where the received data will be stored.
  462. * @param len The maximum number of bytes to read into the buffer.
  463. * @param flags Specifies the behavior of the receive operation. Common flags include:
  464. * - '0': Default operation.
  465. * - 'MSG_DONTWAIT': Non-blocking operation.
  466. * - 'MSG_PEEK': Peeks at the incoming data without removing it from the queue.
  467. * @param from A pointer to a 'sockaddr' structure that will be filled with the address of the
  468. * sending entity. This is the source address from which the data was received.
  469. * @param fromlen A pointer to a variable that initially contains the size of the 'from' structure.
  470. * Upon return, this variable will hold the actual size of the address returned.
  471. *
  472. * @return Returns the number of bytes received on success. On failure, returns '-1' and sets errno to indicate the error.
  473. * A return value of '0' indicates that the connection has been closed by the remote peer.
  474. *
  475. * @note The 'recvfrom()' function is useful for receiving data from an arbitrary source address,
  476. * which makes it especially suited for connectionless protocols where the peer's address may vary.
  477. * The 'from' parameter is filled with the sender's address, which can be useful for identifying
  478. * the origin of the data.
  479. *
  480. * @see socket() Creates the socket used for receiving data.
  481. * @see sendto() Sends data to a specific address, typically used with connectionless sockets.
  482. * @see recv() Receives data on a connected socket.
  483. */
  484. int recvfrom(int s, void *mem, size_t len, int flags,
  485. struct sockaddr *from, socklen_t *fromlen)
  486. {
  487. int socket = dfs_net_getsocket(s);
  488. return sal_recvfrom(socket, mem, len, flags, from, fromlen);
  489. }
  490. RTM_EXPORT(recvfrom);
  491. /**
  492. * @brief Sends data on a connected socket.
  493. *
  494. * This function sends data to a connected socket, specified by the file descriptor 's'.
  495. * It is typically used with connection-oriented protocols (e.g., TCP).
  496. *
  497. * @param s The file descriptor of the socket to send data on.
  498. * The socket must be connected to a remote peer.
  499. * @param dataptr A pointer to the buffer containing the data to send.
  500. * @param size The size, in bytes, of the data to be sent from the buffer.
  501. * @param flags Specifies the behavior of the send operation. Common flags include:
  502. * - '0': Default operation.
  503. * - 'MSG_DONTWAIT': Non-blocking operation.
  504. * - 'MSG_NOSIGNAL': Prevents the sending of 'SIGPIPE' on errors.
  505. *
  506. * @return Returns the number of bytes sent on success. On failure, returns '-1' and sets errno to indicate the error.
  507. * If the connection is closed by the remote peer, the return value may be '0'.
  508. *
  509. * @note The 'send()' function does not guarantee that all data will be sent in a single call.
  510. * If fewer bytes are sent than requested, the remaining data should be sent in subsequent calls.
  511. *
  512. * @see socket() Creates the socket to be used for sending data.
  513. * @see connect() Connects the socket to a remote address (for connection-oriented protocols).
  514. * @see sendto() Sends data to a specific address, typically used with connectionless sockets.
  515. * @see recv() Receives data from a connected socket.
  516. */
  517. int send(int s, const void *dataptr, size_t size, int flags)
  518. {
  519. int socket = dfs_net_getsocket(s);
  520. return sal_sendto(socket, dataptr, size, flags, NULL, 0);
  521. }
  522. RTM_EXPORT(send);
  523. /**
  524. * @brief Sends data to a specific address using an unconnected socket.
  525. *
  526. * This function is typically used with connectionless protocols (e.g., UDP) to send data
  527. * to a specific destination address, as specified by 'to'.
  528. *
  529. * @param s The file descriptor of the socket to send data on.
  530. * @param dataptr A pointer to the buffer containing the data to be sent.
  531. * @param size The size, in bytes, of the data to be sent from the buffer.
  532. * @param flags Specifies the behavior of the send operation. Common flags include:
  533. * - '0': Default operation.
  534. * - 'MSG_DONTWAIT': Non-blocking operation.
  535. * - 'MSG_NOSIGNAL': Prevents the sending of 'SIGPIPE' on errors.
  536. * @param to A pointer to a 'sockaddr' structure that specifies the destination address.
  537. * The structure type (e.g., 'sockaddr_in' for IPv4) depends on the address family.
  538. * @param tolen The length, in bytes, of the address structure pointed to by 'to'.
  539. *
  540. * @return Returns the number of bytes sent on success. On failure, returns '-1' and sets errno to indicate the error.
  541. *
  542. * @note Unlike 'send()', 'sendto()' can specify a target address for each message, allowing it to be used
  543. * for both connected and unconnected sockets. In connectionless protocols, 'sendto()' is commonly
  544. * used without prior calls to 'connect()'.
  545. *
  546. * @see socket() Creates the socket used for sending data.
  547. * @see recvfrom() Receives data from a specific address, typically used with connectionless sockets.
  548. * @see connect() Optional for connection-oriented protocols.
  549. * @see send() Sends data on a connected socket.
  550. */
  551. int sendto(int s, const void *dataptr, size_t size, int flags,
  552. const struct sockaddr *to, socklen_t tolen)
  553. {
  554. int socket = dfs_net_getsocket(s);
  555. return sal_sendto(socket, dataptr, size, flags, to, tolen);
  556. }
  557. RTM_EXPORT(sendto);
  558. /**
  559. * @brief Creates a network socket.
  560. *
  561. * This function creates a socket and returns a file descriptor that can be used for network communication.
  562. *
  563. * @param domain The communication protocol family (address family) that defines the socket's protocol.
  564. * Common values include:
  565. * - 'AF_INET': IPv4
  566. * - 'AF_INET6': IPv6
  567. * - 'AF_UNIX': Local communication (inter-process communication on the same machine)
  568. * - 'AF_AT': AT socket
  569. * - 'AF_WIZ': WIZnet
  570. * @param type The type of socket, which determines the characteristics of data transmission.
  571. * Common values include:
  572. * - 'SOCK_STREAM': Connection-oriented byte stream communication (e.g., TCP)
  573. * - 'SOCK_DGRAM': Connectionless datagram communication (e.g., UDP)
  574. * - 'SOCK_RAW': Provides raw network protocol access
  575. * @param protocol Specifies the protocol to be used with the socket. It is usually set to '0',
  576. * which allows the system to choose the default protocol:
  577. * - For 'SOCK_STREAM', the default is TCP.
  578. * - For 'SOCK_DGRAM', the default is UDP.
  579. *
  580. * @return On success, returns a file descriptor (a non-negative integer) representing the socket.
  581. * On failure, returns '-1' and sets errno to indicate the error.
  582. *
  583. * @note The created socket can be used for binding, listening, receiving, and sending data.
  584. *
  585. * @see bind() Used to bind the socket to a local address.
  586. * @see listen() Used to set the socket to listen for incoming connections.
  587. * @see accept() Used to accept incoming connection requests.
  588. * @see connect() Used to connect to a remote host.
  589. */
  590. int socket(int domain, int type, int protocol)
  591. {
  592. /* create a BSD socket */
  593. int fd;
  594. int socket;
  595. struct dfs_file *d;
  596. /* allocate a fd */
  597. fd = fd_new();
  598. if (fd < 0)
  599. {
  600. rt_set_errno(-ENOMEM);
  601. return -1;
  602. }
  603. d = fd_get(fd);
  604. #ifdef RT_USING_DFS_V2
  605. d->fops = dfs_net_get_fops();
  606. #endif
  607. d->vnode = (struct dfs_vnode *)rt_malloc(sizeof(struct dfs_vnode));
  608. if (!d->vnode)
  609. {
  610. /* release fd */
  611. fd_release(fd);
  612. rt_set_errno(-ENOMEM);
  613. return -1;
  614. }
  615. /* create socket and then put it to the dfs_file */
  616. socket = sal_socket(domain, type, protocol);
  617. if (socket >= 0)
  618. {
  619. dfs_vnode_init(d->vnode, FT_SOCKET, dfs_net_get_fops());
  620. d->flags = O_RDWR; /* set flags as read and write */
  621. /* set socket to the data of dfs_file */
  622. d->vnode->data = (void *)(size_t)socket;
  623. }
  624. else
  625. {
  626. /* release fd */
  627. fd_release(fd);
  628. rt_set_errno(-ENOMEM);
  629. return -1;
  630. }
  631. return fd;
  632. }
  633. RTM_EXPORT(socket);
  634. /**
  635. * @brief Closes a socket.
  636. *
  637. * This function closes the socket specified by the file descriptor 's'. Once closed, the socket
  638. * can no longer be used for communication. Any pending data that has not been transmitted may be lost.
  639. *
  640. * @param s The file descriptor of the socket to close.
  641. *
  642. * @return Returns '0' on success. On failure, returns '-1' and sets errno to indicate the error.
  643. *
  644. * @note After calling 'closesocket()', the socket descriptor becomes invalid. The socket cannot
  645. * be used for further communication or operations. It is important to close sockets when they are no longer needed
  646. * to release system resources.
  647. *
  648. * @see socket() Creates a socket.
  649. * @see shutdown() Shuts down the socket for reading and/or writing, without closing it.
  650. * @see recv() Receives data from a socket.
  651. * @see send() Sends data on a socket.
  652. */
  653. int closesocket(int s)
  654. {
  655. int error = 0;
  656. int socket = -1;
  657. struct dfs_file *d;
  658. socket = dfs_net_getsocket(s);
  659. if (socket < 0)
  660. {
  661. rt_set_errno(-ENOTSOCK);
  662. return -1;
  663. }
  664. d = fd_get(s);
  665. if (d == RT_NULL)
  666. {
  667. rt_set_errno(-EBADF);
  668. return -1;
  669. }
  670. if (!d->vnode)
  671. {
  672. rt_set_errno(-EBADF);
  673. return -1;
  674. }
  675. if (sal_closesocket(socket) == 0)
  676. {
  677. error = 0;
  678. }
  679. else
  680. {
  681. rt_set_errno(-ENOTSOCK);
  682. error = -1;
  683. }
  684. /* socket has been closed, delete it from file system fd */
  685. fd_release(s);
  686. return error;
  687. }
  688. RTM_EXPORT(closesocket);
  689. /**
  690. * @brief Creates a pair of connected sockets.
  691. *
  692. * The 'socketpair()' function creates two connected sockets, which can be used for bidirectional
  693. * communication between processes or threads on the same machine. This is commonly used for inter-process
  694. * communication (IPC) in UNIX-like operating systems.
  695. *
  696. * @param domain The communication domain (or protocol family). Typically, 'AF_UNIX' (or 'AF_LOCAL')
  697. * is used to create sockets for local communication.
  698. * @param type The type of socket to be created. Common values include:
  699. * - 'SOCK_STREAM': Provides reliable, connection-oriented communication.
  700. * - 'SOCK_DGRAM': Provides connectionless, unreliable communication.
  701. * @param protocol The protocol to be used with the sockets. Normally set to '0' to use the default protocol
  702. * for the specified 'domain' and 'type'.
  703. * @param fds An array of two integers where the file descriptors for the two connected sockets will be stored.
  704. * After a successful call, 'fds[0]' and 'fds[1]' represent the two ends of the socket pair.
  705. *
  706. * @return Returns '0' on success. On failure, returns '-1' and sets 'errno' to indicate the error.
  707. *
  708. * @note The 'socketpair()' function is commonly used to create a communication channel between two processes
  709. * (parent and child after 'fork()') or two threads. Data written to one socket is available for reading
  710. * from the other. It is primarily supported on UNIX-like systems and may not be available on Windows.
  711. *
  712. * @see socket() Creates a single socket for network communication.
  713. * @see pipe() Creates an unidirectional communication channel between processes.
  714. */
  715. int socketpair(int domain, int type, int protocol, int *fds)
  716. {
  717. rt_err_t ret = 0;
  718. int sock_fds[2];
  719. fds[0] = socket(domain, type, protocol);
  720. if (fds[0] < 0)
  721. {
  722. fds[0] = 0;
  723. return -1;
  724. }
  725. fds[1] = socket(domain, type, protocol);
  726. if (fds[1] < 0)
  727. {
  728. closesocket(fds[0]);
  729. fds[0] = 0;
  730. fds[1] = 0;
  731. return -1;
  732. }
  733. sock_fds[0] = dfs_net_getsocket(fds[0]);
  734. sock_fds[1] = dfs_net_getsocket(fds[1]);
  735. ret = sal_socketpair(domain, type, protocol, sock_fds);
  736. if (ret < 0)
  737. {
  738. closesocket(fds[0]);
  739. closesocket(fds[1]);
  740. }
  741. return ret;
  742. }
  743. RTM_EXPORT(socketpair);
  744. /**
  745. * @brief Controls socket I/O modes.
  746. *
  747. * The 'ioctlsocket()' function manipulates the I/O mode of the socket specified by the file descriptor 's'.
  748. * It is primarily used to enable or disable non-blocking mode on a socket or to perform other socket-specific
  749. * operations.
  750. *
  751. * @param s The file descriptor of the socket to control.
  752. * @param cmd The command that specifies the operation to perform. Some common commands include:
  753. * - 'FIONBIO': Enables or disables non-blocking mode. Setting 'arg' to a non-zero value
  754. * enables non-blocking mode; setting it to zero disables it.
  755. * - 'FIONREAD': Retrieves the number of bytes available to read, storing the result in 'arg'.
  756. * @param arg A pointer to an argument for the command. The type and meaning of this argument depend on the
  757. * specified command ('cmd'). For example, in non-blocking mode ('FIONBIO'), it points to a 'long'
  758. * that is either non-zero (to enable) or zero (to disable) non-blocking mode.
  759. *
  760. * @return Returns '0' on success. On failure, returns '-1' and sets errno (or 'WSAGetLastError()' on Windows) to indicate the error.
  761. *
  762. * @note This function is specific to Windows environments and is a part of the Winsock API. It performs
  763. * similar functionality to the 'fcntl()' function on UNIX-like systems.
  764. * The 'ioctlsocket()' function allows for various socket manipulations that affect how the socket
  765. * operates in certain conditions, such as setting it to non-blocking mode.
  766. *
  767. * @see socket() Creates a socket to use with 'ioctlsocket()'.
  768. * @see fcntl() Performs similar operations on UNIX-like systems.
  769. */
  770. int ioctlsocket(int s, long cmd, void *arg)
  771. {
  772. int socket = dfs_net_getsocket(s);
  773. return sal_ioctlsocket(socket, cmd, arg);
  774. }
  775. RTM_EXPORT(ioctlsocket);