/src/systemd/src/shared/varlink.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: LGPL-2.1+ */ |
2 | | |
3 | | #include <sys/poll.h> |
4 | | |
5 | | #include "alloc-util.h" |
6 | | #include "errno-util.h" |
7 | | #include "fd-util.h" |
8 | | #include "hashmap.h" |
9 | | #include "list.h" |
10 | | #include "process-util.h" |
11 | | #include "set.h" |
12 | | #include "socket-util.h" |
13 | | #include "string-table.h" |
14 | | #include "string-util.h" |
15 | | #include "strv.h" |
16 | | #include "time-util.h" |
17 | | #include "umask-util.h" |
18 | | #include "user-util.h" |
19 | | #include "varlink.h" |
20 | | |
21 | 14.7k | #define VARLINK_DEFAULT_CONNECTIONS_MAX 4096U |
22 | 7.38k | #define VARLINK_DEFAULT_CONNECTIONS_PER_UID_MAX 1024U |
23 | | |
24 | 7.38k | #define VARLINK_DEFAULT_TIMEOUT_USEC (45U*USEC_PER_SEC) |
25 | 1.25M | #define VARLINK_BUFFER_MAX (16U*1024U*1024U) |
26 | | #define VARLINK_READ_SIZE (64U*1024U) |
27 | | |
28 | | typedef enum VarlinkState { |
29 | | /* Client side states */ |
30 | | VARLINK_IDLE_CLIENT, |
31 | | VARLINK_AWAITING_REPLY, |
32 | | VARLINK_CALLING, |
33 | | VARLINK_CALLED, |
34 | | VARLINK_PROCESSING_REPLY, |
35 | | |
36 | | /* Server side states */ |
37 | | VARLINK_IDLE_SERVER, |
38 | | VARLINK_PROCESSING_METHOD, |
39 | | VARLINK_PROCESSING_METHOD_MORE, |
40 | | VARLINK_PROCESSING_METHOD_ONEWAY, |
41 | | VARLINK_PROCESSED_METHOD, |
42 | | VARLINK_PROCESSED_METHOD_MORE, |
43 | | VARLINK_PENDING_METHOD, |
44 | | VARLINK_PENDING_METHOD_MORE, |
45 | | |
46 | | /* Common states (only during shutdown) */ |
47 | | VARLINK_PENDING_DISCONNECT, |
48 | | VARLINK_PENDING_TIMEOUT, |
49 | | VARLINK_PROCESSING_DISCONNECT, |
50 | | VARLINK_PROCESSING_TIMEOUT, |
51 | | VARLINK_PROCESSING_FAILURE, |
52 | | VARLINK_DISCONNECTED, |
53 | | |
54 | | _VARLINK_STATE_MAX, |
55 | | _VARLINK_STATE_INVALID = -1 |
56 | | } VarlinkState; |
57 | | |
58 | | /* Tests whether we are not yet disconnected. Note that this is true during all states where the connection |
59 | | * is still good for something, and false only when it's dead for good. This means: when we are |
60 | | * asynchronously connecting to a peer and the connect() is still pending, then this will return 'true', as |
61 | | * the connection is still good, and we are likely to be able to properly operate on it soon. */ |
62 | | #define VARLINK_STATE_IS_ALIVE(state) \ |
63 | 2.28M | IN_SET(state, \ |
64 | 7.59k | VARLINK_IDLE_CLIENT, \ |
65 | 7.59k | VARLINK_AWAITING_REPLY, \ |
66 | 7.59k | VARLINK_CALLING, \ |
67 | 7.59k | VARLINK_CALLED, \ |
68 | 7.59k | VARLINK_PROCESSING_REPLY, \ |
69 | 7.59k | VARLINK_IDLE_SERVER, \ |
70 | 7.59k | VARLINK_PROCESSING_METHOD, \ |
71 | 7.59k | VARLINK_PROCESSING_METHOD_MORE, \ |
72 | 7.59k | VARLINK_PROCESSING_METHOD_ONEWAY, \ |
73 | 7.59k | VARLINK_PROCESSED_METHOD, \ |
74 | 7.59k | VARLINK_PROCESSED_METHOD_MORE, \ |
75 | 7.59k | VARLINK_PENDING_METHOD, \ |
76 | 7.59k | VARLINK_PENDING_METHOD_MORE) |
77 | | |
78 | | struct Varlink { |
79 | | unsigned n_ref; |
80 | | |
81 | | VarlinkServer *server; |
82 | | |
83 | | VarlinkState state; |
84 | | bool connecting; /* This boolean indicates whether the socket fd we are operating on is currently |
85 | | * processing an asynchronous connect(). In that state we watch the socket for |
86 | | * EPOLLOUT, but we refrain from calling read() or write() on the socket as that |
87 | | * will trigger ENOTCONN. Note that this boolean is kept separate from the |
88 | | * VarlinkState above on purpose: while the connect() is still not complete we |
89 | | * already want to allow queuing of messages and similar. Thus it's nice to keep |
90 | | * these two state concepts separate: the VarlinkState encodes what our own view of |
91 | | * the connection is, i.e. whether we think it's a server, a client, and has |
92 | | * something queued already, while 'connecting' tells us a detail about the |
93 | | * transport used below, that should have no effect on how we otherwise accept and |
94 | | * process operations from the user. |
95 | | * |
96 | | * Or to say this differently: VARLINK_STATE_IS_ALIVE(state) tells you whether the |
97 | | * connection is good to use, even if it might not be fully connected |
98 | | * yet. connecting=true then informs you that actually we are still connecting, and |
99 | | * the connection is actually not established yet and thus any requests you enqueue |
100 | | * now will still work fine but will be queued only, not sent yet, but that |
101 | | * shouldn't stop you from using the connection, since eventually whatever you queue |
102 | | * *will* be sent. |
103 | | * |
104 | | * Or to say this even differently: 'state' is a high-level ("application layer" |
105 | | * high, if you so will) state, while 'conecting' is a low-level ("transport layer" |
106 | | * low, if you so will) state, and while they are not entirely unrelated and |
107 | | * sometimes propagate effects to each other they are only asynchronously connected |
108 | | * at most. */ |
109 | | unsigned n_pending; |
110 | | |
111 | | int fd; |
112 | | |
113 | | char *input_buffer; /* valid data starts at input_buffer_index, ends at input_buffer_index+input_buffer_size */ |
114 | | size_t input_buffer_allocated; |
115 | | size_t input_buffer_index; |
116 | | size_t input_buffer_size; |
117 | | size_t input_buffer_unscanned; |
118 | | |
119 | | char *output_buffer; /* valid data starts at output_buffer_index, ends at output_buffer_index+output_buffer_size */ |
120 | | size_t output_buffer_allocated; |
121 | | size_t output_buffer_index; |
122 | | size_t output_buffer_size; |
123 | | |
124 | | VarlinkReply reply_callback; |
125 | | |
126 | | JsonVariant *current; |
127 | | JsonVariant *reply; |
128 | | |
129 | | struct ucred ucred; |
130 | | bool ucred_acquired:1; |
131 | | |
132 | | bool write_disconnected:1; |
133 | | bool read_disconnected:1; |
134 | | bool prefer_read_write:1; |
135 | | bool got_pollhup:1; |
136 | | |
137 | | usec_t timestamp; |
138 | | usec_t timeout; |
139 | | |
140 | | void *userdata; |
141 | | char *description; |
142 | | |
143 | | sd_event *event; |
144 | | sd_event_source *io_event_source; |
145 | | sd_event_source *time_event_source; |
146 | | sd_event_source *quit_event_source; |
147 | | sd_event_source *defer_event_source; |
148 | | }; |
149 | | |
150 | | typedef struct VarlinkServerSocket VarlinkServerSocket; |
151 | | |
152 | | struct VarlinkServerSocket { |
153 | | VarlinkServer *server; |
154 | | |
155 | | int fd; |
156 | | char *address; |
157 | | |
158 | | sd_event_source *event_source; |
159 | | |
160 | | LIST_FIELDS(VarlinkServerSocket, sockets); |
161 | | }; |
162 | | |
163 | | struct VarlinkServer { |
164 | | unsigned n_ref; |
165 | | VarlinkServerFlags flags; |
166 | | |
167 | | LIST_HEAD(VarlinkServerSocket, sockets); |
168 | | |
169 | | Hashmap *methods; |
170 | | VarlinkConnect connect_callback; |
171 | | |
172 | | sd_event *event; |
173 | | int64_t event_priority; |
174 | | |
175 | | unsigned n_connections; |
176 | | Hashmap *by_uid; |
177 | | |
178 | | void *userdata; |
179 | | char *description; |
180 | | |
181 | | unsigned connections_max; |
182 | | unsigned connections_per_uid_max; |
183 | | }; |
184 | | |
185 | | static const char* const varlink_state_table[_VARLINK_STATE_MAX] = { |
186 | | [VARLINK_IDLE_CLIENT] = "idle-client", |
187 | | [VARLINK_AWAITING_REPLY] = "awaiting-reply", |
188 | | [VARLINK_CALLING] = "calling", |
189 | | [VARLINK_CALLED] = "called", |
190 | | [VARLINK_PROCESSING_REPLY] = "processing-reply", |
191 | | [VARLINK_IDLE_SERVER] = "idle-server", |
192 | | [VARLINK_PROCESSING_METHOD] = "processing-method", |
193 | | [VARLINK_PROCESSING_METHOD_MORE] = "processing-method-more", |
194 | | [VARLINK_PROCESSING_METHOD_ONEWAY] = "processing-method-oneway", |
195 | | [VARLINK_PROCESSED_METHOD] = "processed-method", |
196 | | [VARLINK_PROCESSED_METHOD_MORE] = "processed-method-more", |
197 | | [VARLINK_PENDING_METHOD] = "pending-method", |
198 | | [VARLINK_PENDING_METHOD_MORE] = "pending-method-more", |
199 | | [VARLINK_PENDING_DISCONNECT] = "pending-disconnect", |
200 | | [VARLINK_PENDING_TIMEOUT] = "pending-timeout", |
201 | | [VARLINK_PROCESSING_DISCONNECT] = "processing-disconnect", |
202 | | [VARLINK_PROCESSING_TIMEOUT] = "processing-timeout", |
203 | | [VARLINK_PROCESSING_FAILURE] = "processing-failure", |
204 | | [VARLINK_DISCONNECTED] = "disconnected", |
205 | | }; |
206 | | |
207 | | DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(varlink_state, VarlinkState); |
208 | | |
209 | | #define varlink_log_errno(v, error, fmt, ...) \ |
210 | 0 | log_debug_errno(error, "%s: " fmt, varlink_description(v), ##__VA_ARGS__) |
211 | | |
212 | | #define varlink_log(v, fmt, ...) \ |
213 | 4.71M | log_debug("%s: " fmt, varlink_description(v), ##__VA_ARGS__) |
214 | | |
215 | | #define varlink_server_log_errno(s, error, fmt, ...) \ |
216 | 0 | log_debug_errno(error, "%s: " fmt, varlink_server_description(s), ##__VA_ARGS__) |
217 | | |
218 | | #define varlink_server_log(s, fmt, ...) \ |
219 | 0 | log_debug("%s: " fmt, varlink_server_description(s), ##__VA_ARGS__) |
220 | | |
221 | 0 | static inline const char *varlink_description(Varlink *v) { |
222 | 0 | return strna(v ? v->description : NULL); |
223 | 0 | } |
224 | | |
225 | 0 | static inline const char *varlink_server_description(VarlinkServer *s) { |
226 | 0 | return strna(s ? s->description : NULL); |
227 | 0 | } |
228 | | |
229 | 1.76M | static void varlink_set_state(Varlink *v, VarlinkState state) { |
230 | 1.76M | assert(v); |
231 | 1.76M | assert(state >= 0 && state < _VARLINK_STATE_MAX); |
232 | 1.76M | |
233 | 1.76M | if (v->state < 0) |
234 | 1.76M | varlink_log(v, "varlink: setting state %s", |
235 | 1.76M | varlink_state_to_string(state)); |
236 | 1.76M | else |
237 | 1.76M | varlink_log(v, "varlink: changing state %s → %s", |
238 | 1.76M | varlink_state_to_string(v->state), |
239 | 1.76M | varlink_state_to_string(state)); |
240 | 1.76M | |
241 | 1.76M | v->state = state; |
242 | 1.76M | } |
243 | | |
244 | 7.38k | static int varlink_new(Varlink **ret) { |
245 | 7.38k | Varlink *v; |
246 | 7.38k | |
247 | 7.38k | assert(ret); |
248 | 7.38k | |
249 | 7.38k | v = new(Varlink, 1); |
250 | 7.38k | if (!v) |
251 | 0 | return -ENOMEM; |
252 | 7.38k | |
253 | 7.38k | *v = (Varlink) { |
254 | 7.38k | .n_ref = 1, |
255 | 7.38k | .fd = -1, |
256 | 7.38k | |
257 | 7.38k | .state = _VARLINK_STATE_INVALID, |
258 | 7.38k | |
259 | 7.38k | .ucred.uid = UID_INVALID, |
260 | 7.38k | .ucred.gid = GID_INVALID, |
261 | 7.38k | |
262 | 7.38k | .timestamp = USEC_INFINITY, |
263 | 7.38k | .timeout = VARLINK_DEFAULT_TIMEOUT_USEC |
264 | 7.38k | }; |
265 | 7.38k | |
266 | 7.38k | *ret = v; |
267 | 7.38k | return 0; |
268 | 7.38k | } |
269 | | |
270 | 0 | int varlink_connect_address(Varlink **ret, const char *address) { |
271 | 0 | _cleanup_(varlink_unrefp) Varlink *v = NULL; |
272 | 0 | union sockaddr_union sockaddr; |
273 | 0 | int r; |
274 | 0 |
|
275 | 0 | assert_return(ret, -EINVAL); |
276 | 0 | assert_return(address, -EINVAL); |
277 | 0 |
|
278 | 0 | r = sockaddr_un_set_path(&sockaddr.un, address); |
279 | 0 | if (r < 0) |
280 | 0 | return r; |
281 | 0 | |
282 | 0 | r = varlink_new(&v); |
283 | 0 | if (r < 0) |
284 | 0 | return r; |
285 | 0 | |
286 | 0 | v->fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); |
287 | 0 | if (v->fd < 0) |
288 | 0 | return -errno; |
289 | 0 | |
290 | 0 | if (connect(v->fd, &sockaddr.sa, SOCKADDR_UN_LEN(sockaddr.un)) < 0) { |
291 | 0 | if (!IN_SET(errno, EAGAIN, EINPROGRESS)) |
292 | 0 | return -errno; |
293 | 0 | |
294 | 0 | v->connecting = true; /* We are asynchronously connecting, i.e. the connect() is being |
295 | 0 | * processed in the background. As long as that's the case the socket |
296 | 0 | * is in a special state: it's there, we can poll it for EPOLLOUT, but |
297 | 0 | * if we attempt to write() to it before we see EPOLLOUT we'll get |
298 | 0 | * ENOTCONN (and not EAGAIN, like we would for a normal connected |
299 | 0 | * socket that isn't writable at the moment). Since ENOTCONN on write() |
300 | 0 | * hence can mean two different things (i.e. connection not complete |
301 | 0 | * yet vs. already disconnected again), we store as a boolean whether |
302 | 0 | * we are still in connect(). */ |
303 | 0 | } |
304 | 0 |
|
305 | 0 | varlink_set_state(v, VARLINK_IDLE_CLIENT); |
306 | 0 |
|
307 | 0 | *ret = TAKE_PTR(v); |
308 | 0 | return r; |
309 | 0 | } |
310 | | |
311 | 3.69k | int varlink_connect_fd(Varlink **ret, int fd) { |
312 | 3.69k | Varlink *v; |
313 | 3.69k | int r; |
314 | 3.69k | |
315 | 3.69k | assert_return(ret, -EINVAL); |
316 | 3.69k | assert_return(fd >= 0, -EBADF); |
317 | 3.69k | |
318 | 3.69k | r = fd_nonblock(fd, true); |
319 | 3.69k | if (r < 0) |
320 | 0 | return r; |
321 | 3.69k | |
322 | 3.69k | r = varlink_new(&v); |
323 | 3.69k | if (r < 0) |
324 | 0 | return r; |
325 | 3.69k | |
326 | 3.69k | v->fd = fd; |
327 | 3.69k | varlink_set_state(v, VARLINK_IDLE_CLIENT); |
328 | 3.69k | |
329 | 3.69k | /* Note that if this function is called we assume the passed socket (if it is one) is already |
330 | 3.69k | * properly connected, i.e. any asynchronous connect() done on it already completed. Because of that |
331 | 3.69k | * we'll not set the 'connecting' boolean here, i.e. we don't need to avoid write()ing to the socket |
332 | 3.69k | * until the connection is fully set up. Behaviour here is hence a bit different from |
333 | 3.69k | * varlink_connect_address() above, as there we do handle asynchronous connections ourselves and |
334 | 3.69k | * avoid doing write() on it before we saw EPOLLOUT for the first time. */ |
335 | 3.69k | |
336 | 3.69k | *ret = v; |
337 | 3.69k | return 0; |
338 | 3.69k | } |
339 | | |
340 | 14.7k | static void varlink_detach_event_sources(Varlink *v) { |
341 | 14.7k | assert(v); |
342 | 14.7k | |
343 | 14.7k | v->io_event_source = sd_event_source_disable_unref(v->io_event_source); |
344 | 14.7k | |
345 | 14.7k | v->time_event_source = sd_event_source_disable_unref(v->time_event_source); |
346 | 14.7k | |
347 | 14.7k | v->quit_event_source = sd_event_source_disable_unref(v->quit_event_source); |
348 | 14.7k | |
349 | 14.7k | v->defer_event_source = sd_event_source_disable_unref(v->defer_event_source); |
350 | 14.7k | } |
351 | | |
352 | 14.7k | static void varlink_clear(Varlink *v) { |
353 | 14.7k | assert(v); |
354 | 14.7k | |
355 | 14.7k | varlink_detach_event_sources(v); |
356 | 14.7k | |
357 | 14.7k | v->fd = safe_close(v->fd); |
358 | 14.7k | |
359 | 14.7k | v->input_buffer = mfree(v->input_buffer); |
360 | 14.7k | v->output_buffer = mfree(v->output_buffer); |
361 | 14.7k | |
362 | 14.7k | v->current = json_variant_unref(v->current); |
363 | 14.7k | v->reply = json_variant_unref(v->reply); |
364 | 14.7k | |
365 | 14.7k | v->event = sd_event_unref(v->event); |
366 | 14.7k | } |
367 | | |
368 | 7.38k | static Varlink* varlink_destroy(Varlink *v) { |
369 | 7.38k | if (!v) |
370 | 0 | return NULL; |
371 | 7.38k | |
372 | 7.38k | /* If this is called the server object must already been unreffed here. Why that? because when we |
373 | 7.38k | * linked up the varlink connection with the server object we took one ref in each direction */ |
374 | 7.38k | assert(!v->server); |
375 | 7.38k | |
376 | 7.38k | varlink_clear(v); |
377 | 7.38k | |
378 | 7.38k | free(v->description); |
379 | 7.38k | return mfree(v); |
380 | 7.38k | } |
381 | | |
382 | | DEFINE_TRIVIAL_REF_UNREF_FUNC(Varlink, varlink, varlink_destroy); |
383 | | |
384 | 335k | static int varlink_test_disconnect(Varlink *v) { |
385 | 335k | assert(v); |
386 | 335k | |
387 | 335k | /* Tests whether we the the connection has been terminated. We are careful to not stop processing it |
388 | 335k | * prematurely, since we want to handle half-open connections as well as possible and want to flush |
389 | 335k | * out and read data before we close down if we can. */ |
390 | 335k | |
391 | 335k | /* Already disconnected? */ |
392 | 335k | if (!VARLINK_STATE_IS_ALIVE(v->state)) |
393 | 335k | return 0; |
394 | 335k | |
395 | 335k | /* Wait until connection setup is complete, i.e. until asynchronous connect() completes */ |
396 | 335k | if (v->connecting) |
397 | 0 | return 0; |
398 | 335k | |
399 | 335k | /* Still something to write and we can write? Stay around */ |
400 | 335k | if (v->output_buffer_size > 0 && !v->write_disconnected) |
401 | 49.7k | return 0; |
402 | 286k | |
403 | 286k | /* Both sides gone already? Then there's no need to stick around */ |
404 | 286k | if (v->read_disconnected && v->write_disconnected) |
405 | 0 | goto disconnect; |
406 | 286k | |
407 | 286k | /* If we are waiting for incoming data but the read side is shut down, disconnect. */ |
408 | 286k | if (IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING, VARLINK_IDLE_SERVER) && v->read_disconnected) |
409 | 0 | goto disconnect; |
410 | 286k | |
411 | 286k | /* Similar, if are a client that hasn't written anything yet but the write side is dead, also |
412 | 286k | * disconnect. We also explicitly check for POLLHUP here since we likely won't notice the write side |
413 | 286k | * being down if we never wrote anything. */ |
414 | 286k | if (IN_SET(v->state, VARLINK_IDLE_CLIENT) && (v->write_disconnected || v->got_pollhup)) |
415 | 0 | goto disconnect; |
416 | 286k | |
417 | 286k | return 0; |
418 | 0 | |
419 | 0 | disconnect: |
420 | 0 | varlink_set_state(v, VARLINK_PENDING_DISCONNECT); |
421 | 0 | return 1; |
422 | 286k | } |
423 | | |
424 | 1.93M | static int varlink_write(Varlink *v) { |
425 | 1.93M | ssize_t n; |
426 | 1.93M | |
427 | 1.93M | assert(v); |
428 | 1.93M | |
429 | 1.93M | if (!VARLINK_STATE_IS_ALIVE(v->state)) |
430 | 1.93M | return 0; |
431 | 1.93M | if (v->connecting) /* Writing while we are still wait for a non-blocking connect() to complete will |
432 | 0 | * result in ENOTCONN, hence exit early here */ |
433 | 0 | return 0; |
434 | 1.93M | if (v->output_buffer_size == 0) |
435 | 764k | return 0; |
436 | 1.17M | if (v->write_disconnected) |
437 | 0 | return 0; |
438 | 1.17M | |
439 | 1.17M | assert(v->fd >= 0); |
440 | 1.17M | |
441 | 1.17M | /* We generally prefer recv()/send() (mostly because of MSG_NOSIGNAL) but also want to be compatible |
442 | 1.17M | * with non-socket IO, hence fall back automatically */ |
443 | 1.17M | if (!v->prefer_read_write) { |
444 | 1.17M | n = send(v->fd, v->output_buffer + v->output_buffer_index, v->output_buffer_size, MSG_DONTWAIT|MSG_NOSIGNAL); |
445 | 1.17M | if (n < 0 && errno == ENOTSOCK) |
446 | 1.17M | v->prefer_read_write = true; |
447 | 1.17M | } |
448 | 1.17M | if (v->prefer_read_write) |
449 | 0 | n = write(v->fd, v->output_buffer + v->output_buffer_index, v->output_buffer_size); |
450 | 1.17M | if (n < 0) { |
451 | 1.07M | if (errno == EAGAIN) |
452 | 1.07M | return 0; |
453 | 0 | |
454 | 0 | if (ERRNO_IS_DISCONNECT(errno)) { |
455 | 0 | /* If we get informed about a disconnect on write, then let's remember that, but not |
456 | 0 | * act on it just yet. Let's wait for read() to report the issue first. */ |
457 | 0 | v->write_disconnected = true; |
458 | 0 | return 1; |
459 | 0 | } |
460 | 0 | |
461 | 0 | return -errno; |
462 | 0 | } |
463 | 93.0k | |
464 | 93.0k | v->output_buffer_size -= n; |
465 | 93.0k | |
466 | 93.0k | if (v->output_buffer_size == 0) |
467 | 92.5k | v->output_buffer_index = 0; |
468 | 497 | else |
469 | 497 | v->output_buffer_index += n; |
470 | 93.0k | |
471 | 93.0k | v->timestamp = now(CLOCK_MONOTONIC); |
472 | 93.0k | return 1; |
473 | 93.0k | } |
474 | | |
475 | 671k | static int varlink_read(Varlink *v) { |
476 | 671k | size_t rs; |
477 | 671k | ssize_t n; |
478 | 671k | |
479 | 671k | assert(v); |
480 | 671k | |
481 | 671k | if (!IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING, VARLINK_IDLE_SERVER)) |
482 | 671k | return 0; |
483 | 670k | if (v->connecting) /* read() on a socket while we are in connect() will fail with EINVAL, hence exit early here */ |
484 | 0 | return 0; |
485 | 670k | if (v->current) |
486 | 0 | return 0; |
487 | 670k | if (v->input_buffer_unscanned > 0) |
488 | 0 | return 0; |
489 | 670k | if (v->read_disconnected) |
490 | 0 | return 0; |
491 | 670k | |
492 | 670k | if (v->input_buffer_size >= VARLINK_BUFFER_MAX) |
493 | 670k | return -ENOBUFS; |
494 | 670k | |
495 | 670k | assert(v->fd >= 0); |
496 | 670k | |
497 | 670k | if (v->input_buffer_allocated <= v->input_buffer_index + v->input_buffer_size) { |
498 | 7.59k | size_t add; |
499 | 7.59k | |
500 | 7.59k | add = MIN(VARLINK_BUFFER_MAX - v->input_buffer_size, VARLINK_READ_SIZE); |
501 | 7.59k | |
502 | 7.59k | if (v->input_buffer_index == 0) { |
503 | 7.52k | |
504 | 7.52k | if (!GREEDY_REALLOC(v->input_buffer, v->input_buffer_allocated, v->input_buffer_size + add)) |
505 | 7.52k | return -ENOMEM; |
506 | 67 | |
507 | 67 | } else { |
508 | 67 | char *b; |
509 | 67 | |
510 | 67 | b = new(char, v->input_buffer_size + add); |
511 | 67 | if (!b) |
512 | 0 | return -ENOMEM; |
513 | 67 | |
514 | 67 | memcpy(b, v->input_buffer + v->input_buffer_index, v->input_buffer_size); |
515 | 67 | |
516 | 67 | free_and_replace(v->input_buffer, b); |
517 | 67 | |
518 | 67 | v->input_buffer_allocated = v->input_buffer_size + add; |
519 | 67 | v->input_buffer_index = 0; |
520 | 67 | } |
521 | 7.59k | } |
522 | 670k | |
523 | 670k | rs = v->input_buffer_allocated - (v->input_buffer_index + v->input_buffer_size); |
524 | 670k | |
525 | 670k | if (!v->prefer_read_write) { |
526 | 670k | n = recv(v->fd, v->input_buffer + v->input_buffer_index + v->input_buffer_size, rs, MSG_DONTWAIT); |
527 | 670k | if (n < 0 && errno == ENOTSOCK) |
528 | 670k | v->prefer_read_write = true; |
529 | 670k | } |
530 | 670k | if (v->prefer_read_write) |
531 | 0 | n = read(v->fd, v->input_buffer + v->input_buffer_index + v->input_buffer_size, rs); |
532 | 670k | if (n < 0) { |
533 | 335k | if (errno == EAGAIN) |
534 | 335k | return 0; |
535 | 0 | |
536 | 0 | if (ERRNO_IS_DISCONNECT(errno)) { |
537 | 0 | v->read_disconnected = true; |
538 | 0 | return 1; |
539 | 0 | } |
540 | 0 | |
541 | 0 | return -errno; |
542 | 0 | } |
543 | 335k | if (n == 0) { /* EOF */ |
544 | 0 | v->read_disconnected = true; |
545 | 0 | return 1; |
546 | 0 | } |
547 | 335k | |
548 | 335k | v->input_buffer_size += n; |
549 | 335k | v->input_buffer_unscanned += n; |
550 | 335k | |
551 | 335k | return 1; |
552 | 335k | } |
553 | | |
554 | 1.26M | static int varlink_parse_message(Varlink *v) { |
555 | 1.26M | const char *e, *begin; |
556 | 1.26M | size_t sz; |
557 | 1.26M | int r; |
558 | 1.26M | |
559 | 1.26M | assert(v); |
560 | 1.26M | |
561 | 1.26M | if (v->current) |
562 | 128 | return 0; |
563 | 1.26M | if (v->input_buffer_unscanned <= 0) |
564 | 344k | return 0; |
565 | 916k | |
566 | 916k | assert(v->input_buffer_unscanned <= v->input_buffer_size); |
567 | 916k | assert(v->input_buffer_index + v->input_buffer_size <= v->input_buffer_allocated); |
568 | 916k | |
569 | 916k | begin = v->input_buffer + v->input_buffer_index; |
570 | 916k | |
571 | 916k | e = memchr(begin + v->input_buffer_size - v->input_buffer_unscanned, 0, v->input_buffer_unscanned); |
572 | 916k | if (!e) { |
573 | 326k | v->input_buffer_unscanned = 0; |
574 | 326k | return 0; |
575 | 326k | } |
576 | 590k | |
577 | 590k | sz = e - begin + 1; |
578 | 590k | |
579 | 590k | varlink_log(v, "New incoming message: %s", begin); |
580 | 590k | |
581 | 590k | r = json_parse(begin, &v->current, NULL, NULL); |
582 | 590k | if (r < 0) |
583 | 6.42k | return r; |
584 | 584k | |
585 | 584k | v->input_buffer_size -= sz; |
586 | 584k | |
587 | 584k | if (v->input_buffer_size == 0) |
588 | 4.25k | v->input_buffer_index = 0; |
589 | 580k | else |
590 | 580k | v->input_buffer_index += sz; |
591 | 584k | |
592 | 584k | v->input_buffer_unscanned = v->input_buffer_size; |
593 | 584k | return 1; |
594 | 584k | } |
595 | | |
596 | 335k | static int varlink_test_timeout(Varlink *v) { |
597 | 335k | assert(v); |
598 | 335k | |
599 | 335k | if (!IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING)) |
600 | 335k | return 0; |
601 | 119k | if (v->timeout == USEC_INFINITY) |
602 | 119k | return 0; |
603 | 119k | |
604 | 119k | if (now(CLOCK_MONOTONIC) < usec_add(v->timestamp, v->timeout)) |
605 | 119k | return 0; |
606 | 0 | |
607 | 0 | varlink_set_state(v, VARLINK_PENDING_TIMEOUT); |
608 | 0 |
|
609 | 0 | return 1; |
610 | 0 | } |
611 | | |
612 | 3.20k | static int varlink_dispatch_local_error(Varlink *v, const char *error) { |
613 | 3.20k | int r; |
614 | 3.20k | |
615 | 3.20k | assert(v); |
616 | 3.20k | assert(error); |
617 | 3.20k | |
618 | 3.20k | if (!v->reply_callback) |
619 | 1.16k | return 0; |
620 | 2.03k | |
621 | 2.03k | r = v->reply_callback(v, NULL, error, VARLINK_REPLY_ERROR|VARLINK_REPLY_LOCAL, v->userdata); |
622 | 2.03k | if (r < 0) |
623 | 2.03k | log_debug_errno(r, "Reply callback returned error, ignoring: %m"); |
624 | 2.03k | |
625 | 2.03k | return 1; |
626 | 2.03k | } |
627 | | |
628 | 335k | static int varlink_dispatch_timeout(Varlink *v) { |
629 | 335k | assert(v); |
630 | 335k | |
631 | 335k | if (v->state != VARLINK_PENDING_TIMEOUT) |
632 | 335k | return 0; |
633 | 0 | |
634 | 0 | varlink_set_state(v, VARLINK_PROCESSING_TIMEOUT); |
635 | 0 | varlink_dispatch_local_error(v, VARLINK_ERROR_TIMEOUT); |
636 | 0 | varlink_close(v); |
637 | 0 |
|
638 | 0 | return 1; |
639 | 0 | } |
640 | | |
641 | 335k | static int varlink_dispatch_disconnect(Varlink *v) { |
642 | 335k | assert(v); |
643 | 335k | |
644 | 335k | if (v->state != VARLINK_PENDING_DISCONNECT) |
645 | 335k | return 0; |
646 | 0 | |
647 | 0 | varlink_set_state(v, VARLINK_PROCESSING_DISCONNECT); |
648 | 0 | varlink_dispatch_local_error(v, VARLINK_ERROR_DISCONNECTED); |
649 | 0 | varlink_close(v); |
650 | 0 |
|
651 | 0 | return 1; |
652 | 0 | } |
653 | | |
654 | 1.16M | static int varlink_sanitize_parameters(JsonVariant **v) { |
655 | 1.16M | assert(v); |
656 | 1.16M | |
657 | 1.16M | /* Varlink always wants a parameters list, hence make one if the caller doesn't want any */ |
658 | 1.16M | if (!*v) |
659 | 584k | return json_variant_new_object(v, NULL, 0); |
660 | 580k | else if (!json_variant_is_object(*v)) |
661 | 0 | return -EINVAL; |
662 | 580k | |
663 | 580k | return 0; |
664 | 580k | } |
665 | | |
666 | 1.84M | static int varlink_dispatch_reply(Varlink *v) { |
667 | 1.84M | _cleanup_(json_variant_unrefp) JsonVariant *parameters = NULL; |
668 | 1.84M | VarlinkReplyFlags flags = 0; |
669 | 1.84M | const char *error = NULL; |
670 | 1.84M | JsonVariant *e; |
671 | 1.84M | const char *k; |
672 | 1.84M | int r; |
673 | 1.84M | |
674 | 1.84M | assert(v); |
675 | 1.84M | |
676 | 1.84M | if (!IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING)) |
677 | 1.84M | return 0; |
678 | 244k | if (!v->current) |
679 | 242k | return 0; |
680 | 2.28k | |
681 | 2.28k | assert(v->n_pending > 0); |
682 | 2.28k | |
683 | 2.28k | if (!json_variant_is_object(v->current)) |
684 | 546 | goto invalid; |
685 | 1.73k | |
686 | 1.73k | JSON_VARIANT_OBJECT_FOREACH(k, e, v->current) { |
687 | 1.56k | |
688 | 1.56k | if (streq(k, "error")) { |
689 | 12 | if (error) |
690 | 1 | goto invalid; |
691 | 11 | if (!json_variant_is_string(e)) |
692 | 1 | goto invalid; |
693 | 10 | |
694 | 10 | error = json_variant_string(e); |
695 | 10 | flags |= VARLINK_REPLY_ERROR; |
696 | 10 | |
697 | 1.55k | } else if (streq(k, "parameters")) { |
698 | 66 | if (parameters) |
699 | 1 | goto invalid; |
700 | 65 | if (!json_variant_is_object(e)) |
701 | 1 | goto invalid; |
702 | 64 | |
703 | 64 | parameters = json_variant_ref(e); |
704 | 64 | |
705 | 1.48k | } else if (streq(k, "continues")) { |
706 | 1 | if (FLAGS_SET(flags, VARLINK_REPLY_CONTINUES)) |
707 | 1 | goto invalid; |
708 | 1 | |
709 | 1 | if (!json_variant_is_boolean(e)) |
710 | 1 | goto invalid; |
711 | 0 | |
712 | 0 | if (json_variant_boolean(e)) |
713 | 0 | flags |= VARLINK_REPLY_CONTINUES; |
714 | 0 | } else |
715 | 1.48k | goto invalid; |
716 | 1.56k | } |
717 | 1.73k | |
718 | 1.73k | if (error && FLAGS_SET(flags, VARLINK_REPLY_CONTINUES)) |
719 | 242 | goto invalid; |
720 | 242 | |
721 | 242 | r = varlink_sanitize_parameters(¶meters); |
722 | 242 | if (r < 0) |
723 | 0 | goto invalid; |
724 | 242 | |
725 | 242 | if (v->state == VARLINK_AWAITING_REPLY) { |
726 | 242 | varlink_set_state(v, VARLINK_PROCESSING_REPLY); |
727 | 242 | |
728 | 242 | if (v->reply_callback) { |
729 | 242 | r = v->reply_callback(v, parameters, error, flags, v->userdata); |
730 | 242 | if (r < 0) |
731 | 242 | log_debug_errno(r, "Reply callback returned error, ignoring: %m"); |
732 | 242 | } |
733 | 242 | |
734 | 242 | v->current = json_variant_unref(v->current); |
735 | 242 | |
736 | 242 | if (v->state == VARLINK_PROCESSING_REPLY) { |
737 | 242 | assert(v->n_pending > 0); |
738 | 242 | v->n_pending--; |
739 | 242 | |
740 | 242 | varlink_set_state(v, v->n_pending == 0 ? VARLINK_IDLE_CLIENT : VARLINK_AWAITING_REPLY); |
741 | 242 | } |
742 | 242 | } else { |
743 | 0 | assert(v->state == VARLINK_CALLING); |
744 | 0 |
|
745 | 0 | if (FLAGS_SET(flags, VARLINK_REPLY_CONTINUES)) |
746 | 0 | goto invalid; |
747 | 0 | |
748 | 0 | varlink_set_state(v, VARLINK_CALLED); |
749 | 0 | } |
750 | 242 | |
751 | 242 | return 1; |
752 | 2.03k | |
753 | 2.03k | invalid: |
754 | 2.03k | varlink_set_state(v, VARLINK_PROCESSING_FAILURE); |
755 | 2.03k | varlink_dispatch_local_error(v, VARLINK_ERROR_PROTOCOL); |
756 | 2.03k | varlink_close(v); |
757 | 2.03k | |
758 | 2.03k | return 1; |
759 | 242 | } |
760 | | |
761 | 1.84M | static int varlink_dispatch_method(Varlink *v) { |
762 | 1.84M | _cleanup_(json_variant_unrefp) JsonVariant *parameters = NULL; |
763 | 1.84M | VarlinkMethodFlags flags = 0; |
764 | 1.84M | const char *method = NULL, *error; |
765 | 1.84M | JsonVariant *e; |
766 | 1.84M | VarlinkMethod callback; |
767 | 1.84M | const char *k; |
768 | 1.84M | int r; |
769 | 1.84M | |
770 | 1.84M | assert(v); |
771 | 1.84M | |
772 | 1.84M | if (v->state != VARLINK_IDLE_SERVER) |
773 | 245k | return 0; |
774 | 1.59M | if (!v->current) |
775 | 1.01M | return 0; |
776 | 581k | |
777 | 581k | if (!json_variant_is_object(v->current)) |
778 | 566 | goto invalid; |
779 | 581k | |
780 | 581k | JSON_VARIANT_OBJECT_FOREACH(k, e, v->current) { |
781 | 581k | |
782 | 581k | if (streq(k, "method")) { |
783 | 580k | if (method) |
784 | 1 | goto invalid; |
785 | 580k | if (!json_variant_is_string(e)) |
786 | 5 | goto invalid; |
787 | 580k | |
788 | 580k | method = json_variant_string(e); |
789 | 580k | |
790 | 580k | } else if (streq(k, "parameters")) { |
791 | 159 | if (parameters) |
792 | 1 | goto invalid; |
793 | 158 | if (!json_variant_is_object(e)) |
794 | 1 | goto invalid; |
795 | 157 | |
796 | 157 | parameters = json_variant_ref(e); |
797 | 157 | |
798 | 347 | } else if (streq(k, "oneway")) { |
799 | 1 | |
800 | 1 | if ((flags & (VARLINK_METHOD_ONEWAY|VARLINK_METHOD_MORE)) != 0) |
801 | 0 | goto invalid; |
802 | 1 | |
803 | 1 | if (!json_variant_is_boolean(e)) |
804 | 1 | goto invalid; |
805 | 0 | |
806 | 0 | if (json_variant_boolean(e)) |
807 | 0 | flags |= VARLINK_METHOD_ONEWAY; |
808 | 0 |
|
809 | 346 | } else if (streq(k, "more")) { |
810 | 1 | |
811 | 1 | if ((flags & (VARLINK_METHOD_ONEWAY|VARLINK_METHOD_MORE)) != 0) |
812 | 0 | goto invalid; |
813 | 1 | |
814 | 1 | if (!json_variant_is_boolean(e)) |
815 | 1 | goto invalid; |
816 | 0 | |
817 | 0 | if (json_variant_boolean(e)) |
818 | 0 | flags |= VARLINK_METHOD_MORE; |
819 | 0 |
|
820 | 0 | } else |
821 | 345 | goto invalid; |
822 | 581k | } |
823 | 581k | |
824 | 581k | if (!method) |
825 | 246 | goto invalid; |
826 | 580k | |
827 | 580k | r = varlink_sanitize_parameters(¶meters); |
828 | 580k | if (r < 0) |
829 | 0 | goto fail; |
830 | 580k | |
831 | 580k | varlink_set_state(v, (flags & VARLINK_METHOD_MORE) ? VARLINK_PROCESSING_METHOD_MORE : |
832 | 580k | (flags & VARLINK_METHOD_ONEWAY) ? VARLINK_PROCESSING_METHOD_ONEWAY : |
833 | 580k | VARLINK_PROCESSING_METHOD); |
834 | 580k | |
835 | 580k | assert(v->server); |
836 | 580k | |
837 | 580k | if (STR_IN_SET(method, "org.varlink.service.GetInfo", "org.varlink.service.GetInterface")) { |
838 | 231 | /* For now, we don't implement a single of varlink's own methods */ |
839 | 231 | callback = NULL; |
840 | 231 | error = VARLINK_ERROR_METHOD_NOT_IMPLEMENTED; |
841 | 580k | } else if (startswith(method, "org.varlink.service.")) { |
842 | 403 | callback = NULL; |
843 | 403 | error = VARLINK_ERROR_METHOD_NOT_FOUND; |
844 | 580k | } else { |
845 | 580k | callback = hashmap_get(v->server->methods, method); |
846 | 580k | error = VARLINK_ERROR_METHOD_NOT_FOUND; |
847 | 580k | } |
848 | 580k | |
849 | 580k | if (callback) { |
850 | 9 | r = callback(v, parameters, flags, v->userdata); |
851 | 9 | if (r < 0) { |
852 | 0 | log_debug_errno(r, "Callback for %s returned error: %m", method); |
853 | 0 |
|
854 | 0 | /* We got an error back from the callback. Propagate it to the client if the method call remains unanswered. */ |
855 | 0 | if (!FLAGS_SET(flags, VARLINK_METHOD_ONEWAY)) { |
856 | 0 | r = varlink_errorb(v, VARLINK_ERROR_SYSTEM, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("errno", JSON_BUILD_INTEGER(-r)))); |
857 | 0 | if (r < 0) |
858 | 0 | return r; |
859 | 580k | } |
860 | 0 | } |
861 | 580k | } else if (!FLAGS_SET(flags, VARLINK_METHOD_ONEWAY)) { |
862 | 580k | assert(error); |
863 | 580k | |
864 | 580k | r = varlink_errorb(v, error, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("method", JSON_BUILD_STRING(method)))); |
865 | 580k | if (r < 0) |
866 | 0 | return r; |
867 | 580k | } |
868 | 580k | |
869 | 580k | switch (v->state) { |
870 | 580k | |
871 | 580k | case VARLINK_PROCESSED_METHOD: /* Method call is fully processed */ |
872 | 580k | case VARLINK_PROCESSING_METHOD_ONEWAY: /* ditto */ |
873 | 580k | v->current = json_variant_unref(v->current); |
874 | 580k | varlink_set_state(v, VARLINK_IDLE_SERVER); |
875 | 580k | break; |
876 | 580k | |
877 | 580k | case VARLINK_PROCESSING_METHOD: /* Method call wasn't replied to, will be replied to later */ |
878 | 9 | varlink_set_state(v, VARLINK_PENDING_METHOD); |
879 | 9 | break; |
880 | 580k | |
881 | 580k | case VARLINK_PROCESSED_METHOD_MORE: /* One reply for a "more" message was sent, more to come */ |
882 | 0 | case VARLINK_PROCESSING_METHOD_MORE: /* No reply for a "more" message was sent, more to come */ |
883 | 0 | varlink_set_state(v, VARLINK_PENDING_METHOD_MORE); |
884 | 0 | break; |
885 | 0 |
|
886 | 0 | default: |
887 | 0 | assert_not_reached("Unexpected state"); |
888 | 580k | |
889 | 580k | } |
890 | 580k | |
891 | 580k | return r; |
892 | 1.16k | |
893 | 1.16k | invalid: |
894 | 1.16k | r = -EINVAL; |
895 | 1.16k | |
896 | 1.16k | fail: |
897 | 1.16k | varlink_set_state(v, VARLINK_PROCESSING_FAILURE); |
898 | 1.16k | varlink_dispatch_local_error(v, VARLINK_ERROR_PROTOCOL); |
899 | 1.16k | varlink_close(v); |
900 | 1.16k | |
901 | 1.16k | return r; |
902 | 1.16k | } |
903 | | |
904 | 1.93M | int varlink_process(Varlink *v) { |
905 | 1.93M | int r; |
906 | 1.93M | |
907 | 1.93M | assert_return(v, -EINVAL); |
908 | 1.93M | |
909 | 1.93M | if (v->state == VARLINK_DISCONNECTED) |
910 | 0 | return -ENOTCONN; |
911 | 1.93M | |
912 | 1.93M | varlink_ref(v); |
913 | 1.93M | |
914 | 1.93M | r = varlink_write(v); |
915 | 1.93M | if (r != 0) |
916 | 93.0k | goto finish; |
917 | 1.84M | |
918 | 1.84M | r = varlink_dispatch_reply(v); |
919 | 1.84M | if (r != 0) |
920 | 2.28k | goto finish; |
921 | 1.84M | |
922 | 1.84M | r = varlink_dispatch_method(v); |
923 | 1.84M | if (r != 0) |
924 | 581k | goto finish; |
925 | 1.26M | |
926 | 1.26M | r = varlink_parse_message(v); |
927 | 1.26M | if (r != 0) |
928 | 590k | goto finish; |
929 | 671k | |
930 | 671k | r = varlink_read(v); |
931 | 671k | if (r != 0) |
932 | 335k | goto finish; |
933 | 335k | |
934 | 335k | r = varlink_test_disconnect(v); |
935 | 335k | if (r != 0) |
936 | 0 | goto finish; |
937 | 335k | |
938 | 335k | r = varlink_dispatch_disconnect(v); |
939 | 335k | if (r != 0) |
940 | 0 | goto finish; |
941 | 335k | |
942 | 335k | r = varlink_test_timeout(v); |
943 | 335k | if (r != 0) |
944 | 0 | goto finish; |
945 | 335k | |
946 | 335k | r = varlink_dispatch_timeout(v); |
947 | 335k | if (r != 0) |
948 | 0 | goto finish; |
949 | 1.93M | |
950 | 1.93M | finish: |
951 | 1.93M | if (r >= 0 && v->defer_event_source) { |
952 | 1.92M | int q; |
953 | 1.92M | |
954 | 1.92M | /* If we did some processing, make sure we are called again soon */ |
955 | 1.92M | q = sd_event_source_set_enabled(v->defer_event_source, r > 0 ? SD_EVENT_ON : SD_EVENT_OFF); |
956 | 1.92M | if (q < 0) |
957 | 0 | r = q; |
958 | 1.92M | } |
959 | 1.93M | |
960 | 1.93M | if (r < 0) { |
961 | 7.59k | if (VARLINK_STATE_IS_ALIVE(v->state)) |
962 | 7.59k | /* Initiate disconnection */ |
963 | 7.59k | varlink_set_state(v, VARLINK_PENDING_DISCONNECT); |
964 | 4.38k | else |
965 | 4.38k | /* We failed while disconnecting, in that case close right away */ |
966 | 4.38k | varlink_close(v); |
967 | 7.59k | } |
968 | 1.93M | |
969 | 1.93M | varlink_unref(v); |
970 | 1.93M | return r; |
971 | 335k | } |
972 | | |
973 | 334k | static void handle_revents(Varlink *v, int revents) { |
974 | 334k | assert(v); |
975 | 334k | |
976 | 334k | if (v->connecting) { |
977 | 0 | /* If we have seen POLLOUT or POLLHUP on a socket we are asynchronously waiting a connect() |
978 | 0 | * to complete on, we know we are ready. We don't read the connection error here though, |
979 | 0 | * we'll get the error on the next read() or write(). */ |
980 | 0 | if ((revents & (POLLOUT|POLLHUP)) == 0) |
981 | 0 | return; |
982 | 0 | |
983 | 0 | varlink_log(v, "Anynchronous connection completed."); |
984 | 0 | v->connecting = false; |
985 | 334k | } else { |
986 | 334k | /* Note that we don't care much about POLLIN/POLLOUT here, we'll just try reading and writing |
987 | 334k | * what we can. However, we do care about POLLHUP to detect connection termination even if we |
988 | 334k | * momentarily don't want to read nor write anything. */ |
989 | 334k | |
990 | 334k | if (!FLAGS_SET(revents, POLLHUP)) |
991 | 334k | return; |
992 | 0 | |
993 | 0 | varlink_log(v, "Got POLLHUP from socket."); |
994 | 0 | v->got_pollhup = true; |
995 | 0 | } |
996 | 334k | } |
997 | | |
998 | 0 | int varlink_wait(Varlink *v, usec_t timeout) { |
999 | 0 | struct timespec ts; |
1000 | 0 | struct pollfd pfd; |
1001 | 0 | int r, fd, events; |
1002 | 0 | usec_t t; |
1003 | 0 |
|
1004 | 0 | assert_return(v, -EINVAL); |
1005 | 0 | assert_return(!v->server, -ENOTTY); |
1006 | 0 |
|
1007 | 0 | if (v->state == VARLINK_DISCONNECTED) |
1008 | 0 | return -ENOTCONN; |
1009 | 0 | |
1010 | 0 | r = varlink_get_timeout(v, &t); |
1011 | 0 | if (r < 0) |
1012 | 0 | return r; |
1013 | 0 | if (t != USEC_INFINITY) { |
1014 | 0 | usec_t n; |
1015 | 0 |
|
1016 | 0 | n = now(CLOCK_MONOTONIC); |
1017 | 0 | if (t < n) |
1018 | 0 | t = 0; |
1019 | 0 | else |
1020 | 0 | t = usec_sub_unsigned(t, n); |
1021 | 0 | } |
1022 | 0 |
|
1023 | 0 | if (timeout != USEC_INFINITY && |
1024 | 0 | (t == USEC_INFINITY || timeout < t)) |
1025 | 0 | t = timeout; |
1026 | 0 |
|
1027 | 0 | fd = varlink_get_fd(v); |
1028 | 0 | if (fd < 0) |
1029 | 0 | return fd; |
1030 | 0 | |
1031 | 0 | events = varlink_get_events(v); |
1032 | 0 | if (events < 0) |
1033 | 0 | return events; |
1034 | 0 | |
1035 | 0 | pfd = (struct pollfd) { |
1036 | 0 | .fd = fd, |
1037 | 0 | .events = events, |
1038 | 0 | }; |
1039 | 0 |
|
1040 | 0 | r = ppoll(&pfd, 1, |
1041 | 0 | t == USEC_INFINITY ? NULL : timespec_store(&ts, t), |
1042 | 0 | NULL); |
1043 | 0 | if (r < 0) |
1044 | 0 | return -errno; |
1045 | 0 | |
1046 | 0 | handle_revents(v, pfd.revents); |
1047 | 0 |
|
1048 | 0 | return r > 0 ? 1 : 0; |
1049 | 0 | } |
1050 | | |
1051 | 0 | int varlink_get_fd(Varlink *v) { |
1052 | 0 |
|
1053 | 0 | assert_return(v, -EINVAL); |
1054 | 0 |
|
1055 | 0 | if (v->state == VARLINK_DISCONNECTED) |
1056 | 0 | return -ENOTCONN; |
1057 | 0 | if (v->fd < 0) |
1058 | 0 | return -EBADF; |
1059 | 0 | |
1060 | 0 | return v->fd; |
1061 | 0 | } |
1062 | | |
1063 | 3.53M | int varlink_get_events(Varlink *v) { |
1064 | 3.53M | int ret = 0; |
1065 | 3.53M | |
1066 | 3.53M | assert_return(v, -EINVAL); |
1067 | 3.53M | |
1068 | 3.53M | if (v->state == VARLINK_DISCONNECTED) |
1069 | 0 | return -ENOTCONN; |
1070 | 3.53M | |
1071 | 3.53M | if (v->connecting) /* When processing an asynchronous connect(), we only wait for EPOLLOUT, which |
1072 | 0 | * tells us that the connection is now complete. Before that we should neither |
1073 | 0 | * write() or read() from the fd. */ |
1074 | 0 | return EPOLLOUT; |
1075 | 3.53M | |
1076 | 3.53M | if (!v->read_disconnected && |
1077 | 3.53M | IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING, VARLINK_IDLE_SERVER) && |
1078 | 3.53M | !v->current && |
1079 | 3.53M | v->input_buffer_unscanned <= 0) |
1080 | 1.94M | ret |= EPOLLIN; |
1081 | 3.53M | |
1082 | 3.53M | if (!v->write_disconnected && |
1083 | 3.53M | v->output_buffer_size > 0) |
1084 | 1.39M | ret |= EPOLLOUT; |
1085 | 3.53M | |
1086 | 3.53M | return ret; |
1087 | 3.53M | } |
1088 | | |
1089 | 3.53M | int varlink_get_timeout(Varlink *v, usec_t *ret) { |
1090 | 3.53M | assert_return(v, -EINVAL); |
1091 | 3.53M | |
1092 | 3.53M | if (v->state == VARLINK_DISCONNECTED) |
1093 | 0 | return -ENOTCONN; |
1094 | 3.53M | |
1095 | 3.53M | if (IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_CALLING) && |
1096 | 3.53M | v->timeout != USEC_INFINITY) { |
1097 | 875k | if (ret) |
1098 | 875k | *ret = usec_add(v->timestamp, v->timeout); |
1099 | 875k | return 1; |
1100 | 2.65M | } else { |
1101 | 2.65M | if (ret) |
1102 | 2.65M | *ret = USEC_INFINITY; |
1103 | 2.65M | return 0; |
1104 | 2.65M | } |
1105 | 3.53M | } |
1106 | | |
1107 | 4.65k | int varlink_flush(Varlink *v) { |
1108 | 4.65k | int ret = 0, r; |
1109 | 4.65k | |
1110 | 4.65k | assert_return(v, -EINVAL); |
1111 | 4.65k | |
1112 | 4.65k | if (v->state == VARLINK_DISCONNECTED) |
1113 | 3.69k | return -ENOTCONN; |
1114 | 963 | |
1115 | 963 | for (;;) { |
1116 | 963 | struct pollfd pfd; |
1117 | 963 | |
1118 | 963 | if (v->output_buffer_size == 0) |
1119 | 963 | break; |
1120 | 0 | if (v->write_disconnected) |
1121 | 0 | return -ECONNRESET; |
1122 | 0 | |
1123 | 0 | r = varlink_write(v); |
1124 | 0 | if (r < 0) |
1125 | 0 | return r; |
1126 | 0 | if (r > 0) { |
1127 | 0 | ret = 1; |
1128 | 0 | continue; |
1129 | 0 | } |
1130 | 0 | |
1131 | 0 | pfd = (struct pollfd) { |
1132 | 0 | .fd = v->fd, |
1133 | 0 | .events = POLLOUT, |
1134 | 0 | }; |
1135 | 0 |
|
1136 | 0 | if (poll(&pfd, 1, -1) < 0) |
1137 | 0 | return -errno; |
1138 | 0 | |
1139 | 0 | handle_revents(v, pfd.revents); |
1140 | 0 | } |
1141 | 963 | |
1142 | 963 | return ret; |
1143 | 963 | } |
1144 | | |
1145 | 7.38k | static void varlink_detach_server(Varlink *v) { |
1146 | 7.38k | assert(v); |
1147 | 7.38k | |
1148 | 7.38k | if (!v->server) |
1149 | 3.69k | return; |
1150 | 3.69k | |
1151 | 3.69k | if (v->server->by_uid && |
1152 | 3.69k | v->ucred_acquired && |
1153 | 3.69k | uid_is_valid(v->ucred.uid)) { |
1154 | 0 | unsigned c; |
1155 | 0 |
|
1156 | 0 | c = PTR_TO_UINT(hashmap_get(v->server->by_uid, UID_TO_PTR(v->ucred.uid))); |
1157 | 0 | assert(c > 0); |
1158 | 0 |
|
1159 | 0 | if (c == 1) |
1160 | 0 | (void) hashmap_remove(v->server->by_uid, UID_TO_PTR(v->ucred.uid)); |
1161 | 0 | else |
1162 | 0 | (void) hashmap_replace(v->server->by_uid, UID_TO_PTR(v->ucred.uid), UINT_TO_PTR(c - 1)); |
1163 | 0 | } |
1164 | 3.69k | |
1165 | 3.69k | assert(v->server->n_connections > 0); |
1166 | 3.69k | v->server->n_connections--; |
1167 | 3.69k | |
1168 | 3.69k | /* If this is a connection associated to a server, then let's disconnect the server and the |
1169 | 3.69k | * connection from each other. This drops the dangling reference that connect_callback() set up. */ |
1170 | 3.69k | v->server = varlink_server_unref(v->server); |
1171 | 3.69k | varlink_unref(v); |
1172 | 3.69k | } |
1173 | | |
1174 | 12.2k | int varlink_close(Varlink *v) { |
1175 | 12.2k | |
1176 | 12.2k | assert_return(v, -EINVAL); |
1177 | 12.2k | |
1178 | 12.2k | if (v->state == VARLINK_DISCONNECTED) |
1179 | 4.85k | return 0; |
1180 | 7.38k | |
1181 | 7.38k | varlink_set_state(v, VARLINK_DISCONNECTED); |
1182 | 7.38k | |
1183 | 7.38k | /* Let's take a reference first, since varlink_detach_server() might drop the final (dangling) ref |
1184 | 7.38k | * which would destroy us before we can call varlink_clear() */ |
1185 | 7.38k | varlink_ref(v); |
1186 | 7.38k | varlink_detach_server(v); |
1187 | 7.38k | varlink_clear(v); |
1188 | 7.38k | varlink_unref(v); |
1189 | 7.38k | |
1190 | 7.38k | return 1; |
1191 | 7.38k | } |
1192 | | |
1193 | 3.69k | Varlink* varlink_flush_close_unref(Varlink *v) { |
1194 | 3.69k | |
1195 | 3.69k | if (!v) |
1196 | 0 | return NULL; |
1197 | 3.69k | |
1198 | 3.69k | (void) varlink_flush(v); |
1199 | 3.69k | (void) varlink_close(v); |
1200 | 3.69k | |
1201 | 3.69k | return varlink_unref(v); |
1202 | 3.69k | } |
1203 | | |
1204 | 584k | static int varlink_enqueue_json(Varlink *v, JsonVariant *m) { |
1205 | 584k | _cleanup_free_ char *text = NULL; |
1206 | 584k | int r; |
1207 | 584k | |
1208 | 584k | assert(v); |
1209 | 584k | assert(m); |
1210 | 584k | |
1211 | 584k | r = json_variant_format(m, 0, &text); |
1212 | 584k | if (r < 0) |
1213 | 0 | return r; |
1214 | 584k | assert(text[r] == '\0'); |
1215 | 584k | |
1216 | 584k | if (v->output_buffer_size + r + 1 > VARLINK_BUFFER_MAX) |
1217 | 584k | return -ENOBUFS; |
1218 | 584k | |
1219 | 584k | varlink_log(v, "Sending message: %s", text); |
1220 | 584k | |
1221 | 584k | if (v->output_buffer_size == 0) { |
1222 | 92.6k | |
1223 | 92.6k | free_and_replace(v->output_buffer, text); |
1224 | 92.6k | |
1225 | 92.6k | v->output_buffer_size = v->output_buffer_allocated = r + 1; |
1226 | 92.6k | v->output_buffer_index = 0; |
1227 | 92.6k | |
1228 | 491k | } else if (v->output_buffer_index == 0) { |
1229 | 491k | |
1230 | 491k | if (!GREEDY_REALLOC(v->output_buffer, v->output_buffer_allocated, v->output_buffer_size + r + 1)) |
1231 | 491k | return -ENOMEM; |
1232 | 491k | |
1233 | 491k | memcpy(v->output_buffer + v->output_buffer_size, text, r + 1); |
1234 | 491k | v->output_buffer_size += r + 1; |
1235 | 491k | |
1236 | 491k | } else { |
1237 | 405 | char *n; |
1238 | 405 | const size_t new_size = v->output_buffer_size + r + 1; |
1239 | 405 | |
1240 | 405 | n = new(char, new_size); |
1241 | 405 | if (!n) |
1242 | 0 | return -ENOMEM; |
1243 | 405 | |
1244 | 405 | memcpy(mempcpy(n, v->output_buffer + v->output_buffer_index, v->output_buffer_size), text, r + 1); |
1245 | 405 | |
1246 | 405 | free_and_replace(v->output_buffer, n); |
1247 | 405 | v->output_buffer_allocated = v->output_buffer_size = new_size; |
1248 | 405 | v->output_buffer_index = 0; |
1249 | 405 | } |
1250 | 584k | |
1251 | 584k | return 0; |
1252 | 584k | } |
1253 | | |
1254 | 0 | int varlink_send(Varlink *v, const char *method, JsonVariant *parameters) { |
1255 | 0 | _cleanup_(json_variant_unrefp) JsonVariant *m = NULL; |
1256 | 0 | int r; |
1257 | 0 |
|
1258 | 0 | assert_return(v, -EINVAL); |
1259 | 0 | assert_return(method, -EINVAL); |
1260 | 0 |
|
1261 | 0 | if (v->state == VARLINK_DISCONNECTED) |
1262 | 0 | return -ENOTCONN; |
1263 | 0 | if (!IN_SET(v->state, VARLINK_IDLE_CLIENT, VARLINK_AWAITING_REPLY)) |
1264 | 0 | return -EBUSY; |
1265 | 0 | |
1266 | 0 | r = varlink_sanitize_parameters(¶meters); |
1267 | 0 | if (r < 0) |
1268 | 0 | return r; |
1269 | 0 | |
1270 | 0 | r = json_build(&m, JSON_BUILD_OBJECT( |
1271 | 0 | JSON_BUILD_PAIR("method", JSON_BUILD_STRING(method)), |
1272 | 0 | JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters)), |
1273 | 0 | JSON_BUILD_PAIR("oneway", JSON_BUILD_BOOLEAN(true)))); |
1274 | 0 | if (r < 0) |
1275 | 0 | return r; |
1276 | 0 | |
1277 | 0 | r = varlink_enqueue_json(v, m); |
1278 | 0 | if (r < 0) |
1279 | 0 | return r; |
1280 | 0 | |
1281 | 0 | /* No state change here, this is one-way only after all */ |
1282 | 0 | v->timestamp = now(CLOCK_MONOTONIC); |
1283 | 0 | return 0; |
1284 | 0 | } |
1285 | | |
1286 | 0 | int varlink_sendb(Varlink *v, const char *method, ...) { |
1287 | 0 | _cleanup_(json_variant_unrefp) JsonVariant *parameters = NULL; |
1288 | 0 | va_list ap; |
1289 | 0 | int r; |
1290 | 0 |
|
1291 | 0 | assert_return(v, -EINVAL); |
1292 | 0 |
|
1293 | 0 | va_start(ap, method); |
1294 | 0 | r = json_buildv(¶meters, ap); |
1295 | 0 | va_end(ap); |
1296 | 0 |
|
1297 | 0 | if (r < 0) |
1298 | 0 | return r; |
1299 | 0 | |
1300 | 0 | return varlink_send(v, method, parameters); |
1301 | 0 | } |
1302 | | |
1303 | 3.69k | int varlink_invoke(Varlink *v, const char *method, JsonVariant *parameters) { |
1304 | 3.69k | _cleanup_(json_variant_unrefp) JsonVariant *m = NULL; |
1305 | 3.69k | int r; |
1306 | 3.69k | |
1307 | 3.69k | assert_return(v, -EINVAL); |
1308 | 3.69k | assert_return(method, -EINVAL); |
1309 | 3.69k | |
1310 | 3.69k | if (v->state == VARLINK_DISCONNECTED) |
1311 | 0 | return -ENOTCONN; |
1312 | 3.69k | if (!IN_SET(v->state, VARLINK_IDLE_CLIENT, VARLINK_AWAITING_REPLY)) |
1313 | 3.69k | return -EBUSY; |
1314 | 3.69k | |
1315 | 3.69k | r = varlink_sanitize_parameters(¶meters); |
1316 | 3.69k | if (r < 0) |
1317 | 0 | return r; |
1318 | 3.69k | |
1319 | 3.69k | r = json_build(&m, JSON_BUILD_OBJECT( |
1320 | 3.69k | JSON_BUILD_PAIR("method", JSON_BUILD_STRING(method)), |
1321 | 3.69k | JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters)))); |
1322 | 3.69k | if (r < 0) |
1323 | 0 | return r; |
1324 | 3.69k | |
1325 | 3.69k | r = varlink_enqueue_json(v, m); |
1326 | 3.69k | if (r < 0) |
1327 | 0 | return r; |
1328 | 3.69k | |
1329 | 3.69k | varlink_set_state(v, VARLINK_AWAITING_REPLY); |
1330 | 3.69k | v->n_pending++; |
1331 | 3.69k | v->timestamp = now(CLOCK_MONOTONIC); |
1332 | 3.69k | |
1333 | 3.69k | return 0; |
1334 | 3.69k | } |
1335 | | |
1336 | 0 | int varlink_invokeb(Varlink *v, const char *method, ...) { |
1337 | 0 | _cleanup_(json_variant_unrefp) JsonVariant *parameters = NULL; |
1338 | 0 | va_list ap; |
1339 | 0 | int r; |
1340 | 0 |
|
1341 | 0 | assert_return(v, -EINVAL); |
1342 | 0 |
|
1343 | 0 | va_start(ap, method); |
1344 | 0 | r = json_buildv(¶meters, ap); |
1345 | 0 | va_end(ap); |
1346 | 0 |
|
1347 | 0 | if (r < 0) |
1348 | 0 | return r; |
1349 | 0 | |
1350 | 0 | return varlink_invoke(v, method, parameters); |
1351 | 0 | } |
1352 | | |
1353 | | int varlink_call( |
1354 | | Varlink *v, |
1355 | | const char *method, |
1356 | | JsonVariant *parameters, |
1357 | | JsonVariant **ret_parameters, |
1358 | | const char **ret_error_id, |
1359 | 0 | VarlinkReplyFlags *ret_flags) { |
1360 | 0 |
|
1361 | 0 | _cleanup_(json_variant_unrefp) JsonVariant *m = NULL; |
1362 | 0 | int r; |
1363 | 0 |
|
1364 | 0 | assert_return(v, -EINVAL); |
1365 | 0 | assert_return(method, -EINVAL); |
1366 | 0 |
|
1367 | 0 | if (v->state == VARLINK_DISCONNECTED) |
1368 | 0 | return -ENOTCONN; |
1369 | 0 | if (!IN_SET(v->state, VARLINK_IDLE_CLIENT)) |
1370 | 0 | return -EBUSY; |
1371 | 0 | |
1372 | 0 | assert(v->n_pending == 0); /* n_pending can't be > 0 if we are in VARLINK_IDLE_CLIENT state */ |
1373 | 0 |
|
1374 | 0 | r = varlink_sanitize_parameters(¶meters); |
1375 | 0 | if (r < 0) |
1376 | 0 | return r; |
1377 | 0 | |
1378 | 0 | r = json_build(&m, JSON_BUILD_OBJECT( |
1379 | 0 | JSON_BUILD_PAIR("method", JSON_BUILD_STRING(method)), |
1380 | 0 | JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters)))); |
1381 | 0 | if (r < 0) |
1382 | 0 | return r; |
1383 | 0 | |
1384 | 0 | r = varlink_enqueue_json(v, m); |
1385 | 0 | if (r < 0) |
1386 | 0 | return r; |
1387 | 0 | |
1388 | 0 | varlink_set_state(v, VARLINK_CALLING); |
1389 | 0 | v->n_pending++; |
1390 | 0 | v->timestamp = now(CLOCK_MONOTONIC); |
1391 | 0 |
|
1392 | 0 | while (v->state == VARLINK_CALLING) { |
1393 | 0 |
|
1394 | 0 | r = varlink_process(v); |
1395 | 0 | if (r < 0) |
1396 | 0 | return r; |
1397 | 0 | if (r > 0) |
1398 | 0 | continue; |
1399 | 0 | |
1400 | 0 | r = varlink_wait(v, USEC_INFINITY); |
1401 | 0 | if (r < 0) |
1402 | 0 | return r; |
1403 | 0 | } |
1404 | 0 |
|
1405 | 0 | switch (v->state) { |
1406 | 0 |
|
1407 | 0 | case VARLINK_CALLED: |
1408 | 0 | assert(v->current); |
1409 | 0 |
|
1410 | 0 | json_variant_unref(v->reply); |
1411 | 0 | v->reply = TAKE_PTR(v->current); |
1412 | 0 |
|
1413 | 0 | varlink_set_state(v, VARLINK_IDLE_CLIENT); |
1414 | 0 | assert(v->n_pending == 1); |
1415 | 0 | v->n_pending--; |
1416 | 0 |
|
1417 | 0 | if (ret_parameters) |
1418 | 0 | *ret_parameters = json_variant_by_key(v->reply, "parameters"); |
1419 | 0 | if (ret_error_id) |
1420 | 0 | *ret_error_id = json_variant_string(json_variant_by_key(v->reply, "error")); |
1421 | 0 | if (ret_flags) |
1422 | 0 | *ret_flags = 0; |
1423 | 0 |
|
1424 | 0 | return 1; |
1425 | 0 |
|
1426 | 0 | case VARLINK_PENDING_DISCONNECT: |
1427 | 0 | case VARLINK_DISCONNECTED: |
1428 | 0 | return -ECONNRESET; |
1429 | 0 |
|
1430 | 0 | case VARLINK_PENDING_TIMEOUT: |
1431 | 0 | return -ETIME; |
1432 | 0 |
|
1433 | 0 | default: |
1434 | 0 | assert_not_reached("Unexpected state after method call."); |
1435 | 0 | } |
1436 | 0 | } |
1437 | | |
1438 | | int varlink_callb( |
1439 | | Varlink *v, |
1440 | | const char *method, |
1441 | | JsonVariant **ret_parameters, |
1442 | | const char **ret_error_id, |
1443 | 0 | VarlinkReplyFlags *ret_flags, ...) { |
1444 | 0 |
|
1445 | 0 | _cleanup_(json_variant_unrefp) JsonVariant *parameters = NULL; |
1446 | 0 | va_list ap; |
1447 | 0 | int r; |
1448 | 0 |
|
1449 | 0 | assert_return(v, -EINVAL); |
1450 | 0 |
|
1451 | 0 | va_start(ap, ret_flags); |
1452 | 0 | r = json_buildv(¶meters, ap); |
1453 | 0 | va_end(ap); |
1454 | 0 |
|
1455 | 0 | if (r < 0) |
1456 | 0 | return r; |
1457 | 0 | |
1458 | 0 | return varlink_call(v, method, parameters, ret_parameters, ret_error_id, ret_flags); |
1459 | 0 | } |
1460 | | |
1461 | 0 | int varlink_reply(Varlink *v, JsonVariant *parameters) { |
1462 | 0 | _cleanup_(json_variant_unrefp) JsonVariant *m = NULL; |
1463 | 0 | int r; |
1464 | 0 |
|
1465 | 0 | assert_return(v, -EINVAL); |
1466 | 0 |
|
1467 | 0 | if (v->state == VARLINK_DISCONNECTED) |
1468 | 0 | return -ENOTCONN; |
1469 | 0 | if (!IN_SET(v->state, |
1470 | 0 | VARLINK_PROCESSING_METHOD, VARLINK_PROCESSING_METHOD_MORE, |
1471 | 0 | VARLINK_PENDING_METHOD, VARLINK_PENDING_METHOD_MORE)) |
1472 | 0 | return -EBUSY; |
1473 | 0 | |
1474 | 0 | r = varlink_sanitize_parameters(¶meters); |
1475 | 0 | if (r < 0) |
1476 | 0 | return r; |
1477 | 0 | |
1478 | 0 | r = json_build(&m, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters)))); |
1479 | 0 | if (r < 0) |
1480 | 0 | return r; |
1481 | 0 | |
1482 | 0 | r = varlink_enqueue_json(v, m); |
1483 | 0 | if (r < 0) |
1484 | 0 | return r; |
1485 | 0 | |
1486 | 0 | if (IN_SET(v->state, VARLINK_PENDING_METHOD, VARLINK_PENDING_METHOD_MORE)) { |
1487 | 0 | /* We just replied to a method call that was let hanging for a while (i.e. we were outside of |
1488 | 0 | * the varlink_dispatch_method() stack frame), which means with this reply we are ready to |
1489 | 0 | * process further messages. */ |
1490 | 0 | v->current = json_variant_unref(v->current); |
1491 | 0 | varlink_set_state(v, VARLINK_IDLE_SERVER); |
1492 | 0 | } else |
1493 | 0 | /* We replied to a method call from within the varlink_dispatch_method() stack frame), which |
1494 | 0 | * means we should it handle the rest of the state engine. */ |
1495 | 0 | varlink_set_state(v, VARLINK_PROCESSED_METHOD); |
1496 | 0 |
|
1497 | 0 | return 1; |
1498 | 0 | } |
1499 | | |
1500 | 0 | int varlink_replyb(Varlink *v, ...) { |
1501 | 0 | _cleanup_(json_variant_unrefp) JsonVariant *parameters = NULL; |
1502 | 0 | va_list ap; |
1503 | 0 | int r; |
1504 | 0 |
|
1505 | 0 | assert_return(v, -EINVAL); |
1506 | 0 |
|
1507 | 0 | va_start(ap, v); |
1508 | 0 | r = json_buildv(¶meters, ap); |
1509 | 0 | va_end(ap); |
1510 | 0 |
|
1511 | 0 | if (r < 0) |
1512 | 0 | return r; |
1513 | 0 | |
1514 | 0 | return varlink_reply(v, parameters); |
1515 | 0 | } |
1516 | | |
1517 | 580k | int varlink_error(Varlink *v, const char *error_id, JsonVariant *parameters) { |
1518 | 580k | _cleanup_(json_variant_unrefp) JsonVariant *m = NULL; |
1519 | 580k | int r; |
1520 | 580k | |
1521 | 580k | assert_return(v, -EINVAL); |
1522 | 580k | assert_return(error_id, -EINVAL); |
1523 | 580k | |
1524 | 580k | if (v->state == VARLINK_DISCONNECTED) |
1525 | 0 | return -ENOTCONN; |
1526 | 580k | if (!IN_SET(v->state, |
1527 | 580k | VARLINK_PROCESSING_METHOD, VARLINK_PROCESSING_METHOD_MORE, |
1528 | 580k | VARLINK_PENDING_METHOD, VARLINK_PENDING_METHOD_MORE)) |
1529 | 580k | return -EBUSY; |
1530 | 580k | |
1531 | 580k | r = varlink_sanitize_parameters(¶meters); |
1532 | 580k | if (r < 0) |
1533 | 0 | return r; |
1534 | 580k | |
1535 | 580k | r = json_build(&m, JSON_BUILD_OBJECT( |
1536 | 580k | JSON_BUILD_PAIR("error", JSON_BUILD_STRING(error_id)), |
1537 | 580k | JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters)))); |
1538 | 580k | if (r < 0) |
1539 | 0 | return r; |
1540 | 580k | |
1541 | 580k | r = varlink_enqueue_json(v, m); |
1542 | 580k | if (r < 0) |
1543 | 0 | return r; |
1544 | 580k | |
1545 | 580k | if (IN_SET(v->state, VARLINK_PENDING_METHOD, VARLINK_PENDING_METHOD_MORE)) { |
1546 | 0 | v->current = json_variant_unref(v->current); |
1547 | 0 | varlink_set_state(v, VARLINK_IDLE_SERVER); |
1548 | 0 | } else |
1549 | 580k | varlink_set_state(v, VARLINK_PROCESSED_METHOD); |
1550 | 580k | |
1551 | 580k | return 1; |
1552 | 580k | } |
1553 | | |
1554 | 580k | int varlink_errorb(Varlink *v, const char *error_id, ...) { |
1555 | 580k | _cleanup_(json_variant_unrefp) JsonVariant *parameters = NULL; |
1556 | 580k | va_list ap; |
1557 | 580k | int r; |
1558 | 580k | |
1559 | 580k | assert_return(v, -EINVAL); |
1560 | 580k | assert_return(error_id, -EINVAL); |
1561 | 580k | |
1562 | 580k | va_start(ap, error_id); |
1563 | 580k | r = json_buildv(¶meters, ap); |
1564 | 580k | va_end(ap); |
1565 | 580k | |
1566 | 580k | if (r < 0) |
1567 | 0 | return r; |
1568 | 580k | |
1569 | 580k | return varlink_error(v, error_id, parameters); |
1570 | 580k | } |
1571 | | |
1572 | 0 | int varlink_error_invalid_parameter(Varlink *v, JsonVariant *parameters) { |
1573 | 0 |
|
1574 | 0 | assert_return(v, -EINVAL); |
1575 | 0 | assert_return(parameters, -EINVAL); |
1576 | 0 |
|
1577 | 0 | /* We expect to be called in one of two ways: the 'parameters' argument is a string variant in which |
1578 | 0 | * case it is the parameter key name that is invalid. Or the 'parameters' argument is an object |
1579 | 0 | * variant in which case we'll pull out the first key. The latter mode is useful in functions that |
1580 | 0 | * don't expect any arguments. */ |
1581 | 0 |
|
1582 | 0 | if (json_variant_is_string(parameters)) |
1583 | 0 | return varlink_error(v, VARLINK_ERROR_INVALID_PARAMETER, parameters); |
1584 | 0 |
|
1585 | 0 | if (json_variant_is_object(parameters) && |
1586 | 0 | json_variant_elements(parameters) > 0) |
1587 | 0 | return varlink_error(v, VARLINK_ERROR_INVALID_PARAMETER, |
1588 | 0 | json_variant_by_index(parameters, 0)); |
1589 | 0 |
|
1590 | 0 | return -EINVAL; |
1591 | 0 | } |
1592 | | |
1593 | 0 | int varlink_notify(Varlink *v, JsonVariant *parameters) { |
1594 | 0 | _cleanup_(json_variant_unrefp) JsonVariant *m = NULL; |
1595 | 0 | int r; |
1596 | 0 |
|
1597 | 0 | assert_return(v, -EINVAL); |
1598 | 0 |
|
1599 | 0 | if (v->state == VARLINK_DISCONNECTED) |
1600 | 0 | return -ENOTCONN; |
1601 | 0 | if (!IN_SET(v->state, VARLINK_PROCESSING_METHOD_MORE, VARLINK_PENDING_METHOD_MORE)) |
1602 | 0 | return -EBUSY; |
1603 | 0 | |
1604 | 0 | r = varlink_sanitize_parameters(¶meters); |
1605 | 0 | if (r < 0) |
1606 | 0 | return r; |
1607 | 0 | |
1608 | 0 | r = json_build(&m, JSON_BUILD_OBJECT( |
1609 | 0 | JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters)), |
1610 | 0 | JSON_BUILD_PAIR("continues", JSON_BUILD_BOOLEAN(true)))); |
1611 | 0 | if (r < 0) |
1612 | 0 | return r; |
1613 | 0 | |
1614 | 0 | r = varlink_enqueue_json(v, m); |
1615 | 0 | if (r < 0) |
1616 | 0 | return r; |
1617 | 0 | |
1618 | 0 | /* No state change, as more is coming */ |
1619 | 0 | return 1; |
1620 | 0 | } |
1621 | | |
1622 | 0 | int varlink_notifyb(Varlink *v, ...) { |
1623 | 0 | _cleanup_(json_variant_unrefp) JsonVariant *parameters = NULL; |
1624 | 0 | va_list ap; |
1625 | 0 | int r; |
1626 | 0 |
|
1627 | 0 | assert_return(v, -EINVAL); |
1628 | 0 |
|
1629 | 0 | va_start(ap, v); |
1630 | 0 | r = json_buildv(¶meters, ap); |
1631 | 0 | va_end(ap); |
1632 | 0 |
|
1633 | 0 | if (r < 0) |
1634 | 0 | return r; |
1635 | 0 | |
1636 | 0 | return varlink_notify(v, parameters); |
1637 | 0 | } |
1638 | | |
1639 | 3.69k | int varlink_bind_reply(Varlink *v, VarlinkReply callback) { |
1640 | 3.69k | assert_return(v, -EINVAL); |
1641 | 3.69k | |
1642 | 3.69k | if (callback && v->reply_callback && callback != v->reply_callback) |
1643 | 0 | return -EBUSY; |
1644 | 3.69k | |
1645 | 3.69k | v->reply_callback = callback; |
1646 | 3.69k | |
1647 | 3.69k | return 0; |
1648 | 3.69k | } |
1649 | | |
1650 | 0 | void* varlink_set_userdata(Varlink *v, void *userdata) { |
1651 | 0 | void *old; |
1652 | 0 |
|
1653 | 0 | assert_return(v, NULL); |
1654 | 0 |
|
1655 | 0 | old = v->userdata; |
1656 | 0 | v->userdata = userdata; |
1657 | 0 |
|
1658 | 0 | return old; |
1659 | 0 | } |
1660 | | |
1661 | 0 | void* varlink_get_userdata(Varlink *v) { |
1662 | 0 | assert_return(v, NULL); |
1663 | 0 |
|
1664 | 0 | return v->userdata; |
1665 | 0 | } |
1666 | | |
1667 | 0 | static int varlink_acquire_ucred(Varlink *v) { |
1668 | 0 | int r; |
1669 | 0 |
|
1670 | 0 | assert(v); |
1671 | 0 |
|
1672 | 0 | if (v->ucred_acquired) |
1673 | 0 | return 0; |
1674 | 0 | |
1675 | 0 | r = getpeercred(v->fd, &v->ucred); |
1676 | 0 | if (r < 0) |
1677 | 0 | return r; |
1678 | 0 | |
1679 | 0 | v->ucred_acquired = true; |
1680 | 0 | return 0; |
1681 | 0 | } |
1682 | | |
1683 | 0 | int varlink_get_peer_uid(Varlink *v, uid_t *ret) { |
1684 | 0 | int r; |
1685 | 0 |
|
1686 | 0 | assert_return(v, -EINVAL); |
1687 | 0 | assert_return(ret, -EINVAL); |
1688 | 0 |
|
1689 | 0 | r = varlink_acquire_ucred(v); |
1690 | 0 | if (r < 0) |
1691 | 0 | return r; |
1692 | 0 | |
1693 | 0 | if (!uid_is_valid(v->ucred.uid)) |
1694 | 0 | return -ENODATA; |
1695 | 0 | |
1696 | 0 | *ret = v->ucred.uid; |
1697 | 0 | return 0; |
1698 | 0 | } |
1699 | | |
1700 | 0 | int varlink_get_peer_pid(Varlink *v, pid_t *ret) { |
1701 | 0 | int r; |
1702 | 0 |
|
1703 | 0 | assert_return(v, -EINVAL); |
1704 | 0 | assert_return(ret, -EINVAL); |
1705 | 0 |
|
1706 | 0 | r = varlink_acquire_ucred(v); |
1707 | 0 | if (r < 0) |
1708 | 0 | return r; |
1709 | 0 | |
1710 | 0 | if (!pid_is_valid(v->ucred.pid)) |
1711 | 0 | return -ENODATA; |
1712 | 0 | |
1713 | 0 | *ret = v->ucred.pid; |
1714 | 0 | return 0; |
1715 | 0 | } |
1716 | | |
1717 | 0 | int varlink_set_relative_timeout(Varlink *v, usec_t timeout) { |
1718 | 0 | assert_return(v, -EINVAL); |
1719 | 0 | assert_return(timeout > 0, -EINVAL); |
1720 | 0 |
|
1721 | 0 | v->timeout = timeout; |
1722 | 0 | return 0; |
1723 | 0 | } |
1724 | | |
1725 | 0 | VarlinkServer *varlink_get_server(Varlink *v) { |
1726 | 0 | assert_return(v, NULL); |
1727 | 0 |
|
1728 | 0 | return v->server; |
1729 | 0 | } |
1730 | | |
1731 | 3.69k | int varlink_set_description(Varlink *v, const char *description) { |
1732 | 3.69k | assert_return(v, -EINVAL); |
1733 | 3.69k | |
1734 | 3.69k | return free_and_strdup(&v->description, description); |
1735 | 3.69k | } |
1736 | | |
1737 | 334k | static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) { |
1738 | 334k | Varlink *v = userdata; |
1739 | 334k | |
1740 | 334k | assert(s); |
1741 | 334k | assert(v); |
1742 | 334k | |
1743 | 334k | handle_revents(v, revents); |
1744 | 334k | (void) varlink_process(v); |
1745 | 334k | |
1746 | 334k | return 1; |
1747 | 334k | } |
1748 | | |
1749 | 0 | static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) { |
1750 | 0 | Varlink *v = userdata; |
1751 | 0 |
|
1752 | 0 | assert(s); |
1753 | 0 | assert(v); |
1754 | 0 |
|
1755 | 0 | (void) varlink_process(v); |
1756 | 0 | return 1; |
1757 | 0 | } |
1758 | | |
1759 | 1.60M | static int defer_callback(sd_event_source *s, void *userdata) { |
1760 | 1.60M | Varlink *v = userdata; |
1761 | 1.60M | |
1762 | 1.60M | assert(s); |
1763 | 1.60M | assert(v); |
1764 | 1.60M | |
1765 | 1.60M | (void) varlink_process(v); |
1766 | 1.60M | return 1; |
1767 | 1.60M | } |
1768 | | |
1769 | 3.53M | static int prepare_callback(sd_event_source *s, void *userdata) { |
1770 | 3.53M | Varlink *v = userdata; |
1771 | 3.53M | int r, e; |
1772 | 3.53M | usec_t until; |
1773 | 3.53M | |
1774 | 3.53M | assert(s); |
1775 | 3.53M | assert(v); |
1776 | 3.53M | |
1777 | 3.53M | e = varlink_get_events(v); |
1778 | 3.53M | if (e < 0) |
1779 | 0 | return e; |
1780 | 3.53M | |
1781 | 3.53M | r = sd_event_source_set_io_events(v->io_event_source, e); |
1782 | 3.53M | if (r < 0) |
1783 | 0 | return r; |
1784 | 3.53M | |
1785 | 3.53M | r = varlink_get_timeout(v, &until); |
1786 | 3.53M | if (r < 0) |
1787 | 0 | return r; |
1788 | 3.53M | if (r > 0) { |
1789 | 875k | r = sd_event_source_set_time(v->time_event_source, until); |
1790 | 875k | if (r < 0) |
1791 | 0 | return r; |
1792 | 3.53M | } |
1793 | 3.53M | |
1794 | 3.53M | r = sd_event_source_set_enabled(v->time_event_source, r > 0 ? SD_EVENT_ON : SD_EVENT_OFF); |
1795 | 3.53M | if (r < 0) |
1796 | 0 | return r; |
1797 | 3.53M | |
1798 | 3.53M | return 1; |
1799 | 3.53M | } |
1800 | | |
1801 | 963 | static int quit_callback(sd_event_source *event, void *userdata) { |
1802 | 963 | Varlink *v = userdata; |
1803 | 963 | |
1804 | 963 | assert(event); |
1805 | 963 | assert(v); |
1806 | 963 | |
1807 | 963 | varlink_flush(v); |
1808 | 963 | varlink_close(v); |
1809 | 963 | |
1810 | 963 | return 1; |
1811 | 963 | } |
1812 | | |
1813 | 7.38k | int varlink_attach_event(Varlink *v, sd_event *e, int64_t priority) { |
1814 | 7.38k | int r; |
1815 | 7.38k | |
1816 | 7.38k | assert_return(v, -EINVAL); |
1817 | 7.38k | assert_return(!v->event, -EBUSY); |
1818 | 7.38k | |
1819 | 7.38k | if (e) |
1820 | 7.38k | v->event = sd_event_ref(e); |
1821 | 0 | else { |
1822 | 0 | r = sd_event_default(&v->event); |
1823 | 0 | if (r < 0) |
1824 | 0 | return r; |
1825 | 7.38k | } |
1826 | 7.38k | |
1827 | 7.38k | r = sd_event_add_time(v->event, &v->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, v); |
1828 | 7.38k | if (r < 0) |
1829 | 0 | goto fail; |
1830 | 7.38k | |
1831 | 7.38k | r = sd_event_source_set_priority(v->time_event_source, priority); |
1832 | 7.38k | if (r < 0) |
1833 | 0 | goto fail; |
1834 | 7.38k | |
1835 | 7.38k | (void) sd_event_source_set_description(v->time_event_source, "varlink-time"); |
1836 | 7.38k | |
1837 | 7.38k | r = sd_event_add_exit(v->event, &v->quit_event_source, quit_callback, v); |
1838 | 7.38k | if (r < 0) |
1839 | 0 | goto fail; |
1840 | 7.38k | |
1841 | 7.38k | r = sd_event_source_set_priority(v->quit_event_source, priority); |
1842 | 7.38k | if (r < 0) |
1843 | 0 | goto fail; |
1844 | 7.38k | |
1845 | 7.38k | (void) sd_event_source_set_description(v->quit_event_source, "varlink-quit"); |
1846 | 7.38k | |
1847 | 7.38k | r = sd_event_add_io(v->event, &v->io_event_source, v->fd, 0, io_callback, v); |
1848 | 7.38k | if (r < 0) |
1849 | 0 | goto fail; |
1850 | 7.38k | |
1851 | 7.38k | r = sd_event_source_set_prepare(v->io_event_source, prepare_callback); |
1852 | 7.38k | if (r < 0) |
1853 | 0 | goto fail; |
1854 | 7.38k | |
1855 | 7.38k | r = sd_event_source_set_priority(v->io_event_source, priority); |
1856 | 7.38k | if (r < 0) |
1857 | 0 | goto fail; |
1858 | 7.38k | |
1859 | 7.38k | (void) sd_event_source_set_description(v->io_event_source, "varlink-io"); |
1860 | 7.38k | |
1861 | 7.38k | r = sd_event_add_defer(v->event, &v->defer_event_source, defer_callback, v); |
1862 | 7.38k | if (r < 0) |
1863 | 0 | goto fail; |
1864 | 7.38k | |
1865 | 7.38k | r = sd_event_source_set_priority(v->defer_event_source, priority); |
1866 | 7.38k | if (r < 0) |
1867 | 0 | goto fail; |
1868 | 7.38k | |
1869 | 7.38k | (void) sd_event_source_set_description(v->defer_event_source, "varlink-defer"); |
1870 | 7.38k | |
1871 | 7.38k | return 0; |
1872 | 0 | |
1873 | 0 | fail: |
1874 | 0 | varlink_detach_event(v); |
1875 | 0 | return r; |
1876 | 7.38k | } |
1877 | | |
1878 | | |
1879 | 0 | void varlink_detach_event(Varlink *v) { |
1880 | 0 | if (!v) |
1881 | 0 | return; |
1882 | 0 | |
1883 | 0 | varlink_detach_event_sources(v); |
1884 | 0 |
|
1885 | 0 | v->event = sd_event_unref(v->event); |
1886 | 0 | } |
1887 | | |
1888 | 0 | sd_event *varlink_get_event(Varlink *v) { |
1889 | 0 | assert_return(v, NULL); |
1890 | 0 |
|
1891 | 0 | return v->event; |
1892 | 0 | } |
1893 | | |
1894 | 3.69k | int varlink_server_new(VarlinkServer **ret, VarlinkServerFlags flags) { |
1895 | 3.69k | VarlinkServer *s; |
1896 | 3.69k | |
1897 | 3.69k | assert_return(ret, -EINVAL); |
1898 | 3.69k | assert_return((flags & ~_VARLINK_SERVER_FLAGS_ALL) == 0, -EINVAL); |
1899 | 3.69k | |
1900 | 3.69k | s = new(VarlinkServer, 1); |
1901 | 3.69k | if (!s) |
1902 | 0 | return -ENOMEM; |
1903 | 3.69k | |
1904 | 3.69k | *s = (VarlinkServer) { |
1905 | 3.69k | .n_ref = 1, |
1906 | 3.69k | .flags = flags, |
1907 | 3.69k | .connections_max = varlink_server_connections_max(NULL), |
1908 | 3.69k | .connections_per_uid_max = varlink_server_connections_per_uid_max(NULL), |
1909 | 3.69k | }; |
1910 | 3.69k | |
1911 | 3.69k | *ret = s; |
1912 | 3.69k | return 0; |
1913 | 3.69k | } |
1914 | | |
1915 | 3.69k | static VarlinkServer* varlink_server_destroy(VarlinkServer *s) { |
1916 | 3.69k | char *m; |
1917 | 3.69k | |
1918 | 3.69k | if (!s) |
1919 | 0 | return NULL; |
1920 | 3.69k | |
1921 | 3.69k | varlink_server_shutdown(s); |
1922 | 3.69k | |
1923 | 7.38k | while ((m = hashmap_steal_first_key(s->methods))) |
1924 | 3.69k | free(m); |
1925 | 3.69k | |
1926 | 3.69k | hashmap_free(s->methods); |
1927 | 3.69k | hashmap_free(s->by_uid); |
1928 | 3.69k | |
1929 | 3.69k | sd_event_unref(s->event); |
1930 | 3.69k | |
1931 | 3.69k | free(s->description); |
1932 | 3.69k | |
1933 | 3.69k | return mfree(s); |
1934 | 3.69k | } |
1935 | | |
1936 | | DEFINE_TRIVIAL_REF_UNREF_FUNC(VarlinkServer, varlink_server, varlink_server_destroy); |
1937 | | |
1938 | 0 | static int validate_connection(VarlinkServer *server, const struct ucred *ucred) { |
1939 | 0 | int allowed = -1; |
1940 | 0 |
|
1941 | 0 | assert(server); |
1942 | 0 | assert(ucred); |
1943 | 0 |
|
1944 | 0 | if (FLAGS_SET(server->flags, VARLINK_SERVER_ROOT_ONLY)) |
1945 | 0 | allowed = ucred->uid == 0; |
1946 | 0 |
|
1947 | 0 | if (FLAGS_SET(server->flags, VARLINK_SERVER_MYSELF_ONLY)) |
1948 | 0 | allowed = allowed > 0 || ucred->uid == getuid(); |
1949 | 0 |
|
1950 | 0 | if (allowed == 0) { /* Allow access when it is explicitly allowed or when neither |
1951 | 0 | * VARLINK_SERVER_ROOT_ONLY nor VARLINK_SERVER_MYSELF_ONLY are specified. */ |
1952 | 0 | varlink_server_log(server, "Unprivileged client attempted connection, refusing."); |
1953 | 0 | return 0; |
1954 | 0 | } |
1955 | 0 |
|
1956 | 0 | if (server->n_connections >= server->connections_max) { |
1957 | 0 | varlink_server_log(server, "Connection limit of %u reached, refusing.", server->connections_max); |
1958 | 0 | return 0; |
1959 | 0 | } |
1960 | 0 |
|
1961 | 0 | if (FLAGS_SET(server->flags, VARLINK_SERVER_ACCOUNT_UID)) { |
1962 | 0 | unsigned c; |
1963 | 0 |
|
1964 | 0 | if (!uid_is_valid(ucred->uid)) { |
1965 | 0 | varlink_server_log(server, "Client with invalid UID attempted connection, refusing."); |
1966 | 0 | return 0; |
1967 | 0 | } |
1968 | 0 |
|
1969 | 0 | c = PTR_TO_UINT(hashmap_get(server->by_uid, UID_TO_PTR(ucred->uid))); |
1970 | 0 | if (c >= server->connections_per_uid_max) { |
1971 | 0 | varlink_server_log(server, "Per-UID connection limit of %u reached, refusing.", |
1972 | 0 | server->connections_per_uid_max); |
1973 | 0 | return 0; |
1974 | 0 | } |
1975 | 0 | } |
1976 | 0 |
|
1977 | 0 | return 1; |
1978 | 0 | } |
1979 | | |
1980 | 3.69k | static int count_connection(VarlinkServer *server, struct ucred *ucred) { |
1981 | 3.69k | unsigned c; |
1982 | 3.69k | int r; |
1983 | 3.69k | |
1984 | 3.69k | assert(server); |
1985 | 3.69k | assert(ucred); |
1986 | 3.69k | |
1987 | 3.69k | server->n_connections++; |
1988 | 3.69k | |
1989 | 3.69k | if (FLAGS_SET(server->flags, VARLINK_SERVER_ACCOUNT_UID)) { |
1990 | 0 | r = hashmap_ensure_allocated(&server->by_uid, NULL); |
1991 | 0 | if (r < 0) |
1992 | 0 | return log_debug_errno(r, "Failed to allocate UID hash table: %m"); |
1993 | 0 | |
1994 | 0 | c = PTR_TO_UINT(hashmap_get(server->by_uid, UID_TO_PTR(ucred->uid))); |
1995 | 0 |
|
1996 | 0 | varlink_server_log(server, "Connections of user " UID_FMT ": %u (of %u max)", |
1997 | 0 | ucred->uid, c, server->connections_per_uid_max); |
1998 | 0 |
|
1999 | 0 | r = hashmap_replace(server->by_uid, UID_TO_PTR(ucred->uid), UINT_TO_PTR(c + 1)); |
2000 | 0 | if (r < 0) |
2001 | 0 | return log_debug_errno(r, "Failed to increment counter in UID hash table: %m"); |
2002 | 3.69k | } |
2003 | 3.69k | |
2004 | 3.69k | return 0; |
2005 | 3.69k | } |
2006 | | |
2007 | 3.69k | int varlink_server_add_connection(VarlinkServer *server, int fd, Varlink **ret) { |
2008 | 3.69k | _cleanup_(varlink_unrefp) Varlink *v = NULL; |
2009 | 3.69k | bool ucred_acquired; |
2010 | 3.69k | struct ucred ucred; |
2011 | 3.69k | int r; |
2012 | 3.69k | |
2013 | 3.69k | assert_return(server, -EINVAL); |
2014 | 3.69k | assert_return(fd >= 0, -EBADF); |
2015 | 3.69k | |
2016 | 3.69k | if ((server->flags & (VARLINK_SERVER_ROOT_ONLY|VARLINK_SERVER_ACCOUNT_UID)) != 0) { |
2017 | 0 | r = getpeercred(fd, &ucred); |
2018 | 0 | if (r < 0) |
2019 | 0 | return varlink_server_log_errno(server, r, "Failed to acquire peer credentials of incoming socket, refusing: %m"); |
2020 | 0 | |
2021 | 0 | ucred_acquired = true; |
2022 | 0 |
|
2023 | 0 | r = validate_connection(server, &ucred); |
2024 | 0 | if (r < 0) |
2025 | 0 | return r; |
2026 | 0 | if (r == 0) |
2027 | 0 | return -EPERM; |
2028 | 3.69k | } else |
2029 | 3.69k | ucred_acquired = false; |
2030 | 3.69k | |
2031 | 3.69k | r = varlink_new(&v); |
2032 | 3.69k | if (r < 0) |
2033 | 0 | return varlink_server_log_errno(server, r, "Failed to allocate connection object: %m"); |
2034 | 3.69k | |
2035 | 3.69k | r = count_connection(server, &ucred); |
2036 | 3.69k | if (r < 0) |
2037 | 0 | return r; |
2038 | 3.69k | |
2039 | 3.69k | v->fd = fd; |
2040 | 3.69k | v->userdata = server->userdata; |
2041 | 3.69k | if (ucred_acquired) { |
2042 | 0 | v->ucred = ucred; |
2043 | 0 | v->ucred_acquired = true; |
2044 | 0 | } |
2045 | 3.69k | |
2046 | 3.69k | (void) asprintf(&v->description, "%s-%i", server->description ?: "varlink", v->fd); |
2047 | 3.69k | |
2048 | 3.69k | /* Link up the server and the connection, and take reference in both directions. Note that the |
2049 | 3.69k | * reference on the connection is left dangling. It will be dropped when the connection is closed, |
2050 | 3.69k | * which happens in varlink_close(), including in the event loop quit callback. */ |
2051 | 3.69k | v->server = varlink_server_ref(server); |
2052 | 3.69k | varlink_ref(v); |
2053 | 3.69k | |
2054 | 3.69k | varlink_set_state(v, VARLINK_IDLE_SERVER); |
2055 | 3.69k | |
2056 | 3.69k | r = varlink_attach_event(v, server->event, server->event_priority); |
2057 | 3.69k | if (r < 0) { |
2058 | 0 | varlink_log_errno(v, r, "Failed to attach new connection: %m"); |
2059 | 0 | v->fd = -1; /* take the fd out of the connection again */ |
2060 | 0 | varlink_close(v); |
2061 | 0 | return r; |
2062 | 0 | } |
2063 | 3.69k | |
2064 | 3.69k | if (ret) |
2065 | 0 | *ret = v; |
2066 | 3.69k | |
2067 | 3.69k | return 0; |
2068 | 3.69k | } |
2069 | | |
2070 | 0 | static int connect_callback(sd_event_source *source, int fd, uint32_t revents, void *userdata) { |
2071 | 0 | VarlinkServerSocket *ss = userdata; |
2072 | 0 | _cleanup_close_ int cfd = -1; |
2073 | 0 | Varlink *v = NULL; |
2074 | 0 | int r; |
2075 | 0 |
|
2076 | 0 | assert(source); |
2077 | 0 | assert(ss); |
2078 | 0 |
|
2079 | 0 | varlink_server_log(ss->server, "New incoming connection."); |
2080 | 0 |
|
2081 | 0 | cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC); |
2082 | 0 | if (cfd < 0) { |
2083 | 0 | if (ERRNO_IS_ACCEPT_AGAIN(errno)) |
2084 | 0 | return 0; |
2085 | 0 | |
2086 | 0 | return varlink_server_log_errno(ss->server, errno, "Failed to accept incoming socket: %m"); |
2087 | 0 | } |
2088 | 0 |
|
2089 | 0 | r = varlink_server_add_connection(ss->server, cfd, &v); |
2090 | 0 | if (r < 0) |
2091 | 0 | return 0; |
2092 | 0 | |
2093 | 0 | TAKE_FD(cfd); |
2094 | 0 |
|
2095 | 0 | if (ss->server->connect_callback) { |
2096 | 0 | r = ss->server->connect_callback(ss->server, v, ss->server->userdata); |
2097 | 0 | if (r < 0) { |
2098 | 0 | varlink_log_errno(v, r, "Connection callback returned error, disconnecting client: %m"); |
2099 | 0 | varlink_close(v); |
2100 | 0 | return 0; |
2101 | 0 | } |
2102 | 0 | } |
2103 | 0 |
|
2104 | 0 | return 0; |
2105 | 0 | } |
2106 | | |
2107 | 0 | int varlink_server_listen_fd(VarlinkServer *s, int fd) { |
2108 | 0 | _cleanup_free_ VarlinkServerSocket *ss = NULL; |
2109 | 0 | int r; |
2110 | 0 |
|
2111 | 0 | assert_return(s, -EINVAL); |
2112 | 0 | assert_return(fd >= 0, -EBADF); |
2113 | 0 |
|
2114 | 0 | r = fd_nonblock(fd, true); |
2115 | 0 | if (r < 0) |
2116 | 0 | return r; |
2117 | 0 | |
2118 | 0 | ss = new(VarlinkServerSocket, 1); |
2119 | 0 | if (!ss) |
2120 | 0 | return -ENOMEM; |
2121 | 0 | |
2122 | 0 | *ss = (VarlinkServerSocket) { |
2123 | 0 | .server = s, |
2124 | 0 | .fd = fd, |
2125 | 0 | }; |
2126 | 0 |
|
2127 | 0 | if (s->event) { |
2128 | 0 | _cleanup_(sd_event_source_unrefp) sd_event_source *es = NULL; |
2129 | 0 |
|
2130 | 0 | r = sd_event_add_io(s->event, &es, fd, EPOLLIN, connect_callback, ss); |
2131 | 0 | if (r < 0) |
2132 | 0 | return r; |
2133 | 0 | |
2134 | 0 | r = sd_event_source_set_priority(ss->event_source, s->event_priority); |
2135 | 0 | if (r < 0) |
2136 | 0 | return r; |
2137 | 0 | } |
2138 | 0 | |
2139 | 0 | LIST_PREPEND(sockets, s->sockets, TAKE_PTR(ss)); |
2140 | 0 | return 0; |
2141 | 0 | } |
2142 | | |
2143 | 0 | int varlink_server_listen_address(VarlinkServer *s, const char *address, mode_t m) { |
2144 | 0 | union sockaddr_union sockaddr; |
2145 | 0 | _cleanup_close_ int fd = -1; |
2146 | 0 | int r; |
2147 | 0 |
|
2148 | 0 | assert_return(s, -EINVAL); |
2149 | 0 | assert_return(address, -EINVAL); |
2150 | 0 | assert_return((m & ~0777) == 0, -EINVAL); |
2151 | 0 |
|
2152 | 0 | r = sockaddr_un_set_path(&sockaddr.un, address); |
2153 | 0 | if (r < 0) |
2154 | 0 | return r; |
2155 | 0 | |
2156 | 0 | fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); |
2157 | 0 | if (fd < 0) |
2158 | 0 | return -errno; |
2159 | 0 | |
2160 | 0 | (void) sockaddr_un_unlink(&sockaddr.un); |
2161 | 0 |
|
2162 | 0 | RUN_WITH_UMASK(~m & 0777) |
2163 | 0 | if (bind(fd, &sockaddr.sa, SOCKADDR_UN_LEN(sockaddr.un)) < 0) |
2164 | 0 | return -errno; |
2165 | 0 |
|
2166 | 0 | if (listen(fd, SOMAXCONN) < 0) |
2167 | 0 | return -errno; |
2168 | 0 | |
2169 | 0 | r = varlink_server_listen_fd(s, fd); |
2170 | 0 | if (r < 0) |
2171 | 0 | return r; |
2172 | 0 | |
2173 | 0 | TAKE_FD(fd); |
2174 | 0 | return 0; |
2175 | 0 | } |
2176 | | |
2177 | 0 | void* varlink_server_set_userdata(VarlinkServer *s, void *userdata) { |
2178 | 0 | void *ret; |
2179 | 0 |
|
2180 | 0 | assert_return(s, NULL); |
2181 | 0 |
|
2182 | 0 | ret = s->userdata; |
2183 | 0 | s->userdata = userdata; |
2184 | 0 |
|
2185 | 0 | return ret; |
2186 | 0 | } |
2187 | | |
2188 | 0 | void* varlink_server_get_userdata(VarlinkServer *s) { |
2189 | 0 | assert_return(s, NULL); |
2190 | 0 |
|
2191 | 0 | return s->userdata; |
2192 | 0 | } |
2193 | | |
2194 | 0 | static VarlinkServerSocket* varlink_server_socket_destroy(VarlinkServerSocket *ss) { |
2195 | 0 | if (!ss) |
2196 | 0 | return NULL; |
2197 | 0 | |
2198 | 0 | if (ss->server) |
2199 | 0 | LIST_REMOVE(sockets, ss->server->sockets, ss); |
2200 | 0 |
|
2201 | 0 | sd_event_source_disable_unref(ss->event_source); |
2202 | 0 |
|
2203 | 0 | free(ss->address); |
2204 | 0 | safe_close(ss->fd); |
2205 | 0 |
|
2206 | 0 | return mfree(ss); |
2207 | 0 | } |
2208 | | |
2209 | 3.69k | int varlink_server_shutdown(VarlinkServer *s) { |
2210 | 3.69k | assert_return(s, -EINVAL); |
2211 | 3.69k | |
2212 | 3.69k | while (s->sockets) |
2213 | 0 | varlink_server_socket_destroy(s->sockets); |
2214 | 3.69k | |
2215 | 3.69k | return 0; |
2216 | 3.69k | } |
2217 | | |
2218 | 3.69k | int varlink_server_attach_event(VarlinkServer *s, sd_event *e, int64_t priority) { |
2219 | 3.69k | VarlinkServerSocket *ss; |
2220 | 3.69k | int r; |
2221 | 3.69k | |
2222 | 3.69k | assert_return(s, -EINVAL); |
2223 | 3.69k | assert_return(!s->event, -EBUSY); |
2224 | 3.69k | |
2225 | 3.69k | if (e) |
2226 | 3.69k | s->event = sd_event_ref(e); |
2227 | 0 | else { |
2228 | 0 | r = sd_event_default(&s->event); |
2229 | 0 | if (r < 0) |
2230 | 0 | return r; |
2231 | 3.69k | } |
2232 | 3.69k | |
2233 | 3.69k | LIST_FOREACH(sockets, ss, s->sockets) { |
2234 | 0 | assert(!ss->event_source); |
2235 | 0 |
|
2236 | 0 | r = sd_event_add_io(s->event, &ss->event_source, ss->fd, EPOLLIN, connect_callback, ss); |
2237 | 0 | if (r < 0) |
2238 | 0 | goto fail; |
2239 | 0 | |
2240 | 0 | r = sd_event_source_set_priority(ss->event_source, priority); |
2241 | 0 | if (r < 0) |
2242 | 0 | goto fail; |
2243 | 0 | } |
2244 | 3.69k | |
2245 | 3.69k | s->event_priority = priority; |
2246 | 3.69k | return 0; |
2247 | 0 | |
2248 | 0 | fail: |
2249 | 0 | varlink_server_detach_event(s); |
2250 | 0 | return r; |
2251 | 3.69k | } |
2252 | | |
2253 | 0 | int varlink_server_detach_event(VarlinkServer *s) { |
2254 | 0 | VarlinkServerSocket *ss; |
2255 | 0 |
|
2256 | 0 | assert_return(s, -EINVAL); |
2257 | 0 |
|
2258 | 0 | LIST_FOREACH(sockets, ss, s->sockets) { |
2259 | 0 |
|
2260 | 0 | if (!ss->event_source) |
2261 | 0 | continue; |
2262 | 0 | |
2263 | 0 | (void) sd_event_source_set_enabled(ss->event_source, SD_EVENT_OFF); |
2264 | 0 | ss->event_source = sd_event_source_unref(ss->event_source); |
2265 | 0 | } |
2266 | 0 |
|
2267 | 0 | sd_event_unref(s->event); |
2268 | 0 | return 0; |
2269 | 0 | } |
2270 | | |
2271 | 0 | sd_event *varlink_server_get_event(VarlinkServer *s) { |
2272 | 0 | assert_return(s, NULL); |
2273 | 0 |
|
2274 | 0 | return s->event; |
2275 | 0 | } |
2276 | | |
2277 | 3.69k | int varlink_server_bind_method(VarlinkServer *s, const char *method, VarlinkMethod callback) { |
2278 | 3.69k | char *m; |
2279 | 3.69k | int r; |
2280 | 3.69k | |
2281 | 3.69k | assert_return(s, -EINVAL); |
2282 | 3.69k | assert_return(method, -EINVAL); |
2283 | 3.69k | assert_return(callback, -EINVAL); |
2284 | 3.69k | |
2285 | 3.69k | if (startswith(method, "org.varlink.service.")) |
2286 | 0 | return -EEXIST; |
2287 | 3.69k | |
2288 | 3.69k | r = hashmap_ensure_allocated(&s->methods, &string_hash_ops); |
2289 | 3.69k | if (r < 0) |
2290 | 0 | return r; |
2291 | 3.69k | |
2292 | 3.69k | m = strdup(method); |
2293 | 3.69k | if (!m) |
2294 | 0 | return -ENOMEM; |
2295 | 3.69k | |
2296 | 3.69k | r = hashmap_put(s->methods, m, callback); |
2297 | 3.69k | if (r < 0) { |
2298 | 0 | free(m); |
2299 | 0 | return r; |
2300 | 0 | } |
2301 | 3.69k | |
2302 | 3.69k | return 0; |
2303 | 3.69k | } |
2304 | | |
2305 | 0 | int varlink_server_bind_method_many_internal(VarlinkServer *s, ...) { |
2306 | 0 | va_list ap; |
2307 | 0 | int r = 0; |
2308 | 0 |
|
2309 | 0 | assert_return(s, -EINVAL); |
2310 | 0 |
|
2311 | 0 | va_start(ap, s); |
2312 | 0 | for (;;) { |
2313 | 0 | VarlinkMethod callback; |
2314 | 0 | const char *method; |
2315 | 0 |
|
2316 | 0 | method = va_arg(ap, const char *); |
2317 | 0 | if (!method) |
2318 | 0 | break; |
2319 | 0 | |
2320 | 0 | callback = va_arg(ap, VarlinkMethod); |
2321 | 0 |
|
2322 | 0 | r = varlink_server_bind_method(s, method, callback); |
2323 | 0 | if (r < 0) |
2324 | 0 | break; |
2325 | 0 | } |
2326 | 0 | va_end(ap); |
2327 | 0 |
|
2328 | 0 | return r; |
2329 | 0 | } |
2330 | | |
2331 | 0 | int varlink_server_bind_connect(VarlinkServer *s, VarlinkConnect callback) { |
2332 | 0 | assert_return(s, -EINVAL); |
2333 | 0 |
|
2334 | 0 | if (callback && s->connect_callback && callback != s->connect_callback) |
2335 | 0 | return -EBUSY; |
2336 | 0 | |
2337 | 0 | s->connect_callback = callback; |
2338 | 0 | return 0; |
2339 | 0 | } |
2340 | | |
2341 | 7.38k | unsigned varlink_server_connections_max(VarlinkServer *s) { |
2342 | 7.38k | struct rlimit rl; |
2343 | 7.38k | |
2344 | 7.38k | /* If a server is specified, return the setting for that server, otherwise the default value */ |
2345 | 7.38k | if (s) |
2346 | 0 | return s->connections_max; |
2347 | 7.38k | |
2348 | 7.38k | assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0); |
2349 | 7.38k | |
2350 | 7.38k | /* Make sure we never use up more than ¾th of RLIMIT_NOFILE for IPC */ |
2351 | 7.38k | if (VARLINK_DEFAULT_CONNECTIONS_MAX > rl.rlim_cur / 4 * 3) |
2352 | 0 | return rl.rlim_cur / 4 * 3; |
2353 | 7.38k | |
2354 | 7.38k | return VARLINK_DEFAULT_CONNECTIONS_MAX; |
2355 | 7.38k | } |
2356 | | |
2357 | 3.69k | unsigned varlink_server_connections_per_uid_max(VarlinkServer *s) { |
2358 | 3.69k | unsigned m; |
2359 | 3.69k | |
2360 | 3.69k | if (s) |
2361 | 0 | return s->connections_per_uid_max; |
2362 | 3.69k | |
2363 | 3.69k | /* Make sure to never use up more than ¾th of available connections for a single user */ |
2364 | 3.69k | m = varlink_server_connections_max(NULL); |
2365 | 3.69k | if (VARLINK_DEFAULT_CONNECTIONS_PER_UID_MAX > m) |
2366 | 0 | return m / 4 * 3; |
2367 | 3.69k | |
2368 | 3.69k | return VARLINK_DEFAULT_CONNECTIONS_PER_UID_MAX; |
2369 | 3.69k | } |
2370 | | |
2371 | 0 | int varlink_server_set_connections_per_uid_max(VarlinkServer *s, unsigned m) { |
2372 | 0 | assert_return(s, -EINVAL); |
2373 | 0 | assert_return(m > 0, -EINVAL); |
2374 | 0 |
|
2375 | 0 | s->connections_per_uid_max = m; |
2376 | 0 | return 0; |
2377 | 0 | } |
2378 | | |
2379 | 0 | int varlink_server_set_connections_max(VarlinkServer *s, unsigned m) { |
2380 | 0 | assert_return(s, -EINVAL); |
2381 | 0 | assert_return(m > 0, -EINVAL); |
2382 | 0 |
|
2383 | 0 | s->connections_max = m; |
2384 | 0 | return 0; |
2385 | 0 | } |
2386 | | |
2387 | 3.69k | int varlink_server_set_description(VarlinkServer *s, const char *description) { |
2388 | 3.69k | assert_return(s, -EINVAL); |
2389 | 3.69k | |
2390 | 3.69k | return free_and_strdup(&s->description, description); |
2391 | 3.69k | } |