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