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