1@page page_component_sal Socket Abstraction Layer: SAL
2
3# SAL Introduction
4
5In order to adapt to more network protocol stack types and avoid the system's dependence on a single network protocol stack, the RT-Thread system provides a SAL (Socket Abstraction Layer) components that implement different network protocol stacks or network implementations. The abstraction of the interface provides a set of standard BSD Socket APIs to the upper layer, so that developers only need to care about and use the network interface provided by the network application layer, without concern for the underlying specific network protocol stack type and implementation, which greatly improves the system's compatibility makes it easy for developers to complete protocol stack adaptation and network-related development. Main features of the SAL component are as follows:
6
7- Abstract and unified multiple network protocol stack interfaces;;
8- Provide Socket-level TLS encrypted transport feature;
9- Support standard BSD Socket APIs;
10- Unified FD management for easy operation of network functions using read/write poll/select11
12## SAL Network Framework
13
14The SAL network framework of RT-Thread is mainly shown in the following structure:
15
16![SAL 网络框架图](figures/sal_frame.jpg)
17
18The top layer is the network's application layer, provides a set of standard BSD Socket APIs, such as `socket`, `connect` and other functions, for most of the system network development applications.
19
20The second part is the virtual file system layer. In the RT-Thread system, the DFS file system program can implement different file system operations using standard interface functions.The network socket interface also supports the file system structure. The network socket descriptor created when using the network socket interface is uniformly managed by the file system. Therefore, the network socket descriptor can also use the standard file operation interface.The interfaces provided for the upper application layer are: `read`, `write`, `close`, `poll`/`select`, and so on.
21
22The third part is the socket abstraction layer, through which RT-thread system can adapt to different network protocol stacks in the lower layer and provide unified network programming interface in the upper layer to facilitate access of different protocol stacks. The socket abstraction layer provides interfaces for the upper application layer, such as `accept`, `connect`, `send`, `recv`, etc.
23
24The fourth part is the protocol stack layer, which includes several commonly used TCP/IP protocol stacks, such as lwIP, a light TCP/IP protocol stack commonly used in embedded development, and AT Socket network function implementation developed by rt-thread. These protocol stacks or network functions directly contact the hardware to complete the transformation of data from the network layer to the transmission layer.
25
26The network application layer of RT-thread provides interfaces mainly based on the standard BSD Socket API, which ensures that programs can be written on PC, debugged, and then ported to the RT-thread operating system.
27
28## Working Principles
29
30The working principle of SAL component is mainly divided into the following three parts:
31
32- Unified abstract functions of multi-protocol stack access and interface functions;
33- SAL TLS encryption transmission function;
34
35### Multi-Protocol Stack Access and Unified Abstract Function Of Interface Function
36
37For different protocol stacks or network function implementations, the names of network interfaces may be different. Take the `connect` connection function as an example. The interface name in the lwIP protocol stack is `lwip_connect`, and the interface name in the AT Socket network implementation is `at_connect`. The SAL component provides abstraction and unification of the interface of different protocol stacks or networks. When the socket is created, the component **judges the protocol stack or network function used by judging the incoming protocol domain type**, and completes the RT-Thread.
38
39Currently, the protocol stack or network implementation types supported by the SAL component are: **lwIP protocol stack**, **AT Socket protocol stack**, **WIZnet hardware TCP/IP protocol stack**.
40
41```c
42int socket(int domain, int type, int protocol);
43```
44
45The above is the definition of the socket creation function in the standard BSD Socket API. The `domain` indicates that the protocol domain is also called the protocol domain. It is used to determine which protocol stack or network implementation to use. The domain type used by the AT Socket protocol stack is **AF_AT**, lwIP protocol stack uses protocol domain type **AF_INET**, etc., WIZnet protocol stack uses protocol domain type **AF_WIZ**.
46
47For different software packages, the protocol domain type passed to the socket may be fixed and will not change depending on how the SAL component is accessed. **In order to dynamically adapt access to different protocol stacks or network implementations**, the SAL component provides two protocol domain type matching methods for each protocol stack or network implementation: **Primary protocol domain type and secondary protocol domain type**. When socket is created, it first determines whether the incoming protocol domain type has the supported primary protocol type. If it is, it uses the corresponding protocol stack or network implementation, if not, determine whether the subprotocol cluster type supports. The current system support protocol domain types are as follows:
48
491. lwIP Protocol stack: family = AF_INET、sec_family = AF_INET
50
512. AT Socket Protocol stack: family = AF_AT、sec_family = AF_INET
52
533. WIZnet hardware TCP/IP Protocol stack: family = AF_WIZ、sec_family = AF_INET
54
55
56
57The main function of the SAL component is to unify the underlying BSD Socket API interface. The following takes the `connect` function call flow as an example to illustrate the SAL component function call method:
58
59- `connect`: The abstract BSD Socket API provided by the SAL component for unified FD management;
60- `sal_connect`: The `connect` implementation function in the SAL component that is used to call the `operation` function registered by the underlying stack.。
61- `lwip_connect`: The layer `connect` connection function provided by the underlying protocol stack is registered in the SAL component when the NIC is initialized, and the final call operation function。
62
63```c
64/* SAL component provides BSD Socket APIs for the application layer  */
65int connect(int s, const struct sockaddr *name, socklen_t namelen)
66{
67    /* Get the SAL socket descriptor */
68    int socket = dfs_net_getsocket(s);
69
70    /* Execute the sal_connect function with a SAL socket descriptor*/
71    return sal_connect(socket, name, namelen);
72}
73
74/* SAL component abstract function interface implementation */
75int sal_connect(int socket, const struct sockaddr *name, socklen_t namelen)
76{
77    struct sal_socket *sock;
78    struct sal_proto_family *pf;
79    int ret;
80
81    /* Check if the SAL socket structure is normal */
82    SAL_SOCKET_OBJ_GET(sock, socket);
83
84    /* Check if the current socket network connection status is normal. */
85    SAL_NETDEV_IS_COMMONICABLE(sock->netdev);
86    /* Check if the underlying operation function corresponding to the current socket is normal.  */
87    SAL_NETDEV_SOCKETOPS_VALID(sock->netdev, pf, connect);
88
89    /* The connect operation function that performs the underlying registration */
90    ret = pf->skt_ops->connect((int) sock->user_data, name, namelen);
91#ifdef SAL_USING_TLS
92    if (ret >= 0 && SAL_SOCKOPS_PROTO_TLS_VALID(sock, connect))
93    {
94        if (proto_tls->ops->connect(sock->user_data_tls) < 0)
95        {
96            return -1;
97        }
98        return ret;
99    }
100#endif
101    return ret;
102}
103
104/* The underlying connect function of the lwIP protocol stack function */
105int lwip_connect(int socket, const struct sockaddr *name, socklen_t namelen)
106{
107    ...
108}
109```
110
111### SAL TLS Encrypted Transmission Function
112
113**1. SAL TLS Feature**
114
115In the transmission of protocol data such as TCP and UDP, since the data packet is plaintext, it is likely to be intercepted and parsed by others, which has a great impact on the secure transmission of information. In order to solve such problems, users generally need to add the SSL/TLS protocol between the application layer and the transport layer.
116
117TLS (Transport Layer Security) is a protocol based on the transport layer TCP protocol. Its predecessor is SSL (Secure Socket Layer). Its main function is to encrypt the application layer message asymmetrically and then transmit it by TCP protocol, so as to achieve secure data encryption interaction.
118
119Currently used TLS methods: **MbedTLS, OpenSSL, s2n**, etc., but for different encryption methods, you need to use their specified encryption interface and process for encryption, the migration of some application layer protocols is more complicated. Therefore, the SAL TLS function is generated, the main function is to **provide TLS-encrypted transmission characteristics at the Socket level, abstract multiple TLS processing methods, and provide a unified interface for completing TLS data interaction**.
120
121**2. How to use the SAL TLS feature**
122
123The process is as follows:
124
125- Configure to enable any network protocol stack support (such as lwIP protocol stack);
126
127- Configure to enable the MbedTLS package (currently only supports MbedTLS type encryption);
128
129- Configure to enable SAL_TLS support (as shown in the configuration options section below);
130
131After the configuration is complete, as long as the `protocol` type passed in the socket creation uses **PROTOCOL_TLS** or **PROTOCOL_DTLS **, the standard BSD Socket API interface can be used to complete the establishment of the TLS connection and the data transmission and reception. The sample code is as follows:
132
133```c
134#include <stdio.h>
135#include <string.h>
136
137#include <rtthread.h>
138#include <sys/socket.h>
139#include <netdb.h>
140
141/* RT-Thread offical website,supporting TLS function */
142#define SAL_TLS_HOST    "www.rt-thread.org"
143#define SAL_TLS_PORT    443
144#define SAL_TLS_BUFSZ   1024
145
146static const char *send_data = "GET /download/rt-thread.txt HTTP/1.1\r\n"
147    "Host: www.rt-thread.org\r\n"
148    "User-Agent: rtthread/4.0.1 rtt\r\n\r\n";
149
150void sal_tls_test(void)
151{
152    int ret, i;
153    char *recv_data;
154    struct hostent *host;
155    int sock = -1, bytes_received;
156    struct sockaddr_in server_addr;
157
158    /* Get the host address through the function entry parameter url (if it is a domain name, it will do domain name resolution) */
159    host = gethostbyname(SAL_TLS_HOST);
160
161    recv_data = rt_calloc(1, SAL_TLS_BUFSZ);
162    if (recv_data == RT_NULL)
163    {
164        rt_kprintf("No memory\n");
165        return;
166    }
167
168    /* Create a socket of type SOCKET_STREAM, TCP protocol, TLS type */
169    if ((sock = socket(AF_INET, SOCK_STREAM, PROTOCOL_TLS)) < 0)
170    {
171        rt_kprintf("Socket error\n");
172        goto __exit;
173    }
174
175    /* Initialize the server address */
176    server_addr.sin_family = AF_INET;
177    server_addr.sin_port = htons(SAL_TLS_PORT);
178    server_addr.sin_addr = *((struct in_addr *)host->h_addr);
179    rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
180
181    if (connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) < 0)
182    {
183        rt_kprintf("Connect fail!\n");
184        goto __exit;
185    }
186
187    /* Send data to the socket connection */
188    ret = send(sock, send_data, strlen(send_data), 0);
189    if (ret <= 0)
190    {
191        rt_kprintf("send error,close the socket.\n");
192        goto __exit;
193    }
194
195    /* Receive and print the response data, using encrypted data transmission */
196    bytes_received = recv(sock, recv_data, SAL_TLS_BUFSZ  - 1, 0);
197    if (bytes_received <= 0)
198    {
199        rt_kprintf("received error,close the socket.\n");
200        goto __exit;
201    }
202
203    rt_kprintf("recv data:\n");
204    for (i = 0; i < bytes_received; i++)
205    {
206        rt_kprintf("%c", recv_data[i]);
207    }
208
209__exit:
210    if (recv_data)
211        rt_free(recv_data);
212
213    if (sock >= 0)
214        closesocket(sock);
215}
216
217#ifdef FINSH_USING_MSH
218#include <finsh.h>
219MSH_CMD_EXPORT(sal_tls_test, SAL TLS function test);
220#endif /* FINSH_USING_MSH */
221```
222
223## Configuration Options
224
225When we use the SAL component we need to define the following macro definition in rtconfig.h226
227|   **Macro definition**   | **Description**                      |
228|--------------------------------|--------------------------------|
229| RT_USING_SAL  | Enable the SAL function |
230| SAL_USING_LWIP  | Enable lwIP stack support |
231| SAL_USING_AT | Enable AT Socket protocol stack support |
232| SAL_USING_TLS | Enable SAL TLS feature support |
233| SAL_USING_POSIX   | Enable POSIX file system related function support, such as read, write, select/poll, etc. |
234
235Currently, the SAL abstraction layer supports the lwIP protocol stack, the AT Socket protocol stack, and the WIZnet hardware TCP/IP protocol stack. To enable SAL in the system, at least one protocol stack support is required.
236
237The above configuration options can be added directly to the `rtconfig.h` file or added by the component package management tool Env configuration option. The specific configuration path in the Env tool is as follows:
238
239```c
240RT-Thread Components  --->
241    Network  --->
242        Socket abstraction layer  --->
243        [*] Enable socket abstraction layer
244            protocol stack implement --->
245            [ ] Support lwIP stack
246            [ ] Support AT Commands stack
247            [ ] Support MbedTLS protocol
248        [*]    Enable BSD socket operated by file system API
249```
250
251After the configuration is complete, you can use the `scons` command to regenerate the function and complete the addition of the SAL component.
252
253# Initialization
254
255配置开启 SAL 选项之后,需要在启动时对它进行初始化,开启 SAL 功能,如果程序中已经使用了组件自动初始化,则不再需要额外进行单独的初始化,否则需要在初始化任务中调用如下函数:
256
257```c
258int sal_init(void);
259```
260
261The initialization function is mainly for initializing the SAL component, supporting the component to repeatedly initialize the judgment, and completing the initialization of the resource such as the mutex used in the component. There is no new thread created in the SAL component, which means that the SAL component resource is very small. Currently, the **SAL component resource is occupied by ROM 2.8K and RAM 0.6K**.
262
263
264# BSD Socket API Introduction
265
266The SAL component abstracts the standard BSD Socket API interface. The following is an introduction to common network interfaces:
267
268## Create a Socket (socket)
269
270``` c
271int socket(int domain, int type, int protocol);
272```
273
274|   **Parameter**   | **Description**                       |
275|--------|-------------------------------------|
276|  domain  | protocol domain type  |
277|   type   | protocol type               |
278| protocol | Transport layer protocol for actual use |
279|   **back**   | --                                 |
280|  >=0  | Success, an integer representing the socket descriptor will be returned |
281|    -1    | Fail                              |
282
283This function is used to assign a socket descriptor and the resources it USES based on the specified address family, data type, and protocol.
284
285**domain ( protocol domain type ):**
286
287-   AF_INET: IPv4
288-   AF_INET6: IPv6
289
290**type ( protocol type ):**
291
292-   SOCK_STREAM:Stream socket
293-   SOCK_DGRAM: Datagram socket
294-   SOCK_RAW: Raw socket
295
296## Bind Socket (bind)
297
298```c
299int bind(int s, const struct sockaddr *name, socklen_t namelen);
300```
301
302|   **P**arameter   | **Description**                               |
303|---------|---------------------------------------------|
304|     s     | socket descriptor                |
305|    name   | a pointer to the sockaddr structure representing the address to bind to |
306| namelen | length of sockaddr structure |
307|   **back**   | --                                         |
308|     0     | success                                   |
309|     -1    | fail                                      |
310
311This function is used to bind the port number and IP address to the specified socket。
312
313SAL components depend on the `netdev` components, when using ` bind () ` function, can get  IP address information through the netdev nic name, is used to create Socket bound to the specified object of network interface card. The following example completes the process of binding the IP address of the network interface card and connecting to the server through the name of the incoming network interface card:
314
315```c
316#include <rtthread.h>
317#include <arpa/inet.h>
318#include <netdev.h>
319
320#define SERVER_HOST   "192.168.1.123"
321#define SERVER_PORT   1234
322
323static int bing_test(int argc, char **argv)
324{
325    struct sockaddr_in client_addr;
326    struct sockaddr_in server_addr;
327    struct netdev *netdev = RT_NULL;
328    int sockfd = -1;
329
330    if (argc != 2)
331    {
332        rt_kprintf("bind_test [netdev_name]  --bind network interface device by name.\n");
333        return -RT_ERROR;
334    }
335
336    /* Get the netdev network interface card object by name */
337    netdev = netdev_get_by_name(argv[1]);
338    if (netdev == RT_NULL)
339    {
340        rt_kprintf("get network interface device(%s) failed.\n", argv[1]);
341        return -RT_ERROR;
342    }
343
344    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
345    {
346        rt_kprintf("Socket create failed.\n");
347        return -RT_ERROR;
348    }
349
350    /* Initializes the client address to bind to */
351    client_addr.sin_family = AF_INET;
352    client_addr.sin_port = htons(8080);
353    /* Gets the IP address information in the network interface card object */
354    client_addr.sin_addr.s_addr = netdev->ip_addr.addr;
355    rt_memset(&(client_addr.sin_zero), 0, sizeof(client_addr.sin_zero));
356
357    if (bind(sockfd, (struct sockaddr *)&client_addr, sizeof(struct sockaddr)) < 0)
358    {
359        rt_kprintf("socket bind failed.\n");
360        closesocket(sockfd);
361        return -RT_ERROR;
362    }
363    rt_kprintf("socket bind network interface device(%s) success!\n", netdev->name);
364
365    /* Initializes the server address for the pre-connection */
366    server_addr.sin_family = AF_INET;
367    server_addr.sin_port = htons(SERVER_PORT);
368    server_addr.sin_addr.s_addr = inet_addr(SERVER_HOST);
369    rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
370
371    /* Connect to the server */
372    if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) < 0)
373    {
374        rt_kprintf("socket connect failed!\n");
375        closesocket(sockfd);
376        return -RT_ERROR;
377    }
378    else
379    {
380        rt_kprintf("socket connect success!\n");
381    }
382
383    /* Close the connection */
384    closesocket(sockfd);
385    return RT_EOK;
386}
387
388#ifdef FINSH_USING_MSH
389#include <finsh.h>
390MSH_CMD_EXPORT(bing_test, bind network interface device test);
391#endif /* FINSH_USING_MSH */
392```
393
394## Listen Socket (listen)
395
396```c
397int listen(int s, int backlog);
398```
399
400|  **Parameter**  | **Description**                 |
401|-------|-------------------------------|
402|    s    | socket descriptor  |
403| backlog | represents the maximum number of connections that can wait at a time |
404|  **back**  | --                           |
405|    0    | success                    |
406|    -1   | fail                     |
407
408This function is used by the TCP server to listen for a specified socket connection。
409
410## Accept Connection (accept)
411
412```c
413int accept(int s, struct sockaddr *addr, socklen_t *addrlen);
414```
415
416|  **Parameter**  | **Descrption**                 |
417|-------|-------------------------------|
418|    s    | socket descriptor  |
419|   addr  | represents the maximum number of connections that can wait at a time |
420| addrlen | length of client device address structure |
421|  **back**  | --                           |
422|    0    | success, return the newly created socket descriptor |
423|    -1   | fail                        |
424
425When the application listens for connections from other hosts, the connection is initialized with the `accept()` function, and `accept()` creates a new socket for each connection and removes the connection from the listen queue.
426
427## Establish Connection (connect)
428
429```c
430int connect(int s, const struct sockaddr *name, socklen_t namelen);
431```
432
433|  **Parameter**  | **Description** |
434|-------|-------------------------------|
435|    s    | socket descriptor  |
436|   name  | server address information |
437| namelen | server address structure length |
438|  **back**  | --                    |
439|    0    | successful, return the newly created socket descriptor |
440|    -1   | fail                 |
441
442This function is used to establish a connection to the specified socket.
443
444## Send TCP Data (send)
445
446```c
447int send(int s, const void *dataptr, size_t size, int flags);
448```
449
450|  **Parameter**  | **Description**             |
451|-------|---------------------------|
452|    s    | socket descriptor |
453| dataptr | sent data pointer |
454|   size  | length of sent data |
455|  flags  | flags, usually 0 |
456|  **back**  | --                       |
457|  >0  | success, the length of the sent data  is returned |
458|  <=0 | Fail                    |
459
460This function is commonly used to send data over a TCP connection。
461
462## Receive TCP Data (recv)
463
464```c
465int recv(int s, void *mem, size_t len, int flags);
466```
467
468| **Parameter** | **Description**             |
469|-----|---------------------------|
470|   s   | socket descriptor |
471|  mem  | received data pointer |
472|  len  | length of received data |
473| flags | flags, usually 0 |
474| **back** | --                       |
475| >0 | success, the length of the received data will be returned |
476|   =0  | the destination address has been transmitted and the connection is closed |
477| <0 | fail                                                         |
478
479This function is used to receive data over a TCP connection。
480
481## Send UDP Data (sendto)
482
483```c
484int sendto(int s, const void *dataptr, size_t size, int flags, const struct sockaddr *to, socklen_t tolen);
485```
486
487|  **Parameter**  | **Description**            |
488|-------|---------------------------|
489|    s    | socket descriptor |
490| dataptr | sent data pointer |
491|   size  | length of sent data |
492|  flags  | flags, usually 0 |
493|    to   | target address structure pointer |
494|  tolen  | length of the target address structure |
495| **return** | --                       |
496|  >0  | success, the length of the received data will be returned |
497|  <=0 | fail                    |
498
499This function is used for UDP connections to send data。
500
501## Receive  UDP Data (recvfrom)
502
503```c
504int recvfrom(int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
505```
506
507|  **Parameter**  | **Description**           |
508|-------|---------------------------|
509|    s    | socket descriptor |
510|   mem   | received data pointer |
511|   len   | length of data received |
512|  flags  | flags, usually 0 |
513|   from  | received address structure pointer |
514| fromlen | length of received address structure |
515|  **back**  | --                       |
516|  >0  | success, return the length of the received data |
517|    =0   | the receiving address has been transferred and the connection is closed |
518|  <0  | fail                    |
519
520This function is used to receive data on a UDP connection。
521
522## Close Socket (closesocket)
523
524```c
525int closesocket(int s);
526```
527
528| **Parameter** | **Description** |
529|----|-------------|
530|   s  | Socket descriptor |
531| **back** | --         |
532|   0  | success   |
533|  -1  | fail      |
534
535This function is used to close the connection and release the resource.。
536
537## Shutdown The Socket By Setting(shutdown)
538
539```c
540int shutdown(int s, int how);
541```
542
543| **Parameter** | **Descrption**    |
544|----|-----------------|
545|   s  | socket descriptor |
546|  how | socket control |
547| **back** | --             |
548|   0  | fail          |
549|  -1  | success       |
550
551This function provides more permissions to control the closing process of the socket.。
552
553**How ( socket control ):**
554
555-   0: Stop receiving current data and reject future data reception;
556-   1: Stop sending data and discard unsent data;
557-   2: Stop receiving and sending data。
558
559## Set Socket Options(setsockopt)
560
561```c
562int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
563```
564
565|  **Parameter**  | **Description**         |
566|-------|-----------------------|
567|    s    | socket descriptor |
568|  level  | protocol stack configuration options |
569| optname | option name to be set |
570|  optval | set the buffer address of the option value |
571|  optlen | set the buffer length of the option value |
572|  **back**  | --                   |
573|    =0   | success             |
574|  <0  | fail                |
575
576This function is used to set the socket mode and modify the socket configuration options.。
577
578**level ( protocol stack configuration options ):**
579
580-   SOL_SOCKET:Socket layer
581-   IPPROTO_TCP:TCP layer
582-   IPPROTO_IP:IP layer
583
584**optname ( Option name to be set ):**
585
586-   SO_KEEPALIVE:Set keep alive options
587-   SO_RCVTIMEO:Set socket data reception timeout
588-   SO_SNDTIMEO:Set socket data sending timeout
589
590## Get Socket Options(getsockopt)
591
592```c
593int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen);
594```
595
596|  **Parameter**  | **Description**             |
597|-------|---------------------------|
598|    s    | socket descriptor |
599|  level  | protocol stack configuration options |
600| optname | option name to be set |
601|  optval | get the buffer address of the option value |
602|  optlen | get the buffer length address of the option value |
603|  **back**  | --                       |
604|    =0   | success               |
605|  <0  | fail                    |
606
607This function is used to get the socket configuration options。
608
609## Get Remote Address Information (getpeername)
610
611```c
612int getpeername(int s, struct sockaddr *name, socklen_t *namelen);
613```
614
615|  **Parameter**  | **Description**          |
616|-------|-------------------------|
617|    s    | socket descriptor |
618|   name  | received address structure pointer |
619| namelen | length of received address structure |
620|  **back**  | --                     |
621|    =0   | success               |
622|  <0  | fail                  |
623
624This function is used to get the remote address information associated with the socket。
625
626## Get Local Address Information (getsockname)
627
628```c
629int getsockname(int s, struct sockaddr *name, socklen_t *namelen);
630```
631
632|  **Parameter**  | **Description**           |
633|-------|-------------------------|
634|    s    | Socket descriptor |
635|   name  | received address structure pointer |
636| namelen | length of received address structure |
637|  **back**  | --                     |
638|    =0   | success               |
639|  <0  | fail                  |
640
641This function is used to get local socket address information。
642
643## Configure Socket Parameters (ioctlsocket))
644
645```c
646int ioctlsocket(int s, long cmd, void *arg);
647```
648
649| **Parameter** | **Description**   |
650|-----|-----------------|
651|   s   | socket descriptor |
652|  cmd  | socket operation command |
653|  arg  | operation command's parameters |
654| **back** | --             |
655|   =0  | success      |
656| <0 | fail          |
657
658This function sets the socket control mode。
659
660**The CMD supports following commands**
661
662-   FIONBIO: Turns on or off the socket's non-blocking mode. Arg parameter 1 is open non-blocking and 0 is closed non-blocking.
663
664# Network Protocol Stack Access
665
666Access to the network protocol stack or network function implementation is mainly to initialize and register the protocol cluster structure, and add it to the protocol cluster list in SAL component. The protocol cluster structure is defined as follows:
667
668```c
669/* network interface socket opreations */
670struct sal_socket_ops
671{
672    int (*socket)     (int domain, int type, int protocol);
673    int (*closesocket)(int s);
674    int (*bind)       (int s, const struct sockaddr *name, socklen_t namelen);
675    int (*listen)     (int s, int backlog);
676    int (*connect)    (int s, const struct sockaddr *name, socklen_t namelen);
677    int (*accept)     (int s, struct sockaddr *addr, socklen_t *addrlen);
678    int (*sendto)     (int s, const void *data, size_t size, int flags, const struct sockaddr *to, socklen_t tolen);
679    int (*recvfrom)   (int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
680    int (*getsockopt) (int s, int level, int optname, void *optval, socklen_t *optlen);
681    int (*setsockopt) (int s, int level, int optname, const void *optval, socklen_t optlen);
682    int (*shutdown)   (int s, int how);
683    int (*getpeername)(int s, struct sockaddr *name, socklen_t *namelen);
684    int (*getsockname)(int s, struct sockaddr *name, socklen_t *namelen);
685    int (*ioctlsocket)(int s, long cmd, void *arg);
686#ifdef SAL_USING_POSIX
687    int (*poll)       (struct dfs_file *file, struct rt_pollreq *req);
688#endif
689};
690
691/* sal network database name resolving */
692struct sal_netdb_ops
693{
694    struct hostent* (*gethostbyname)  (const char *name);
695    int             (*gethostbyname_r)(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop);
696    int             (*getaddrinfo)    (const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res);
697    void            (*freeaddrinfo)   (struct addrinfo *ai);
698};
699
700/* Protocol domain structure definition */
701struct sal_proto_family
702{
703    int family;                                  /* primary protocol families type */
704    int sec_family;                              /* secondary protocol families type */
705    const struct sal_socket_ops *skt_ops;        /* socket opreations */
706    const struct sal_netdb_ops *netdb_ops;       /* network database opreations */
707};
708
709```
710
711- `family`: Each protocol stack supports the main protocol cluster types, such as AF_INET for lwIP, AF_AT Socket, and AF_WIZ for WIZnet。
712- `sec_family`:The type of sub-protocol domain supported by each protocol stack, used to support a single protocol stack or network implementation, that matches other types of protocol cluster types in the package。
713- `skt_ops`: Define socket related functions, such as connect, send, recv, etc., each protocol cluster has a different set of implementation。
714- `netdb_ops`:Define non-socket-related execution functions, such as `gethostbyname`, `getaddrinfo`, `freeaddrinfo`, etc. Each protocol cluster has a different set of implementations。
715
716The following is the access registration process implemented by AT Socket network. Developers can refer to other protocol stacks or network implementations for access:
717
718```c
719#include <rtthread.h>
720#include <netdb.h>
721#include <sal_low_lvl.h>            /* SAL component structure holds the header file */
722#include <at_socket.h>      /* AT Socket related header file */
723#include <af_inet.h>
724
725#include <netdev.h>         /*network interface card function related header file */
726
727#ifdef SAL_USING_POSIX
728#include <dfs_poll.h>       /* Poll function related header file */
729#endif
730
731#ifdef SAL_USING_AT
732
733/* A custom poll execution function that handles the events received in the poll */
734static int at_poll(struct dfs_file *file, struct rt_pollreq *req)
735{
736    int mask = 0;
737    struct at_socket *sock;
738    struct socket *sal_sock;
739
740    sal_sock = sal_get_socket((int) file->data);
741    if(!sal_sock)
742    {
743        return -1;
744    }
745
746    sock = at_get_socket((int)sal_sock->user_data);
747    if (sock != NULL)
748    {
749        rt_base_t level;
750
751        rt_poll_add(&sock->wait_head, req);
752
753        level = rt_hw_interrupt_disable();
754        if (sock->rcvevent)
755        {
756            mask |= POLLIN;
757        }
758        if (sock->sendevent)
759        {
760            mask |= POLLOUT;
761        }
762        if (sock->errevent)
763        {
764            mask |= POLLERR;
765        }
766        rt_hw_interrupt_enable(level);
767    }
768
769    return mask;
770}
771#endif
772
773/* Define and assign socket execution functions, and the SAL component calls the underlying function of the registration when it executes relevant functions */
774static const struct proto_ops at_inet_stream_ops =
775{
776    at_socket,
777    at_closesocket,
778    at_bind,
779    NULL,
780    at_connect,
781    NULL,
782    at_sendto,
783    at_recvfrom,
784    at_getsockopt,
785    at_setsockopt,
786    at_shutdown,
787    NULL,
788    NULL,
789    NULL,
790
791#ifdef SAL_USING_POSIX
792    at_poll,
793#else
794    NULL,
795#endif /* SAL_USING_POSIX */
796};
797
798static const struct sal_netdb_ops at_netdb_ops =
799{
800    at_gethostbyname,
801    NULL,
802    at_getaddrinfo,
803    at_freeaddrinfo,
804};
805
806/* define and assign AT Socket protocol domain structure */
807static const struct sal_proto_family at_inet_family =
808{
809    AF_AT,
810    AF_INET,
811    &at_socket_ops,
812    &at_netdb_ops,
813};
814
815/* Used to set the protocol domain information in the network interface card device */
816int sal_at_netdev_set_pf_info(struct netdev *netdev)
817{
818    RT_ASSERT(netdev);
819
820    netdev->sal_user_data = (void *) &at_inet_family;
821    return 0;
822}
823
824#endif /* SAL_USING_AT */
825```
826