]>
Commit | Line | Data |
---|---|---|
5cb5a6ff LP |
1 | /*-*- Mode: C; c-basic-offset: 8 -*-*/ |
2 | ||
83c60c9f LP |
3 | #include <sys/types.h> |
4 | #include <sys/stat.h> | |
5 | #include <unistd.h> | |
6 | #include <errno.h> | |
7 | #include <fcntl.h> | |
9152c765 | 8 | #include <sys/poll.h> |
034c6ed7 | 9 | #include <signal.h> |
83c60c9f | 10 | |
87f0e418 | 11 | #include "unit.h" |
5cb5a6ff | 12 | #include "socket.h" |
83c60c9f LP |
13 | #include "log.h" |
14 | ||
87f0e418 LP |
15 | static const UnitActiveState state_table[_SOCKET_STATE_MAX] = { |
16 | [SOCKET_DEAD] = UNIT_INACTIVE, | |
17 | [SOCKET_START_PRE] = UNIT_ACTIVATING, | |
18 | [SOCKET_START_POST] = UNIT_ACTIVATING, | |
19 | [SOCKET_LISTENING] = UNIT_ACTIVE, | |
20 | [SOCKET_RUNNING] = UNIT_ACTIVE, | |
21 | [SOCKET_STOP_PRE] = UNIT_DEACTIVATING, | |
22 | [SOCKET_STOP_PRE_SIGTERM] = UNIT_DEACTIVATING, | |
23 | [SOCKET_STOP_PRE_SIGKILL] = UNIT_DEACTIVATING, | |
24 | [SOCKET_STOP_POST] = UNIT_DEACTIVATING, | |
25 | [SOCKET_STOP_POST_SIGTERM] = UNIT_DEACTIVATING, | |
26 | [SOCKET_STOP_POST_SIGKILL] = UNIT_DEACTIVATING, | |
27 | [SOCKET_MAINTAINANCE] = UNIT_INACTIVE, | |
83c60c9f | 28 | }; |
5cb5a6ff | 29 | |
87f0e418 LP |
30 | static void socket_done(Unit *u) { |
31 | Socket *s = SOCKET(u); | |
034c6ed7 LP |
32 | SocketPort *p; |
33 | ||
34 | assert(s); | |
35 | ||
36 | while ((p = s->ports)) { | |
37 | LIST_REMOVE(SocketPort, port, s->ports, p); | |
38 | ||
39 | if (p->fd >= 0) | |
40 | close_nointr(p->fd); | |
41 | free(p->path); | |
42 | free(p); | |
43 | } | |
44 | ||
45 | exec_context_done(&s->exec_context); | |
46 | exec_command_free_array(s->exec_command, _SOCKET_EXEC_MAX); | |
47 | s->control_command = NULL; | |
48 | ||
49 | if (s->control_pid > 0) { | |
87f0e418 | 50 | unit_unwatch_pid(u, s->control_pid); |
034c6ed7 LP |
51 | s->control_pid = 0; |
52 | } | |
53 | ||
54 | s->service = NULL; | |
55 | ||
87f0e418 | 56 | unit_unwatch_timer(u, &s->timer_id); |
5cb5a6ff LP |
57 | } |
58 | ||
87f0e418 LP |
59 | static int socket_init(Unit *u) { |
60 | Socket *s = SOCKET(u); | |
44d8db9e LP |
61 | char *t; |
62 | int r; | |
63 | ||
64 | /* First, reset everything to the defaults, in case this is a | |
65 | * reload */ | |
66 | ||
67 | s->state = 0; | |
68 | s->timer_id = -1; | |
69 | s->bind_ipv6_only = false; | |
70 | s->backlog = SOMAXCONN; | |
71 | s->timeout_usec = DEFAULT_TIMEOUT_USEC; | |
72 | exec_context_init(&s->exec_context); | |
73 | ||
87f0e418 | 74 | if ((r = unit_load_fragment_and_dropin(u)) < 0) |
44d8db9e LP |
75 | goto fail; |
76 | ||
87f0e418 | 77 | if (!(t = unit_name_change_suffix(unit_id(u), ".service"))) { |
44d8db9e LP |
78 | r = -ENOMEM; |
79 | goto fail; | |
80 | } | |
81 | ||
87f0e418 | 82 | r = manager_load_unit(u->meta.manager, t, (Unit**) &s->service); |
44d8db9e LP |
83 | free(t); |
84 | ||
85 | if (r < 0) | |
86 | goto fail; | |
87 | ||
87f0e418 | 88 | if ((r = unit_add_dependency(u, UNIT_BEFORE, UNIT(s->service))) < 0) |
44d8db9e LP |
89 | goto fail; |
90 | ||
91 | return 0; | |
92 | ||
93 | fail: | |
87f0e418 | 94 | socket_done(u); |
44d8db9e LP |
95 | return r; |
96 | } | |
97 | ||
542563ba LP |
98 | static const char* listen_lookup(int type) { |
99 | ||
100 | if (type == SOCK_STREAM) | |
101 | return "ListenStream"; | |
102 | else if (type == SOCK_DGRAM) | |
103 | return "ListenDatagram"; | |
104 | else if (type == SOCK_SEQPACKET) | |
105 | return "ListenSequentialPacket"; | |
106 | ||
034c6ed7 | 107 | assert_not_reached("Unknown socket type"); |
542563ba LP |
108 | return NULL; |
109 | } | |
110 | ||
87f0e418 | 111 | static void socket_dump(Unit *u, FILE *f, const char *prefix) { |
5cb5a6ff LP |
112 | |
113 | static const char* const state_table[_SOCKET_STATE_MAX] = { | |
114 | [SOCKET_DEAD] = "dead", | |
115 | [SOCKET_START_PRE] = "start-pre", | |
116 | [SOCKET_START_POST] = "start-post", | |
117 | [SOCKET_LISTENING] = "listening", | |
118 | [SOCKET_RUNNING] = "running", | |
119 | [SOCKET_STOP_PRE] = "stop-pre", | |
034c6ed7 LP |
120 | [SOCKET_STOP_PRE_SIGTERM] = "stop-pre-sigterm", |
121 | [SOCKET_STOP_PRE_SIGKILL] = "stop-pre-sigkill", | |
5cb5a6ff | 122 | [SOCKET_STOP_POST] = "stop-post", |
034c6ed7 LP |
123 | [SOCKET_STOP_POST_SIGTERM] = "stop-post-sigterm", |
124 | [SOCKET_STOP_POST_SIGKILL] = "stop-post-sigkill", | |
5cb5a6ff LP |
125 | [SOCKET_MAINTAINANCE] = "maintainance" |
126 | }; | |
127 | ||
128 | static const char* const command_table[_SOCKET_EXEC_MAX] = { | |
129 | [SOCKET_EXEC_START_PRE] = "StartPre", | |
130 | [SOCKET_EXEC_START_POST] = "StartPost", | |
131 | [SOCKET_EXEC_STOP_PRE] = "StopPre", | |
132 | [SOCKET_EXEC_STOP_POST] = "StopPost" | |
133 | }; | |
134 | ||
135 | SocketExecCommand c; | |
87f0e418 | 136 | Socket *s = SOCKET(u); |
542563ba | 137 | SocketPort *p; |
5cb5a6ff LP |
138 | |
139 | assert(s); | |
140 | ||
5cb5a6ff LP |
141 | fprintf(f, |
142 | "%sSocket State: %s\n" | |
542563ba LP |
143 | "%sBindIPv6Only: %s\n" |
144 | "%sBacklog: %u\n", | |
5cb5a6ff | 145 | prefix, state_table[s->state], |
542563ba LP |
146 | prefix, yes_no(s->bind_ipv6_only), |
147 | prefix, s->backlog); | |
148 | ||
034c6ed7 | 149 | LIST_FOREACH(port, p, s->ports) { |
5cb5a6ff | 150 | |
542563ba LP |
151 | if (p->type == SOCKET_SOCKET) { |
152 | const char *t; | |
153 | int r; | |
154 | char *k; | |
155 | ||
156 | if ((r = socket_address_print(&p->address, &k)) < 0) | |
157 | t = strerror(-r); | |
158 | else | |
159 | t = k; | |
160 | ||
161 | fprintf(f, "%s%s: %s\n", prefix, listen_lookup(p->address.type), k); | |
162 | free(k); | |
163 | } else | |
164 | fprintf(f, "%sListenFIFO: %s\n", prefix, p->path); | |
165 | } | |
5cb5a6ff LP |
166 | |
167 | exec_context_dump(&s->exec_context, f, prefix); | |
168 | ||
169 | for (c = 0; c < _SOCKET_EXEC_MAX; c++) { | |
170 | ExecCommand *i; | |
171 | ||
034c6ed7 | 172 | LIST_FOREACH(command, i, s->exec_command[c]) |
5cb5a6ff LP |
173 | fprintf(f, "%s%s: %s\n", prefix, command_table[c], i->path); |
174 | } | |
175 | } | |
176 | ||
034c6ed7 | 177 | static void socket_close_fds(Socket *s) { |
83c60c9f LP |
178 | SocketPort *p; |
179 | ||
180 | assert(s); | |
181 | ||
034c6ed7 | 182 | LIST_FOREACH(port, p, s->ports) { |
83c60c9f LP |
183 | if (p->fd < 0) |
184 | continue; | |
185 | ||
87f0e418 | 186 | unit_unwatch_fd(UNIT(s), p->fd); |
9152c765 LP |
187 | assert_se(close_nointr(p->fd) >= 0); |
188 | ||
83c60c9f LP |
189 | p->fd = -1; |
190 | } | |
191 | } | |
192 | ||
034c6ed7 | 193 | static int socket_open_fds(Socket *s) { |
83c60c9f LP |
194 | SocketPort *p; |
195 | int r; | |
196 | ||
197 | assert(s); | |
198 | ||
034c6ed7 | 199 | LIST_FOREACH(port, p, s->ports) { |
83c60c9f | 200 | |
034c6ed7 LP |
201 | if (p->fd >= 0) |
202 | continue; | |
83c60c9f LP |
203 | |
204 | if (p->type == SOCKET_SOCKET) { | |
205 | ||
206 | if ((r = socket_address_listen(&p->address, s->backlog, s->bind_ipv6_only, &p->fd)) < 0) | |
207 | goto rollback; | |
208 | ||
209 | } else { | |
210 | struct stat st; | |
211 | assert(p->type == SOCKET_FIFO); | |
212 | ||
213 | if (mkfifo(p->path, 0666 & ~s->exec_context.umask) < 0 && errno != EEXIST) { | |
214 | r = -errno; | |
215 | goto rollback; | |
216 | } | |
217 | ||
218 | if ((p->fd = open(p->path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW)) < 0) { | |
219 | r = -errno; | |
220 | goto rollback; | |
221 | } | |
222 | ||
223 | if (fstat(p->fd, &st) < 0) { | |
224 | r = -errno; | |
225 | goto rollback; | |
226 | } | |
227 | ||
228 | /* FIXME verify user, access mode */ | |
229 | ||
230 | if (!S_ISFIFO(st.st_mode)) { | |
231 | r = -EEXIST; | |
232 | goto rollback; | |
233 | } | |
234 | } | |
034c6ed7 LP |
235 | } |
236 | ||
237 | return 0; | |
238 | ||
239 | rollback: | |
240 | socket_close_fds(s); | |
241 | return r; | |
242 | } | |
243 | ||
244 | static void socket_unwatch_fds(Socket *s) { | |
245 | SocketPort *p; | |
9152c765 | 246 | |
034c6ed7 LP |
247 | assert(s); |
248 | ||
249 | LIST_FOREACH(port, p, s->ports) { | |
250 | if (p->fd < 0) | |
251 | continue; | |
252 | ||
87f0e418 | 253 | unit_unwatch_fd(UNIT(s), p->fd); |
83c60c9f | 254 | } |
034c6ed7 LP |
255 | } |
256 | ||
257 | static int socket_watch_fds(Socket *s) { | |
258 | SocketPort *p; | |
259 | int r; | |
260 | ||
261 | assert(s); | |
83c60c9f | 262 | |
034c6ed7 LP |
263 | LIST_FOREACH(port, p, s->ports) { |
264 | if (p->fd < 0) | |
265 | continue; | |
266 | ||
87f0e418 | 267 | if ((r = unit_watch_fd(UNIT(s), p->fd, POLLIN)) < 0) |
034c6ed7 LP |
268 | goto fail; |
269 | } | |
83c60c9f | 270 | |
542563ba | 271 | return 0; |
83c60c9f | 272 | |
034c6ed7 LP |
273 | fail: |
274 | socket_unwatch_fds(s); | |
275 | return r; | |
276 | } | |
277 | ||
278 | static void socket_set_state(Socket *s, SocketState state) { | |
279 | SocketState old_state; | |
280 | assert(s); | |
281 | ||
282 | old_state = s->state; | |
283 | s->state = state; | |
284 | ||
285 | if (state != SOCKET_START_PRE && | |
286 | state != SOCKET_START_POST && | |
287 | state != SOCKET_STOP_PRE && | |
288 | state != SOCKET_STOP_PRE_SIGTERM && | |
289 | state != SOCKET_STOP_PRE_SIGKILL && | |
290 | state != SOCKET_STOP_POST && | |
291 | state != SOCKET_STOP_POST_SIGTERM && | |
292 | state != SOCKET_STOP_POST_SIGKILL) | |
87f0e418 | 293 | unit_unwatch_timer(UNIT(s), &s->timer_id); |
034c6ed7 LP |
294 | |
295 | if (state != SOCKET_START_PRE && | |
296 | state != SOCKET_START_POST && | |
297 | state != SOCKET_STOP_PRE && | |
298 | state != SOCKET_STOP_PRE_SIGTERM && | |
299 | state != SOCKET_STOP_PRE_SIGKILL && | |
300 | state != SOCKET_STOP_POST && | |
301 | state != SOCKET_STOP_POST_SIGTERM && | |
302 | state != SOCKET_STOP_POST_SIGKILL) | |
303 | if (s->control_pid >= 0) { | |
87f0e418 | 304 | unit_unwatch_pid(UNIT(s), s->control_pid); |
034c6ed7 LP |
305 | s->control_pid = 0; |
306 | } | |
307 | ||
308 | if (state != SOCKET_START_PRE && | |
309 | state != SOCKET_START_POST && | |
310 | state != SOCKET_STOP_PRE && | |
311 | state != SOCKET_STOP_POST) | |
312 | s->control_command = NULL; | |
313 | ||
314 | if (state != SOCKET_START_POST && | |
315 | state != SOCKET_LISTENING && | |
316 | state != SOCKET_RUNNING && | |
317 | state != SOCKET_STOP_PRE && | |
318 | state != SOCKET_STOP_PRE_SIGTERM && | |
319 | state != SOCKET_STOP_PRE_SIGKILL) | |
320 | socket_close_fds(s); | |
321 | ||
322 | if (state != SOCKET_LISTENING) | |
323 | socket_unwatch_fds(s); | |
324 | ||
87f0e418 | 325 | unit_notify(UNIT(s), state_table[old_state], state_table[s->state]); |
034c6ed7 LP |
326 | } |
327 | ||
328 | static int socket_spawn(Socket *s, ExecCommand *c, bool timeout, pid_t *_pid) { | |
329 | pid_t pid; | |
330 | int r; | |
331 | ||
332 | assert(s); | |
333 | assert(c); | |
334 | assert(_pid); | |
335 | ||
336 | if (timeout) { | |
87f0e418 | 337 | if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_id)) < 0) |
034c6ed7 LP |
338 | goto fail; |
339 | } else | |
87f0e418 | 340 | unit_unwatch_timer(UNIT(s), &s->timer_id); |
034c6ed7 LP |
341 | |
342 | if ((r = exec_spawn(c, &s->exec_context, NULL, 0, &pid)) < 0) | |
343 | goto fail; | |
344 | ||
87f0e418 | 345 | if ((r = unit_watch_pid(UNIT(s), pid)) < 0) |
034c6ed7 LP |
346 | /* FIXME: we need to do something here */ |
347 | goto fail; | |
83c60c9f | 348 | |
034c6ed7 LP |
349 | *_pid = pid; |
350 | ||
351 | return 0; | |
352 | ||
353 | fail: | |
354 | if (timeout) | |
87f0e418 | 355 | unit_unwatch_timer(UNIT(s), &s->timer_id); |
83c60c9f LP |
356 | |
357 | return r; | |
542563ba LP |
358 | } |
359 | ||
034c6ed7 LP |
360 | static void socket_enter_dead(Socket *s, bool success) { |
361 | assert(s); | |
362 | ||
363 | if (!success) | |
364 | s->failure = true; | |
365 | ||
366 | socket_set_state(s, s->failure ? SOCKET_MAINTAINANCE : SOCKET_DEAD); | |
367 | } | |
368 | ||
369 | static void socket_enter_stop_post(Socket *s, bool success) { | |
370 | int r; | |
371 | assert(s); | |
372 | ||
373 | if (!success) | |
374 | s->failure = true; | |
375 | ||
376 | if ((s->control_command = s->exec_command[SOCKET_EXEC_STOP_POST])) { | |
377 | ||
378 | if ((r = socket_spawn(s, s->control_command, true, &s->control_pid)) < 0) | |
379 | goto fail; | |
380 | ||
381 | socket_set_state(s, SOCKET_STOP_POST); | |
382 | } else | |
383 | socket_enter_dead(s, true); | |
384 | ||
385 | return; | |
386 | ||
387 | fail: | |
87f0e418 | 388 | log_warning("%s failed to run stop-post executable: %s", unit_id(UNIT(s)), strerror(-r)); |
034c6ed7 LP |
389 | socket_enter_dead(s, false); |
390 | } | |
391 | ||
392 | static void socket_enter_signal(Socket *s, SocketState state, bool success) { | |
393 | int r; | |
394 | ||
395 | assert(s); | |
396 | ||
397 | if (!success) | |
398 | s->failure = true; | |
399 | ||
400 | if (s->control_pid > 0) { | |
401 | int sig; | |
402 | ||
403 | sig = (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_POST_SIGTERM) ? SIGTERM : SIGKILL; | |
404 | ||
405 | if (kill(s->control_pid, sig) < 0 && errno != ESRCH) { | |
406 | r = -errno; | |
407 | goto fail; | |
408 | } | |
409 | ||
410 | socket_set_state(s, state); | |
411 | } else | |
412 | socket_enter_dead(s, true); | |
413 | ||
414 | return; | |
415 | ||
416 | fail: | |
87f0e418 | 417 | log_warning("%s failed to kill processes: %s", unit_id(UNIT(s)), strerror(-r)); |
034c6ed7 LP |
418 | |
419 | if (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_PRE_SIGKILL) | |
420 | socket_enter_stop_post(s, false); | |
421 | else | |
422 | socket_enter_dead(s, false); | |
423 | } | |
424 | ||
425 | static void socket_enter_stop_pre(Socket *s, bool success) { | |
426 | int r; | |
427 | assert(s); | |
428 | ||
429 | if (!success) | |
430 | s->failure = true; | |
431 | ||
432 | if ((s->control_command = s->exec_command[SOCKET_EXEC_STOP_PRE])) { | |
433 | ||
434 | if ((r = socket_spawn(s, s->control_command, true, &s->control_pid)) < 0) | |
435 | goto fail; | |
436 | ||
437 | socket_set_state(s, SOCKET_STOP_PRE); | |
438 | } else | |
439 | socket_enter_stop_post(s, true); | |
440 | ||
441 | return; | |
442 | ||
443 | fail: | |
87f0e418 | 444 | log_warning("%s failed to run stop-pre executable: %s", unit_id(UNIT(s)), strerror(-r)); |
034c6ed7 LP |
445 | socket_enter_stop_post(s, false); |
446 | } | |
447 | ||
448 | static void socket_enter_start_post(Socket *s) { | |
449 | int r; | |
450 | assert(s); | |
451 | ||
452 | if ((r = socket_open_fds(s)) < 0 || | |
453 | (r = socket_watch_fds(s)) < 0) { | |
87f0e418 | 454 | log_warning("%s failed to listen on sockets: %s", unit_id(UNIT(s)), strerror(-r)); |
034c6ed7 LP |
455 | goto fail; |
456 | } | |
457 | ||
458 | if ((s->control_command = s->exec_command[SOCKET_EXEC_START_POST])) { | |
459 | ||
460 | if ((r = socket_spawn(s, s->control_command, true, &s->control_pid)) < 0) { | |
87f0e418 | 461 | log_warning("%s failed to run start-post executable: %s", unit_id(UNIT(s)), strerror(-r)); |
034c6ed7 LP |
462 | goto fail; |
463 | } | |
464 | ||
465 | socket_set_state(s, SOCKET_START_POST); | |
466 | } else | |
467 | socket_set_state(s, SOCKET_LISTENING); | |
468 | ||
469 | return; | |
470 | ||
471 | fail: | |
472 | socket_enter_stop_pre(s, false); | |
473 | } | |
474 | ||
475 | static void socket_enter_start_pre(Socket *s) { | |
476 | int r; | |
477 | assert(s); | |
478 | ||
479 | if ((s->control_command = s->exec_command[SOCKET_EXEC_START_PRE])) { | |
480 | ||
481 | if ((r = socket_spawn(s, s->control_command, true, &s->control_pid)) < 0) | |
482 | goto fail; | |
483 | ||
484 | socket_set_state(s, SOCKET_START_PRE); | |
485 | } else | |
486 | socket_enter_start_post(s); | |
487 | ||
488 | return; | |
489 | ||
490 | fail: | |
87f0e418 | 491 | log_warning("%s failed to run start-pre exectuable: %s", unit_id(UNIT(s)), strerror(-r)); |
034c6ed7 LP |
492 | socket_enter_dead(s, false); |
493 | } | |
494 | ||
495 | static void socket_enter_running(Socket *s) { | |
496 | int r; | |
497 | ||
498 | assert(s); | |
499 | ||
87f0e418 | 500 | if ((r = manager_add_job(UNIT(s)->meta.manager, JOB_START, UNIT(s->service), JOB_REPLACE, true, NULL)) < 0) |
034c6ed7 LP |
501 | goto fail; |
502 | ||
503 | socket_set_state(s, SOCKET_RUNNING); | |
504 | return; | |
505 | ||
506 | fail: | |
87f0e418 | 507 | log_warning("%s failed to queue socket startup job: %s", unit_id(UNIT(s)), strerror(-r)); |
034c6ed7 LP |
508 | socket_enter_dead(s, false); |
509 | } | |
510 | ||
511 | static void socket_run_next(Socket *s, bool success) { | |
512 | int r; | |
513 | ||
514 | assert(s); | |
515 | assert(s->control_command); | |
516 | assert(s->control_command->command_next); | |
517 | ||
518 | if (!success) | |
519 | s->failure = true; | |
520 | ||
521 | s->control_command = s->control_command->command_next; | |
522 | ||
523 | if ((r = socket_spawn(s, s->control_command, true, &s->control_pid)) < 0) | |
524 | goto fail; | |
525 | ||
526 | return; | |
527 | ||
528 | fail: | |
529 | if (s->state == SOCKET_STOP_PRE) | |
530 | socket_enter_stop_post(s, false); | |
531 | else if (s->state == SOCKET_STOP_POST) | |
532 | socket_enter_dead(s, false); | |
533 | else | |
534 | socket_enter_stop_pre(s, false); | |
535 | } | |
536 | ||
87f0e418 LP |
537 | static int socket_start(Unit *u) { |
538 | Socket *s = SOCKET(u); | |
83c60c9f LP |
539 | |
540 | assert(s); | |
541 | ||
034c6ed7 LP |
542 | /* We cannot fulfill this request right now, try again later |
543 | * please! */ | |
544 | if (s->state == SOCKET_STOP_PRE || | |
545 | s->state == SOCKET_STOP_PRE_SIGKILL || | |
546 | s->state == SOCKET_STOP_PRE_SIGTERM || | |
547 | s->state == SOCKET_STOP_POST || | |
548 | s->state == SOCKET_STOP_POST_SIGTERM || | |
549 | s->state == SOCKET_STOP_POST_SIGKILL) | |
550 | return -EAGAIN; | |
551 | ||
83c60c9f LP |
552 | if (s->state == SOCKET_START_PRE || |
553 | s->state == SOCKET_START_POST) | |
034c6ed7 | 554 | return 0; |
83c60c9f | 555 | |
034c6ed7 | 556 | /* Cannot run this without the service being around */ |
87f0e418 | 557 | if (s->service->meta.load_state != UNIT_LOADED) |
034c6ed7 | 558 | return -ENOENT; |
83c60c9f | 559 | |
034c6ed7 | 560 | assert(s->state == SOCKET_DEAD || s->state == SOCKET_MAINTAINANCE); |
83c60c9f | 561 | |
034c6ed7 LP |
562 | s->failure = false; |
563 | socket_enter_start_pre(s); | |
564 | return 0; | |
565 | } | |
83c60c9f | 566 | |
87f0e418 LP |
567 | static int socket_stop(Unit *u) { |
568 | Socket *s = SOCKET(u); | |
034c6ed7 LP |
569 | |
570 | assert(s); | |
571 | ||
572 | /* We cannot fulfill this request right now, try again later | |
573 | * please! */ | |
574 | if (s->state == SOCKET_START_PRE || | |
575 | s->state == SOCKET_START_POST) | |
576 | return -EAGAIN; | |
83c60c9f | 577 | |
034c6ed7 | 578 | assert(s->state == SOCKET_LISTENING || s->state == SOCKET_RUNNING); |
83c60c9f | 579 | |
034c6ed7 | 580 | socket_enter_stop_pre(s, true); |
542563ba LP |
581 | return 0; |
582 | } | |
583 | ||
87f0e418 LP |
584 | static UnitActiveState socket_active_state(Unit *u) { |
585 | assert(u); | |
5cb5a6ff | 586 | |
87f0e418 | 587 | return state_table[SOCKET(u)->state]; |
5cb5a6ff LP |
588 | } |
589 | ||
87f0e418 LP |
590 | static void socket_fd_event(Unit *u, int fd, uint32_t events) { |
591 | Socket *s = SOCKET(u); | |
9152c765 | 592 | |
034c6ed7 | 593 | assert(s); |
9152c765 | 594 | |
87f0e418 | 595 | log_info("Incoming traffic on %s", unit_id(u)); |
9152c765 | 596 | |
034c6ed7 LP |
597 | if (events != POLLIN) |
598 | socket_enter_stop_pre(s, false); | |
9152c765 | 599 | |
034c6ed7 | 600 | socket_enter_running(s); |
9152c765 LP |
601 | } |
602 | ||
87f0e418 LP |
603 | static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) { |
604 | Socket *s = SOCKET(u); | |
034c6ed7 | 605 | bool success; |
5cb5a6ff LP |
606 | |
607 | assert(s); | |
034c6ed7 | 608 | assert(pid >= 0); |
5cb5a6ff | 609 | |
034c6ed7 LP |
610 | success = code == CLD_EXITED || status == 0; |
611 | s->failure = s->failure || !success; | |
542563ba | 612 | |
034c6ed7 LP |
613 | assert(s->control_pid == pid); |
614 | assert(s->control_command); | |
615 | ||
616 | exec_status_fill(&s->control_command->exec_status, pid, code, status); | |
617 | s->control_pid = 0; | |
618 | ||
87f0e418 | 619 | log_debug("%s: control process exited, code=%s status=%i", unit_id(u), sigchld_code(code), status); |
034c6ed7 LP |
620 | |
621 | if (s->control_command->command_next && | |
622 | (success || (s->state == SOCKET_EXEC_STOP_PRE || s->state == SOCKET_EXEC_STOP_POST))) | |
623 | socket_run_next(s, success); | |
624 | else { | |
625 | /* No further commands for this step, so let's figure | |
626 | * out what to do next */ | |
5cb5a6ff | 627 | |
034c6ed7 LP |
628 | switch (s->state) { |
629 | ||
630 | case SOCKET_START_PRE: | |
631 | if (success) | |
632 | socket_enter_start_pre(s); | |
633 | else | |
634 | socket_enter_stop_pre(s, false); | |
635 | break; | |
636 | ||
637 | case SOCKET_START_POST: | |
638 | if (success) | |
639 | socket_set_state(s, SOCKET_LISTENING); | |
640 | else | |
641 | socket_enter_stop_pre(s, false); | |
642 | break; | |
643 | ||
644 | case SOCKET_STOP_PRE: | |
645 | case SOCKET_STOP_PRE_SIGTERM: | |
646 | case SOCKET_STOP_PRE_SIGKILL: | |
647 | socket_enter_stop_post(s, success); | |
648 | break; | |
649 | ||
650 | case SOCKET_STOP_POST: | |
651 | case SOCKET_STOP_POST_SIGTERM: | |
652 | case SOCKET_STOP_POST_SIGKILL: | |
653 | socket_enter_dead(s, success); | |
654 | break; | |
655 | ||
656 | default: | |
657 | assert_not_reached("Uh, control process died at wrong time."); | |
658 | } | |
659 | } | |
660 | } | |
5cb5a6ff | 661 | |
87f0e418 LP |
662 | static void socket_timer_event(Unit *u, int id, uint64_t elapsed) { |
663 | Socket *s = SOCKET(u); | |
5cb5a6ff | 664 | |
034c6ed7 LP |
665 | assert(s); |
666 | assert(elapsed == 1); | |
667 | ||
668 | assert(s->timer_id == id); | |
669 | ||
670 | switch (s->state) { | |
671 | ||
672 | case SOCKET_START_PRE: | |
673 | case SOCKET_START_POST: | |
87f0e418 | 674 | log_warning("%s operation timed out. Stopping.", unit_id(u)); |
034c6ed7 LP |
675 | socket_enter_stop_pre(s, false); |
676 | break; | |
677 | ||
678 | case SOCKET_STOP_PRE: | |
87f0e418 | 679 | log_warning("%s stopping timed out. Terminating.", unit_id(u)); |
034c6ed7 LP |
680 | socket_enter_signal(s, SOCKET_STOP_PRE_SIGTERM, false); |
681 | break; | |
682 | ||
683 | case SOCKET_STOP_PRE_SIGTERM: | |
87f0e418 | 684 | log_warning("%s stopping timed out. Killing.", unit_id(u)); |
034c6ed7 LP |
685 | socket_enter_signal(s, SOCKET_STOP_PRE_SIGKILL, false); |
686 | break; | |
687 | ||
688 | case SOCKET_STOP_PRE_SIGKILL: | |
87f0e418 | 689 | log_warning("%s still around after SIGKILL. Ignoring.", unit_id(u)); |
034c6ed7 LP |
690 | socket_enter_stop_post(s, false); |
691 | break; | |
692 | ||
693 | case SOCKET_STOP_POST: | |
87f0e418 | 694 | log_warning("%s stopping timed out (2). Terminating.", unit_id(u)); |
034c6ed7 LP |
695 | socket_enter_signal(s, SOCKET_STOP_POST_SIGTERM, false); |
696 | break; | |
697 | ||
698 | case SOCKET_STOP_POST_SIGTERM: | |
87f0e418 | 699 | log_warning("%s stopping timed out (2). Killing.", unit_id(u)); |
034c6ed7 LP |
700 | socket_enter_signal(s, SOCKET_STOP_POST_SIGKILL, false); |
701 | break; | |
702 | ||
703 | case SOCKET_STOP_POST_SIGKILL: | |
87f0e418 | 704 | log_warning("%s still around after SIGKILL (2). Entering maintainance mode.", unit_id(u)); |
034c6ed7 LP |
705 | socket_enter_dead(s, false); |
706 | break; | |
707 | ||
708 | default: | |
709 | assert_not_reached("Timeout at wrong time."); | |
710 | } | |
5cb5a6ff LP |
711 | } |
712 | ||
44d8db9e LP |
713 | int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds) { |
714 | int *rfds; | |
715 | unsigned rn_fds, k; | |
716 | SocketPort *p; | |
717 | ||
718 | assert(s); | |
719 | assert(fds); | |
720 | assert(n_fds); | |
721 | ||
722 | /* Called from the service code for requesting our fds */ | |
723 | ||
724 | rn_fds = 0; | |
725 | LIST_FOREACH(port, p, s->ports) | |
726 | if (p->fd >= 0) | |
727 | rn_fds++; | |
728 | ||
729 | if (!(rfds = new(int, rn_fds)) < 0) | |
730 | return -ENOMEM; | |
731 | ||
732 | k = 0; | |
733 | LIST_FOREACH(port, p, s->ports) | |
734 | if (p->fd >= 0) | |
735 | rfds[k++] = p->fd; | |
736 | ||
737 | assert(k == rn_fds); | |
738 | ||
739 | *fds = rfds; | |
740 | *n_fds = rn_fds; | |
741 | ||
742 | return 0; | |
743 | } | |
744 | ||
87f0e418 | 745 | const UnitVTable socket_vtable = { |
5cb5a6ff LP |
746 | .suffix = ".socket", |
747 | ||
034c6ed7 LP |
748 | .init = socket_init, |
749 | .done = socket_done, | |
750 | ||
5cb5a6ff LP |
751 | .dump = socket_dump, |
752 | ||
542563ba LP |
753 | .start = socket_start, |
754 | .stop = socket_stop, | |
5cb5a6ff LP |
755 | |
756 | .active_state = socket_active_state, | |
757 | ||
9152c765 | 758 | .fd_event = socket_fd_event, |
034c6ed7 LP |
759 | .sigchld_event = socket_sigchld_event, |
760 | .timer_event = socket_timer_event | |
5cb5a6ff | 761 | }; |