1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 David Strauss
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.
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.
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/>.
22 #include <arpa/inet.h>
29 #include <sys/fcntl.h>
30 #include <sys/socket.h>
34 #include "sd-daemon.h"
37 #include "socket-util.h"
39 #include "event-util.h"
42 #define BUFFER_SIZE 16384
43 #define _cleanup_freeaddrinfo_ _cleanup_(freeaddrinfop)
45 unsigned int total_clients = 0;
47 DEFINE_TRIVIAL_CLEANUP_FUNC(struct addrinfo *, freeaddrinfo);
53 const char *remote_host;
54 const char *remote_service;
61 struct connection *c_destination;
62 size_t buffer_filled_len;
63 size_t buffer_sent_len;
64 char buffer[BUFFER_SIZE];
67 static void free_connection(struct connection *c) {
69 log_debug("Freeing fd=%d (conn %p).", c->fd, c);
70 sd_event_source_unref(c->w);
72 close_nointr_nofail(c->fd);
77 static int add_event_to_connection(struct connection *c, uint32_t events) {
80 log_debug("Have revents=%d. Adding revents=%d.", c->events, events);
84 r = sd_event_source_set_io_events(c->w, c->events);
86 log_error("Error %d setting revents: %s", r, strerror(-r));
90 r = sd_event_source_set_enabled(c->w, SD_EVENT_ON);
92 log_error("Error %d enabling source: %s", r, strerror(-r));
99 static int remove_event_from_connection(struct connection *c, uint32_t events) {
102 log_debug("Have revents=%d. Removing revents=%d.", c->events, events);
104 c->events &= ~events;
106 r = sd_event_source_set_io_events(c->w, c->events);
108 log_error("Error %d setting revents: %s", r, strerror(-r));
112 if (c->events == 0) {
113 r = sd_event_source_set_enabled(c->w, SD_EVENT_OFF);
115 log_error("Error %d disabling source: %s", r, strerror(-r));
123 static int send_buffer(struct connection *sender) {
124 struct connection *receiver = sender->c_destination;
128 /* We cannot assume that even a partial send() indicates that
129 * the next send() will return EAGAIN or EWOULDBLOCK. Loop until
131 while (sender->buffer_filled_len > sender->buffer_sent_len) {
132 len = send(receiver->fd, sender->buffer + sender->buffer_sent_len, sender->buffer_filled_len - sender->buffer_sent_len, 0);
133 log_debug("send(%d, ...)=%zd", receiver->fd, len);
135 if (errno != EWOULDBLOCK && errno != EAGAIN) {
136 log_error("Error %d in send to fd=%d: %m", errno, receiver->fd);
140 /* send() is in a would-block state. */
145 /* len < 0 can't occur here. len == 0 is possible but
146 * undefined behavior for nonblocking send(). */
148 sender->buffer_sent_len += len;
151 log_debug("send(%d, ...) completed with %zu bytes still buffered.", receiver->fd, sender->buffer_filled_len - sender->buffer_sent_len);
153 /* Detect a would-block state or partial send. */
154 if (sender->buffer_filled_len > sender->buffer_sent_len) {
156 /* If the buffer is full, disable events coming for recv. */
157 if (sender->buffer_filled_len == BUFFER_SIZE) {
158 r = remove_event_from_connection(sender, EPOLLIN);
160 log_error("Error %d disabling EPOLLIN for fd=%d: %s", r, sender->fd, strerror(-r));
165 /* Watch for when the recipient can be sent data again. */
166 r = add_event_to_connection(receiver, EPOLLOUT);
168 log_error("Error %d enabling EPOLLOUT for fd=%d: %s", r, receiver->fd, strerror(-r));
171 log_debug("Done with recv for fd=%d. Waiting on send for fd=%d.", sender->fd, receiver->fd);
175 /* If we sent everything without any issues (would-block or
176 * partial send), the buffer is now empty. */
177 sender->buffer_filled_len = 0;
178 sender->buffer_sent_len = 0;
180 /* Enable the sender's receive watcher, in case the buffer was
181 * full and we disabled it. */
182 r = add_event_to_connection(sender, EPOLLIN);
184 log_error("Error %d enabling EPOLLIN for fd=%d: %s", r, sender->fd, strerror(-r));
188 /* Disable the other side's send watcher, as we have no data to send now. */
189 r = remove_event_from_connection(receiver, EPOLLOUT);
191 log_error("Error %d disabling EPOLLOUT for fd=%d: %s", r, receiver->fd, strerror(-r));
198 static int transfer_data_cb(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
199 struct connection *c = (struct connection *) userdata;
203 assert(revents & (EPOLLIN | EPOLLOUT));
207 log_debug("Got event revents=%d from fd=%d (conn %p).", revents, fd, c);
209 if (revents & EPOLLIN) {
210 log_debug("About to recv up to %zu bytes from fd=%d (%zu/BUFFER_SIZE).", BUFFER_SIZE - c->buffer_filled_len, fd, c->buffer_filled_len);
212 /* Receive until the buffer's full, there's no more data,
213 * or the client/server disconnects. */
214 while (c->buffer_filled_len < BUFFER_SIZE) {
215 len = recv(fd, c->buffer + c->buffer_filled_len, BUFFER_SIZE - c->buffer_filled_len, 0);
216 log_debug("recv(%d, ...)=%zd", fd, len);
218 if (errno != EWOULDBLOCK && errno != EAGAIN) {
219 log_error("Error %d in recv from fd=%d: %m", errno, fd);
223 /* recv() is in a blocking state. */
228 log_debug("Clean disconnection from fd=%d", fd);
230 free_connection(c->c_destination);
236 log_debug("Recording that the buffer got %zd more bytes full.", len);
237 c->buffer_filled_len += len;
238 log_debug("Buffer now has %zu bytes full.", c->buffer_filled_len);
241 /* Try sending the data immediately. */
242 return send_buffer(c);
245 return send_buffer(c->c_destination);
251 /* Once sending to the server is ready, set up the real watchers. */
252 static int connected_to_server_cb(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
253 struct sd_event *e = NULL;
254 struct connection *c_server_to_client = (struct connection *) userdata;
255 struct connection *c_client_to_server = c_server_to_client->c_destination;
258 assert(revents & EPOLLOUT);
262 /* Cancel the initial write watcher for the server. */
263 sd_event_source_unref(s);
265 log_debug("Connected to server. Initializing watchers for receiving data.");
267 /* A recv watcher for the server. */
268 r = sd_event_add_io(e, c_server_to_client->fd, EPOLLIN, transfer_data_cb, c_server_to_client, &c_server_to_client->w);
270 log_error("Error %d creating recv watcher for fd=%d: %s", r, c_server_to_client->fd, strerror(-r));
273 c_server_to_client->events = EPOLLIN;
275 /* A recv watcher for the client. */
276 r = sd_event_add_io(e, c_client_to_server->fd, EPOLLIN, transfer_data_cb, c_client_to_server, &c_client_to_server->w);
278 log_error("Error %d creating recv watcher for fd=%d: %s", r, c_client_to_server->fd, strerror(-r));
281 c_client_to_server->events = EPOLLIN;
286 free_connection(c_client_to_server);
287 free_connection(c_server_to_client);
293 static int get_server_connection_fd(const struct proxy *proxy) {
298 if (proxy->remote_is_inet) {
300 _cleanup_freeaddrinfo_ struct addrinfo *result = NULL;
301 struct addrinfo hints = {.ai_family = AF_UNSPEC,
302 .ai_socktype = SOCK_STREAM,
303 .ai_flags = AI_PASSIVE};
305 log_debug("Looking up address info for %s:%s", proxy->remote_host, proxy->remote_service);
306 s = getaddrinfo(proxy->remote_host, proxy->remote_service, &hints, &result);
308 log_error("getaddrinfo error (%d): %s", s, gai_strerror(s));
312 if (result == NULL) {
313 log_error("getaddrinfo: no result");
317 /* @TODO: Try connecting to all results instead of just the first. */
318 server_fd = socket(result->ai_family, result->ai_socktype | SOCK_NONBLOCK, result->ai_protocol);
320 log_error("Error %d creating socket: %m", errno);
324 r = connect(server_fd, result->ai_addr, result->ai_addrlen);
325 /* Ignore EINPROGRESS errors because they're expected for a nonblocking socket. */
326 if (r < 0 && errno != EINPROGRESS) {
327 log_error("Error %d while connecting to socket %s:%s: %m", errno, proxy->remote_host, proxy->remote_service);
332 struct sockaddr_un remote;
334 server_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
336 log_error("Error %d creating socket: %m", errno);
340 remote.sun_family = AF_UNIX;
341 strncpy(remote.sun_path, proxy->remote_host, sizeof(remote.sun_path));
342 len = strlen(remote.sun_path) + sizeof(remote.sun_family);
343 r = connect(server_fd, (struct sockaddr *) &remote, len);
344 if (r < 0 && errno != EINPROGRESS) {
345 log_error("Error %d while connecting to Unix domain socket %s: %m", errno, proxy->remote_host);
350 log_debug("Server connection is fd=%d", server_fd);
354 static int do_accept(sd_event *e, struct proxy *p, int fd) {
355 struct connection *c_server_to_client = NULL;
356 struct connection *c_client_to_server = NULL;
358 union sockaddr_union sa;
359 socklen_t salen = sizeof(sa);
360 int client_fd, server_fd;
362 client_fd = accept4(fd, (struct sockaddr *) &sa, &salen, SOCK_NONBLOCK|SOCK_CLOEXEC);
364 if (errno == EAGAIN || errno == EWOULDBLOCK)
366 log_error("Error %d accepting client connection: %m", errno);
371 server_fd = get_server_connection_fd(p);
373 log_error("Error initiating server connection.");
378 c_client_to_server = new0(struct connection, 1);
379 if (c_client_to_server == NULL) {
384 c_server_to_client = new0(struct connection, 1);
385 if (c_server_to_client == NULL) {
390 c_client_to_server->fd = client_fd;
391 c_server_to_client->fd = server_fd;
393 if (sa.sa.sa_family == AF_INET || sa.sa.sa_family == AF_INET6) {
394 char sa_str[INET6_ADDRSTRLEN];
397 success = inet_ntop(sa.sa.sa_family, &sa.in6.sin6_addr, sa_str, INET6_ADDRSTRLEN);
399 log_warning("Error %d calling inet_ntop: %m", errno);
401 log_debug("Accepted client connection from %s as fd=%d", sa_str, c_client_to_server->fd);
404 log_debug("Accepted client connection (non-IP) as fd=%d", c_client_to_server->fd);
408 log_debug("Client fd=%d (conn %p) successfully connected. Total clients: %u", c_client_to_server->fd, c_client_to_server, total_clients);
409 log_debug("Server fd=%d (conn %p) successfully initialized.", c_server_to_client->fd, c_server_to_client);
411 /* Initialize watcher for send to server; this shows connectivity. */
412 r = sd_event_add_io(e, c_server_to_client->fd, EPOLLOUT, connected_to_server_cb, c_server_to_client, &c_server_to_client->w);
414 log_error("Error %d creating connectivity watcher for fd=%d: %s", r, c_server_to_client->fd, strerror(-r));
418 /* Allow lookups of the opposite connection. */
419 c_server_to_client->c_destination = c_client_to_server;
420 c_client_to_server->c_destination = c_server_to_client;
425 log_warning("Accepting a client connection or connecting to the server failed.");
426 free_connection(c_client_to_server);
427 free_connection(c_server_to_client);
433 static int accept_cb(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
434 struct proxy *p = (struct proxy *) userdata;
438 assert(revents & EPOLLIN);
443 r = do_accept(e, p, fd);
444 if (r == -EAGAIN || r == -EWOULDBLOCK)
447 log_error("Error %d while trying to accept: %s", r, strerror(-r));
452 /* Re-enable the watcher. */
453 r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT);
455 log_error("Error %d while re-enabling listener with ONESHOT: %s", r, strerror(-r));
459 /* Preserve the main loop even if a single accept() fails. */
463 static int run_main_loop(struct proxy *proxy) {
464 _cleanup_event_source_unref_ sd_event_source *w_accept = NULL;
465 _cleanup_event_unref_ sd_event *e = NULL;
466 int r = EXIT_SUCCESS;
468 r = sd_event_new(&e);
470 log_error("Failed to allocate event loop: %s", strerror(-r));
474 r = fd_nonblock(proxy->listen_fd, true);
476 log_error("Failed to make listen file descriptor nonblocking: %s", strerror(-r));
480 log_debug("Initializing main listener fd=%d", proxy->listen_fd);
482 r = sd_event_add_io(e, proxy->listen_fd, EPOLLIN, accept_cb, proxy, &w_accept);
484 log_error("Error %d while adding event IO source: %s", r, strerror(-r));
488 /* Set the watcher to oneshot in case other processes are also
489 * watching to accept(). */
490 r = sd_event_source_set_enabled(w_accept, SD_EVENT_ONESHOT);
492 log_error("Error %d while setting event IO source to ONESHOT: %s", r, strerror(-r));
496 log_debug("Initialized main listener. Entering loop.");
498 return sd_event_loop(e);
501 static int help(void) {
503 printf("%s hostname-or-ip port-or-service\n"
504 "%s unix-domain-socket-path\n\n"
505 "Inherit a socket. Bidirectionally proxy.\n\n"
506 " -h --help Show this help\n"
507 " --version Print version and exit\n"
508 " --ignore-env Ignore expected systemd environment\n",
509 program_invocation_short_name,
510 program_invocation_short_name);
515 static int parse_argv(int argc, char *argv[], struct proxy *p) {
522 static const struct option options[] = {
523 { "help", no_argument, NULL, 'h' },
524 { "version", no_argument, NULL, ARG_VERSION },
525 { "ignore-env", no_argument, NULL, ARG_IGNORE_ENV},
534 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
542 puts(PACKAGE_STRING);
543 puts(SYSTEMD_FEATURES);
547 p->ignore_env = true;
554 assert_not_reached("Unhandled option");
558 if (optind + 1 != argc && optind + 2 != argc) {
559 log_error("Incorrect number of positional arguments.");
564 p->remote_host = argv[optind];
565 assert(p->remote_host);
567 p->remote_is_inet = p->remote_host[0] != '/';
569 if (optind == argc - 2) {
570 if (!p->remote_is_inet) {
571 log_error("A port or service is not allowed for Unix socket destinations.");
575 p->remote_service = argv[optind + 1];
576 assert(p->remote_service);
577 } else if (p->remote_is_inet) {
578 log_error("A port or service is required for IP destinations.");
586 int main(int argc, char *argv[]) {
590 log_parse_environment();
593 r = parse_argv(argc, argv, &p);
597 p.listen_fd = SD_LISTEN_FDS_START;
601 n = sd_listen_fds(1);
603 log_error("Found zero inheritable sockets. Are you sure this is running as a socket-activated service?");
607 log_error("Error %d while finding inheritable sockets: %s", n, strerror(-n));
611 log_error("Can't listen on more than one socket.");
617 r = sd_is_socket(p.listen_fd, 0, SOCK_STREAM, 1);
619 log_error("Error %d while checking inherited socket: %s", r, strerror(-r));
623 log_info("Starting the socket activation proxy with listener fd=%d.", p.listen_fd);
625 r = run_main_loop(&p);
628 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;