1.. _socket_service_interface: 2 3Socket Services 4############### 5 6.. contents:: 7 :local: 8 :depth: 2 9 10Overview 11******** 12 13The socket service API can be used to install a handler that is called if there 14is data received on a socket. The API helps to avoid creating a dedicated thread 15for each TCP or UDP service that the application provides. Instead one thread 16is created that serves data to multiple listening sockets which saves memory 17as only one thread needs to be created in the system in this case. 18 19See :zephyr:code-sample:`sockets-service-echo` sample application to learn how 20to create a simple BSD socket based server application using the sockets service API. 21The source code for this sample application can be found at: 22:zephyr_file:`samples/net/sockets/echo_service`. 23 24API Description 25*************** 26 27Socket service API is enabled using :kconfig:option:`CONFIG_NET_SOCKETS_SERVICE` 28config option and implements the following operations: 29 30* :c:macro:`NET_SOCKET_SERVICE_SYNC_DEFINE` 31 32 Define a network socket service. This socket service is created with extern 33 scope so it can be used from multiple C source files. 34 35* :c:macro:`NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC` 36 37 Define a network socket service with static scope. This socket service can only 38 be used within one C source file. 39 40* :c:func:`net_socket_service_register` 41 42 Register pollable sockets for this service. User must create the sockets 43 before this call. 44 45* :c:func:`net_socket_service_unregister` 46 47 Remove pollable sockets for this service. User can close the sockets after 48 this call. 49 50* :c:type:`net_socket_service_handler_t` 51 52 User specified callback which is called when data is received on the 53 listening socket. 54 55Application Overview 56******************** 57 58If the socket service API is enabled, an application must create the service like 59this: 60 61.. code-block:: c 62 63 #define MAX_BUF_LEN 1500 64 #define MAX_SERVICES 1 65 66 static void udp_service_handler(struct net_socket_service_event *pev) 67 { 68 struct pollfd *pfd = &pev->event; 69 int client = pfd->fd; 70 struct sockaddr_in6 addr; 71 socklen_t addrlen = sizeof(addr); 72 73 /* In this example we use one static buffer in order to avoid 74 * having a large stack. 75 */ 76 static char buf[MAX_BUF_LEN]; 77 78 len = recvfrom(client, buf, sizeof(buf), 0, 79 (struct sockaddr *)&addr, &addrlen); 80 if (len <= 0) { 81 /* Error */ 82 ... 83 return; 84 } 85 86 /* Do something with the received data. The pev variable contains 87 * user data that was stored in the socket service when it was 88 * registered. 89 */ 90 } 91 92 NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(service_udp, udp_service_handler, MAX_SERVICES); 93 94The application needs to create the sockets, then register them to the socket 95service after which the socket service thread will start to call the callback 96for any incoming data. 97 98.. code-block:: c 99 100 /* Create one or multiple sockets */ 101 102 struct pollfd sockfd_udp[1] = { 0 }; 103 int sock, ret; 104 105 sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 106 if (sock < 0) { 107 LOG_ERR("socket: %d", -errno); 108 return -errno; 109 } 110 111 /* Set possible socket options after creation */ 112 ... 113 114 /* Then bind the socket to local address */ 115 if (bind(sock, (struct sockaddr *)addr, sizeof(*addr)) < 0) { 116 LOG_ERR("bind: %d", -errno); 117 return -errno; 118 } 119 120 /* Set the polled sockets */ 121 sockfd_udp[0].fd = sock; 122 sockfd_udp[0].events = POLLIN; 123 124 /* Register UDP socket to service handler */ 125 ret = net_socket_service_register(&service_udp, sockfd_udp, 126 ARRAY_SIZE(sockfd_udp), NULL); 127 if (ret < 0) { 128 LOG_ERR("Cannot register socket service handler (%d)", ret); 129 return ret; 130 } 131 132 /* Application logic happens here. When application is ready to 133 * quit, one should unregister the socket service and close the 134 * socket. 135 */ 136 137 (void)net_socket_service_unregister(&service_udp); 138 close(sock); 139 140The TCP socket needs slightly different logic as we need to add any 141accepted socket to the listening socket by calling the 142:c:func:`net_socket_service_register` for the accepted socket. 143 144.. code-block:: c 145 146 struct sockaddr_in6 client_addr; 147 socklen_t client_addr_len = sizeof(client_addr); 148 struct pollfd sockfd_tcp[1] = { 0 }; 149 int client; 150 151 /* TCP socket service is created similar way as the UDP one */ 152 sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); 153 if (sock < 0) { 154 LOG_ERR("socket: %d", -errno); 155 return -errno; 156 } 157 158 if (bind(sock, (struct sockaddr *)addr, sizeof(*addr)) < 0) { 159 LOG_ERR("bind: %d", -errno); 160 return -errno; 161 } 162 163 if (listen(sock, 5) < 0) { 164 LOG_ERR("listen: %d", -errno); 165 return -errno; 166 } 167 168 while (1) { 169 client = accept(tcp_sock, (struct sockaddr *)&client_addr, 170 &client_addr_len); 171 if (client < 0) { 172 LOG_ERR("accept: %d", -errno); 173 continue; 174 } 175 176 inet_ntop(client_addr.sin6_family, &client_addr.sin6_addr, 177 addr_str, sizeof(addr_str)); 178 LOG_INF("Connection from %s (%d)", addr_str, client); 179 180 sockfd_tcp[0].fd = client; 181 sockfd_tcp[0].events = POLLIN; 182 183 /* Register all the sockets to service handler */ 184 ret = net_socket_service_register(&service_tcp, sockfd_tcp, 185 ARRAY_SIZE(sockfd_tcp), NULL); 186 if (ret < 0) { 187 LOG_ERR("Cannot register socket service handler (%d)", ret); 188 break; 189 } 190 } 191 192For any closed TCP client connection we need to remove the closed 193socket from the polled socket list. 194 195.. code-block:: c 196 197 /* If the TCP socket is closed while reading the data in the handler, 198 * mark it as non pollable. 199 */ 200 if (sockfd_tcp[0].fd == client) { 201 sockfd_tcp[0].fd = -1; 202 203 /* Update the handler so that client connection is 204 * not monitored any more. 205 */ 206 (void)net_socket_service_register(&service_tcp, sockfd_tcp, 207 ARRAY_SIZE(sockfd_tcp), NULL); 208 close(client); 209 210 LOG_INF("Connection from %s closed", addr_str); 211 } 212 213Please see a more complete example in the ``echo_service`` sample source 214code at :zephyr_file:`samples/net/sockets/echo_service/src/main.c`. 215 216API Reference 217************* 218 219.. doxygengroup:: bsd_socket_service 220