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