]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/socket-proxy/socket-proxyd.c
treewide: use log_*_errno whenever %m is in the format string
[thirdparty/systemd.git] / src / socket-proxy / socket-proxyd.c
CommitLineData
912b54ad
DS
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 David Strauss
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22#include <arpa/inet.h>
23#include <errno.h>
24#include <getopt.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <netdb.h>
fdb8bd0f 29#include <fcntl.h>
912b54ad
DS
30#include <sys/socket.h>
31#include <sys/un.h>
32#include <unistd.h>
33
912b54ad
DS
34#include "sd-daemon.h"
35#include "sd-event.h"
fb69d709 36#include "sd-resolve.h"
96c374d0 37#include "log.h"
912b54ad
DS
38#include "socket-util.h"
39#include "util.h"
96c374d0 40#include "event-util.h"
eb9da376 41#include "build.h"
8569a776
LP
42#include "set.h"
43#include "path-util.h"
44
45#define BUFFER_SIZE (256 * 1024)
46#define CONNECTIONS_MAX 256
912b54ad 47
fb69d709
LP
48static const char *arg_remote_host = NULL;
49
8569a776 50typedef struct Context {
fb69d709
LP
51 sd_event *event;
52 sd_resolve *resolve;
53
8569a776
LP
54 Set *listen;
55 Set *connections;
56} Context;
912b54ad 57
8569a776 58typedef struct Connection {
e633ea1c
LP
59 Context *context;
60
8569a776
LP
61 int server_fd, client_fd;
62 int server_to_client_buffer[2]; /* a pipe */
63 int client_to_server_buffer[2]; /* a pipe */
912b54ad 64
8569a776
LP
65 size_t server_to_client_buffer_full, client_to_server_buffer_full;
66 size_t server_to_client_buffer_size, client_to_server_buffer_size;
67
68 sd_event_source *server_event_source, *client_event_source;
912b54ad 69
fb69d709
LP
70 sd_resolve_query *resolve_query;
71} Connection;
912b54ad 72
8569a776
LP
73static void connection_free(Connection *c) {
74 assert(c);
32d3c809 75
e633ea1c
LP
76 if (c->context)
77 set_remove(c->context->connections, c);
78
8569a776
LP
79 sd_event_source_unref(c->server_event_source);
80 sd_event_source_unref(c->client_event_source);
32d3c809 81
03e334a1
LP
82 safe_close(c->server_fd);
83 safe_close(c->client_fd);
32d3c809 84
3d94f76c
LP
85 safe_close_pair(c->server_to_client_buffer);
86 safe_close_pair(c->client_to_server_buffer);
32d3c809 87
fb69d709
LP
88 sd_resolve_query_unref(c->resolve_query);
89
8569a776
LP
90 free(c);
91}
32d3c809 92
8569a776
LP
93static void context_free(Context *context) {
94 sd_event_source *es;
95 Connection *c;
96
97 assert(context);
98
99 while ((es = set_steal_first(context->listen)))
100 sd_event_source_unref(es);
101
e633ea1c 102 while ((c = set_first(context->connections)))
8569a776
LP
103 connection_free(c);
104
105 set_free(context->listen);
106 set_free(context->connections);
32d3c809 107
fb69d709
LP
108 sd_event_unref(context->event);
109 sd_resolve_unref(context->resolve);
8569a776 110}
912b54ad 111
8569a776
LP
112static int connection_create_pipes(Connection *c, int buffer[2], size_t *sz) {
113 int r;
912b54ad 114
8569a776
LP
115 assert(c);
116 assert(buffer);
117 assert(sz);
912b54ad 118
8569a776
LP
119 if (buffer[0] >= 0)
120 return 0;
912b54ad 121
8569a776 122 r = pipe2(buffer, O_CLOEXEC|O_NONBLOCK);
912b54ad 123 if (r < 0) {
56f64d95 124 log_error_errno(errno, "Failed to allocate pipe buffer: %m");
8569a776 125 return -errno;
912b54ad
DS
126 }
127
25dbe4f5 128 (void) fcntl(buffer[0], F_SETPIPE_SZ, BUFFER_SIZE);
8569a776
LP
129
130 r = fcntl(buffer[0], F_GETPIPE_SZ);
912b54ad 131 if (r < 0) {
56f64d95 132 log_error_errno(errno, "Failed to get pipe buffer size: %m");
8569a776 133 return -errno;
912b54ad
DS
134 }
135
8569a776
LP
136 assert(r > 0);
137 *sz = r;
138
912b54ad
DS
139 return 0;
140}
141
8569a776
LP
142static int connection_shovel(
143 Connection *c,
144 int *from, int buffer[2], int *to,
145 size_t *full, size_t *sz,
146 sd_event_source **from_source, sd_event_source **to_source) {
147
148 bool shoveled;
149
150 assert(c);
151 assert(from);
152 assert(buffer);
153 assert(buffer[0] >= 0);
154 assert(buffer[1] >= 0);
155 assert(to);
156 assert(full);
157 assert(sz);
158 assert(from_source);
159 assert(to_source);
160
161 do {
162 ssize_t z;
163
164 shoveled = false;
165
166 if (*full < *sz && *from >= 0 && *to >= 0) {
167 z = splice(*from, NULL, buffer[1], NULL, *sz - *full, SPLICE_F_MOVE|SPLICE_F_NONBLOCK);
168 if (z > 0) {
169 *full += z;
170 shoveled = true;
171 } else if (z == 0 || errno == EPIPE || errno == ECONNRESET) {
172 *from_source = sd_event_source_unref(*from_source);
03e334a1 173 *from = safe_close(*from);
8569a776 174 } else if (errno != EAGAIN && errno != EINTR) {
56f64d95 175 log_error_errno(errno, "Failed to splice: %m");
8569a776 176 return -errno;
912b54ad 177 }
912b54ad
DS
178 }
179
8569a776
LP
180 if (*full > 0 && *to >= 0) {
181 z = splice(buffer[0], NULL, *to, NULL, *full, SPLICE_F_MOVE|SPLICE_F_NONBLOCK);
182 if (z > 0) {
183 *full -= z;
184 shoveled = true;
185 } else if (z == 0 || errno == EPIPE || errno == ECONNRESET) {
186 *to_source = sd_event_source_unref(*to_source);
03e334a1 187 *to = safe_close(*to);
8569a776 188 } else if (errno != EAGAIN && errno != EINTR) {
56f64d95 189 log_error_errno(errno, "Failed to splice: %m");
8569a776
LP
190 return -errno;
191 }
192 }
193 } while (shoveled);
912b54ad 194
8569a776 195 return 0;
912b54ad
DS
196}
197
fb69d709 198static int connection_enable_event_sources(Connection *c);
8569a776
LP
199
200static int traffic_cb(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
201 Connection *c = userdata;
912b54ad
DS
202 int r;
203
8569a776
LP
204 assert(s);
205 assert(fd >= 0);
206 assert(c);
912b54ad 207
8569a776
LP
208 r = connection_shovel(c,
209 &c->server_fd, c->server_to_client_buffer, &c->client_fd,
210 &c->server_to_client_buffer_full, &c->server_to_client_buffer_size,
211 &c->server_event_source, &c->client_event_source);
212 if (r < 0)
213 goto quit;
912b54ad 214
8569a776
LP
215 r = connection_shovel(c,
216 &c->client_fd, c->client_to_server_buffer, &c->server_fd,
217 &c->client_to_server_buffer_full, &c->client_to_server_buffer_size,
218 &c->client_event_source, &c->server_event_source);
219 if (r < 0)
220 goto quit;
912b54ad 221
8569a776
LP
222 /* EOF on both sides? */
223 if (c->server_fd == -1 && c->client_fd == -1)
224 goto quit;
912b54ad 225
8569a776
LP
226 /* Server closed, and all data written to client? */
227 if (c->server_fd == -1 && c->server_to_client_buffer_full <= 0)
228 goto quit;
912b54ad 229
8569a776
LP
230 /* Client closed, and all data written to server? */
231 if (c->client_fd == -1 && c->client_to_server_buffer_full <= 0)
232 goto quit;
912b54ad 233
fb69d709 234 r = connection_enable_event_sources(c);
8569a776
LP
235 if (r < 0)
236 goto quit;
912b54ad 237
8569a776 238 return 1;
912b54ad 239
8569a776
LP
240quit:
241 connection_free(c);
242 return 0; /* ignore errors, continue serving */
912b54ad
DS
243}
244
fb69d709 245static int connection_enable_event_sources(Connection *c) {
8569a776
LP
246 uint32_t a = 0, b = 0;
247 int r;
912b54ad 248
8569a776 249 assert(c);
912b54ad 250
8569a776
LP
251 if (c->server_to_client_buffer_full > 0)
252 b |= EPOLLOUT;
253 if (c->server_to_client_buffer_full < c->server_to_client_buffer_size)
254 a |= EPOLLIN;
912b54ad 255
8569a776
LP
256 if (c->client_to_server_buffer_full > 0)
257 a |= EPOLLOUT;
258 if (c->client_to_server_buffer_full < c->client_to_server_buffer_size)
259 b |= EPOLLIN;
912b54ad 260
8569a776
LP
261 if (c->server_event_source)
262 r = sd_event_source_set_io_events(c->server_event_source, a);
263 else if (c->server_fd >= 0)
fb69d709 264 r = sd_event_add_io(c->context->event, &c->server_event_source, c->server_fd, a, traffic_cb, c);
8569a776
LP
265 else
266 r = 0;
267
f647962d
MS
268 if (r < 0)
269 return log_error_errno(r, "Failed to set up server event source: %m");
912b54ad 270
8569a776
LP
271 if (c->client_event_source)
272 r = sd_event_source_set_io_events(c->client_event_source, b);
273 else if (c->client_fd >= 0)
fb69d709 274 r = sd_event_add_io(c->context->event, &c->client_event_source, c->client_fd, b, traffic_cb, c);
8569a776
LP
275 else
276 r = 0;
912b54ad 277
f647962d
MS
278 if (r < 0)
279 return log_error_errno(r, "Failed to set up client event source: %m");
912b54ad 280
8569a776 281 return 0;
912b54ad
DS
282}
283
fb69d709
LP
284static int connection_complete(Connection *c) {
285 int r;
286
287 assert(c);
288
289 r = connection_create_pipes(c, c->server_to_client_buffer, &c->server_to_client_buffer_size);
290 if (r < 0)
291 goto fail;
292
293 r = connection_create_pipes(c, c->client_to_server_buffer, &c->client_to_server_buffer_size);
294 if (r < 0)
295 goto fail;
296
297 r = connection_enable_event_sources(c);
298 if (r < 0)
299 goto fail;
300
301 return 0;
302
303fail:
304 connection_free(c);
305 return 0; /* ignore errors, continue serving */
306}
307
8569a776
LP
308static int connect_cb(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
309 Connection *c = userdata;
310 socklen_t solen;
311 int error, r;
312
313 assert(s);
314 assert(fd >= 0);
315 assert(c);
316
317 solen = sizeof(error);
318 r = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &solen);
319 if (r < 0) {
56f64d95 320 log_error_errno(errno, "Failed to issue SO_ERROR: %m");
40976028
DS
321 goto fail;
322 }
912b54ad 323
8569a776 324 if (error != 0) {
279d3c9c 325 log_error_errno(error, "Failed to connect to remote host: %m");
912b54ad
DS
326 goto fail;
327 }
328
8569a776
LP
329 c->client_event_source = sd_event_source_unref(c->client_event_source);
330
fb69d709 331 return connection_complete(c);
912b54ad 332
fb69d709
LP
333fail:
334 connection_free(c);
335 return 0; /* ignore errors, continue serving */
336}
912b54ad 337
fb69d709
LP
338static int connection_start(Connection *c, struct sockaddr *sa, socklen_t salen) {
339 int r;
340
341 assert(c);
342 assert(sa);
343 assert(salen);
344
345 c->client_fd = socket(sa->sa_family, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
346 if (c->client_fd < 0) {
56f64d95 347 log_error_errno(errno, "Failed to get remote socket: %m");
8569a776 348 goto fail;
fb69d709
LP
349 }
350
351 r = connect(c->client_fd, sa, salen);
352 if (r < 0) {
353 if (errno == EINPROGRESS) {
354 r = sd_event_add_io(c->context->event, &c->client_event_source, c->client_fd, EPOLLOUT, connect_cb, c);
355 if (r < 0) {
da927ba9 356 log_error_errno(r, "Failed to add connection socket: %m");
fb69d709
LP
357 goto fail;
358 }
359
360 r = sd_event_source_set_enabled(c->client_event_source, SD_EVENT_ONESHOT);
361 if (r < 0) {
da927ba9 362 log_error_errno(r, "Failed to enable oneshot event source: %m");
fb69d709
LP
363 goto fail;
364 }
365 } else {
56f64d95 366 log_error_errno(errno, "Failed to connect to remote host: %m");
fb69d709
LP
367 goto fail;
368 }
369 } else {
370 r = connection_complete(c);
371 if (r < 0)
372 goto fail;
373 }
912b54ad 374
8569a776 375 return 0;
912b54ad 376
8569a776
LP
377fail:
378 connection_free(c);
379 return 0; /* ignore errors, continue serving */
380}
381
fb69d709
LP
382static int resolve_cb(sd_resolve_query *q, int ret, const struct addrinfo *ai, void *userdata) {
383 Connection *c = userdata;
384
385 assert(q);
386 assert(c);
387
388 if (ret != 0) {
389 log_error("Failed to resolve host: %s", gai_strerror(ret));
390 goto fail;
391 }
392
393 c->resolve_query = sd_resolve_query_unref(c->resolve_query);
394
395 return connection_start(c, ai->ai_addr, ai->ai_addrlen);
396
397fail:
398 connection_free(c);
399 return 0; /* ignore errors, continue serving */
400}
401
402static int resolve_remote(Connection *c) {
403
404 static const struct addrinfo hints = {
405 .ai_family = AF_UNSPEC,
406 .ai_socktype = SOCK_STREAM,
407 .ai_flags = AI_ADDRCONFIG
408 };
409
1ec6af16 410 union sockaddr_union sa = {};
fb69d709 411 const char *node, *service;
8569a776 412 socklen_t salen;
fb69d709
LP
413 int r;
414
415 if (path_is_absolute(arg_remote_host)) {
416 sa.un.sun_family = AF_UNIX;
417 strncpy(sa.un.sun_path, arg_remote_host, sizeof(sa.un.sun_path)-1);
418 sa.un.sun_path[sizeof(sa.un.sun_path)-1] = 0;
419
420 salen = offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path);
421
422 return connection_start(c, &sa.sa, salen);
423 }
424
425 if (arg_remote_host[0] == '@') {
426 sa.un.sun_family = AF_UNIX;
427 sa.un.sun_path[0] = 0;
428 strncpy(sa.un.sun_path+1, arg_remote_host+1, sizeof(sa.un.sun_path)-2);
429 sa.un.sun_path[sizeof(sa.un.sun_path)-1] = 0;
430
431 salen = offsetof(union sockaddr_union, un.sun_path) + 1 + strlen(sa.un.sun_path + 1);
432
433 return connection_start(c, &sa.sa, salen);
434 }
435
436 service = strrchr(arg_remote_host, ':');
437 if (service) {
438 node = strndupa(arg_remote_host, service - arg_remote_host);
439 service ++;
440 } else {
441 node = arg_remote_host;
442 service = "80";
443 }
444
445 log_debug("Looking up address info for %s:%s", node, service);
446 r = sd_resolve_getaddrinfo(c->context->resolve, &c->resolve_query, node, service, &hints, resolve_cb, c);
447 if (r < 0) {
da927ba9 448 log_error_errno(r, "Failed to resolve remote host: %m");
fb69d709
LP
449 goto fail;
450 }
451
452 return 0;
453
454fail:
455 connection_free(c);
456 return 0; /* ignore errors, continue serving */
457}
458
459static int add_connection_socket(Context *context, int fd) {
8569a776
LP
460 Connection *c;
461 int r;
462
463 assert(context);
8569a776
LP
464 assert(fd >= 0);
465
466 if (set_size(context->connections) > CONNECTIONS_MAX) {
467 log_warning("Hit connection limit, refusing connection.");
03e334a1 468 safe_close(fd);
8569a776 469 return 0;
912b54ad
DS
470 }
471
d5099efc 472 r = set_ensure_allocated(&context->connections, NULL);
fb69d709
LP
473 if (r < 0) {
474 log_oom();
475 return 0;
476 }
912b54ad 477
8569a776 478 c = new0(Connection, 1);
fb69d709
LP
479 if (!c) {
480 log_oom();
481 return 0;
482 }
8569a776 483
e633ea1c 484 c->context = context;
8569a776
LP
485 c->server_fd = fd;
486 c->client_fd = -1;
487 c->server_to_client_buffer[0] = c->server_to_client_buffer[1] = -1;
488 c->client_to_server_buffer[0] = c->client_to_server_buffer[1] = -1;
489
e633ea1c
LP
490 r = set_put(context->connections, c);
491 if (r < 0) {
492 free(c);
fb69d709
LP
493 log_oom();
494 return 0;
8569a776 495 }
912b54ad 496
fb69d709 497 return resolve_remote(c);
40976028
DS
498}
499
500static int accept_cb(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
7b77ed8c 501 _cleanup_free_ char *peer = NULL;
8569a776
LP
502 Context *context = userdata;
503 int nfd = -1, r;
40976028 504
8569a776
LP
505 assert(s);
506 assert(fd >= 0);
40976028 507 assert(revents & EPOLLIN);
8569a776
LP
508 assert(context);
509
510 nfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
7b77ed8c
LP
511 if (nfd < 0) {
512 if (errno != -EAGAIN)
56f64d95 513 log_warning_errno(errno, "Failed to accept() socket: %m");
7b77ed8c 514 } else {
8569a776
LP
515 getpeername_pretty(nfd, &peer);
516 log_debug("New connection from %s", strna(peer));
40976028 517
fb69d709 518 r = add_connection_socket(context, nfd);
f4bd42aa 519 if (r < 0) {
da927ba9 520 log_error_errno(r, "Failed to accept connection, ignoring: %m");
03e334a1 521 safe_close(fd);
f4bd42aa 522 }
7b77ed8c 523 }
8569a776 524
40976028
DS
525 r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT);
526 if (r < 0) {
da927ba9 527 log_error_errno(r, "Error while re-enabling listener with ONESHOT: %m");
fb69d709 528 sd_event_exit(context->event, r);
40976028
DS
529 return r;
530 }
531
96c374d0 532 return 1;
912b54ad
DS
533}
534
fb69d709 535static int add_listen_socket(Context *context, int fd) {
8569a776
LP
536 sd_event_source *source;
537 int r;
538
539 assert(context);
8569a776 540 assert(fd >= 0);
912b54ad 541
d5099efc 542 r = set_ensure_allocated(&context->listen, NULL);
96c374d0 543 if (r < 0) {
8569a776
LP
544 log_oom();
545 return r;
546 }
547
548 r = sd_is_socket(fd, 0, SOCK_STREAM, 1);
f647962d
MS
549 if (r < 0)
550 return log_error_errno(r, "Failed to determine socket type: %m");
8569a776
LP
551 if (r == 0) {
552 log_error("Passed in socket is not a stream socket.");
553 return -EINVAL;
554 }
912b54ad 555
8569a776 556 r = fd_nonblock(fd, true);
f647962d
MS
557 if (r < 0)
558 return log_error_errno(r, "Failed to mark file descriptor non-blocking: %m");
912b54ad 559
fb69d709 560 r = sd_event_add_io(context->event, &source, fd, EPOLLIN, accept_cb, context);
f647962d
MS
561 if (r < 0)
562 return log_error_errno(r, "Failed to add event source: %m");
912b54ad 563
8569a776 564 r = set_put(context->listen, source);
96c374d0 565 if (r < 0) {
da927ba9 566 log_error_errno(r, "Failed to add source to set: %m");
8569a776 567 sd_event_source_unref(source);
40976028
DS
568 return r;
569 }
570
571 /* Set the watcher to oneshot in case other processes are also
572 * watching to accept(). */
8569a776 573 r = sd_event_source_set_enabled(source, SD_EVENT_ONESHOT);
f647962d
MS
574 if (r < 0)
575 return log_error_errno(r, "Failed to enable oneshot mode: %m");
912b54ad 576
8569a776 577 return 0;
912b54ad
DS
578}
579
601185b4
ZJS
580static void help(void) {
581 printf("%1$s [HOST:PORT]\n"
582 "%1$s [SOCKET]\n\n"
8569a776 583 "Bidirectionally proxy local sockets to another (possibly remote) socket.\n\n"
8cf030b3
LP
584 " -h --help Show this help\n"
585 " --version Show package version\n",
912b54ad 586 program_invocation_short_name);
912b54ad
DS
587}
588
8569a776 589static int parse_argv(int argc, char *argv[]) {
912b54ad
DS
590
591 enum {
8cf030b3
LP
592 ARG_VERSION = 0x100,
593 ARG_IGNORE_ENV
912b54ad
DS
594 };
595
596 static const struct option options[] = {
8cf030b3
LP
597 { "help", no_argument, NULL, 'h' },
598 { "version", no_argument, NULL, ARG_VERSION },
eb9da376 599 {}
912b54ad
DS
600 };
601
8cf030b3 602 int c;
912b54ad
DS
603
604 assert(argc >= 0);
605 assert(argv);
606
601185b4 607 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
912b54ad
DS
608
609 switch (c) {
610
611 case 'h':
601185b4
ZJS
612 help();
613 return 0;
912b54ad
DS
614
615 case ARG_VERSION:
eb9da376
LP
616 puts(PACKAGE_STRING);
617 puts(SYSTEMD_FEATURES);
912b54ad
DS
618 return 0;
619
eb9da376 620 case '?':
912b54ad 621 return -EINVAL;
eb9da376
LP
622
623 default:
624 assert_not_reached("Unhandled option");
912b54ad 625 }
912b54ad 626
8569a776
LP
627 if (optind >= argc) {
628 log_error("Not enough parameters.");
912b54ad
DS
629 return -EINVAL;
630 }
631
8569a776
LP
632 if (argc != optind+1) {
633 log_error("Too many parameters.");
912b54ad
DS
634 return -EINVAL;
635 }
636
8569a776 637 arg_remote_host = argv[optind];
912b54ad
DS
638 return 1;
639}
640
641int main(int argc, char *argv[]) {
8569a776
LP
642 Context context = {};
643 int r, n, fd;
912b54ad
DS
644
645 log_parse_environment();
646 log_open();
647
8569a776 648 r = parse_argv(argc, argv);
912b54ad
DS
649 if (r <= 0)
650 goto finish;
651
fb69d709 652 r = sd_event_default(&context.event);
8569a776 653 if (r < 0) {
da927ba9 654 log_error_errno(r, "Failed to allocate event loop: %m");
8569a776
LP
655 goto finish;
656 }
912b54ad 657
fb69d709
LP
658 r = sd_resolve_default(&context.resolve);
659 if (r < 0) {
da927ba9 660 log_error_errno(r, "Failed to allocate resolver: %m");
fb69d709
LP
661 goto finish;
662 }
663
664 r = sd_resolve_attach_event(context.resolve, context.event, 0);
665 if (r < 0) {
da927ba9 666 log_error_errno(r, "Failed to attach resolver: %m");
fb69d709
LP
667 goto finish;
668 }
669
670 sd_event_set_watchdog(context.event, true);
cde93897 671
8cf030b3
LP
672 n = sd_listen_fds(1);
673 if (n < 0) {
674 log_error("Failed to receive sockets from parent.");
675 r = n;
676 goto finish;
677 } else if (n == 0) {
678 log_error("Didn't get any sockets passed in.");
679 r = -EINVAL;
680 goto finish;
681 }
682
683 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
fb69d709 684 r = add_listen_socket(&context, fd);
8569a776 685 if (r < 0)
96c374d0 686 goto finish;
912b54ad
DS
687 }
688
fb69d709 689 r = sd_event_loop(context.event);
912b54ad 690 if (r < 0) {
da927ba9 691 log_error_errno(r, "Failed to run event loop: %m");
912b54ad
DS
692 goto finish;
693 }
694
912b54ad 695finish:
8569a776
LP
696 context_free(&context);
697
912b54ad
DS
698 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
699}