1 /**
2  * @file
3  * @brief BSD Socket service API
4  *
5  * API can be used to install a k_work that is called
6  * if there is data received to a socket.
7  */
8 
9 /*
10  * Copyright (c) 2023 Nordic Semiconductor ASA
11  *
12  * SPDX-License-Identifier: Apache-2.0
13  */
14 
15 #ifndef ZEPHYR_INCLUDE_NET_SOCKET_SERVICE_H_
16 #define ZEPHYR_INCLUDE_NET_SOCKET_SERVICE_H_
17 
18 /**
19  * @brief BSD socket service API
20  * @defgroup bsd_socket_service BSD socket service API
21  * @since 3.6
22  * @version 0.2.0
23  * @ingroup networking
24  * @{
25  */
26 
27 #include <sys/types.h>
28 #include <zephyr/types.h>
29 #include <zephyr/net/socket.h>
30 
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34 
35 struct net_socket_service_event;
36 
37 /** @brief The signature for a net socket service handler function.
38  *
39  * The function will be invoked by the socket service.
40  *
41  * @param pev the socket service event that provided the handler.
42  */
43 typedef void (*net_socket_service_handler_t)(struct net_socket_service_event *pev);
44 
45 /**
46  * This struct contains information which socket triggered
47  * calls to the callback function.
48  */
49 struct net_socket_service_event {
50 	/** Callback to be called for desired socket activity */
51 	net_socket_service_handler_t callback;
52 	/** Socket information that triggered this event. */
53 	struct zsock_pollfd event;
54 	/** User data */
55 	void *user_data;
56 	/** Service back pointer */
57 	struct net_socket_service_desc *svc;
58 };
59 
60 /**
61  * Main structure holding socket service configuration information.
62  * The k_work item is created so that when there is data coming
63  * to those fds, the k_work callback is then called.
64  * The workqueue can be set NULL in which case system workqueue is used.
65  * The service descriptor should be created at built time, and then used
66  * as a parameter to register the sockets to be monitored.
67  * User should create needed sockets and then setup the poll struct and
68  * then register the sockets to be monitored at runtime.
69  */
70 struct net_socket_service_desc {
71 #if CONFIG_NET_SOCKETS_LOG_LEVEL >= LOG_LEVEL_DBG
72 	/**
73 	 * Owner name. This can be used in debugging to see who has
74 	 * registered this service.
75 	 */
76 	const char *owner;
77 #endif
78 	/** Pointer to the list of services that we are listening */
79 	struct net_socket_service_event *pev;
80 	/** Length of the pollable socket array for this service. */
81 	int pev_len;
82 	/** Where are my pollfd entries in the global list */
83 	int *idx;
84 };
85 
86 /** @cond INTERNAL_HIDDEN */
87 
88 #define __z_net_socket_svc_get_name(_svc_id) __z_net_socket_service_##_svc_id
89 #define __z_net_socket_svc_get_idx(_svc_id) __z_net_socket_service_idx_##_svc_id
90 #define __z_net_socket_svc_get_owner __FILE__ ":" STRINGIFY(__LINE__)
91 
92 #if CONFIG_NET_SOCKETS_LOG_LEVEL >= LOG_LEVEL_DBG
93 #define NET_SOCKET_SERVICE_OWNER .owner = __z_net_socket_svc_get_owner,
94 #else
95 #define NET_SOCKET_SERVICE_OWNER
96 #endif
97 
98 #define __z_net_socket_service_define(_name, _cb, _count, ...) \
99 	static int __z_net_socket_svc_get_idx(_name);			\
100 	static struct net_socket_service_event				\
101 			__z_net_socket_svc_get_name(_name)[_count] = {	\
102 		[0 ... ((_count) - 1)] = {				\
103 			.event.fd = -1, /* Invalid socket */		\
104 			.callback = _cb,				\
105 		}							\
106 	};								\
107 	COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), (), __VA_ARGS__)	\
108 	const STRUCT_SECTION_ITERABLE(net_socket_service_desc, _name) = { \
109 		NET_SOCKET_SERVICE_OWNER				\
110 		.pev = __z_net_socket_svc_get_name(_name),		\
111 		.pev_len = (_count),					\
112 		.idx = &__z_net_socket_svc_get_idx(_name),		\
113 	}
114 
115 /** @endcond */
116 
117 /**
118  * @brief Statically define a network socket service.
119  *        The user callback is called synchronously for this service meaning that
120  *        the service API will wait until the user callback returns before continuing
121  *        with next socket service.
122  *
123  * The socket service can be accessed outside the module where it is defined using:
124  *
125  * @code extern struct net_socket_service_desc <name>; @endcode
126  *
127  * @note This macro cannot be used together with a static keyword.
128  *       If such a use-case is desired, use NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC
129  *       instead.
130  *
131  * @param name Name of the service.
132  * @param cb Callback function that is called for socket activity.
133  * @param count How many pollable sockets is needed for this service.
134  */
135 #define NET_SOCKET_SERVICE_SYNC_DEFINE(name, cb, count)	\
136 	__z_net_socket_service_define(name, cb, count)
137 
138 /**
139  * @brief Statically define a network socket service in a private (static) scope.
140  *        The user callback is called synchronously for this service meaning that
141  *        the service API will wait until the user callback returns before continuing
142  *        with next socket service.
143  *
144  * @param name Name of the service.
145  * @param cb Callback function that is called for socket activity.
146  * @param count How many pollable sockets is needed for this service.
147  */
148 #define NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(name, cb, count)	\
149 	__z_net_socket_service_define(name, cb, count, static)
150 
151 /**
152  * @brief Register pollable sockets.
153  *
154  * @param service Pointer to a service description.
155  * @param fds Socket array to poll.
156  * @param len Length of the socket array.
157  * @param user_data User specific data.
158  *
159  * @retval 0 No error
160  * @retval -ENOENT Service is not found.
161  * @retval -ENINVAL Invalid parameter.
162  */
163 __syscall int net_socket_service_register(const struct net_socket_service_desc *service,
164 					  struct zsock_pollfd *fds, int len, void *user_data);
165 
166 /**
167  * @brief Unregister pollable sockets.
168  *
169  * @param service Pointer to a service description.
170  *
171  * @retval 0 No error
172  * @retval -ENOENT Service is not found.
173  * @retval -ENINVAL Invalid parameter.
174  */
net_socket_service_unregister(const struct net_socket_service_desc * service)175 static inline int net_socket_service_unregister(const struct net_socket_service_desc *service)
176 {
177 	return net_socket_service_register(service, NULL, 0, NULL);
178 }
179 
180 /**
181  * @typedef net_socket_service_cb_t
182  * @brief Callback used while iterating over socket services.
183  *
184  * @param svc Pointer to current socket service.
185  * @param user_data A valid pointer to user data or NULL
186  */
187 typedef void (*net_socket_service_cb_t)(const struct net_socket_service_desc *svc,
188 					void *user_data);
189 
190 /**
191  * @brief Go through all the socket services and call callback for each service.
192  *
193  * @param cb User-supplied callback function to call
194  * @param user_data User specified data
195  */
196 void net_socket_service_foreach(net_socket_service_cb_t cb, void *user_data);
197 
198 #ifdef __cplusplus
199 }
200 #endif
201 
202 #include <zephyr/syscalls/socket_service.h>
203 
204 /**
205  * @}
206  */
207 
208 #endif /* ZEPHYR_INCLUDE_NET_SOCKET_SERVICE_H_ */
209