+ return 0; /* ignore errors, continue serving */
+}
+
+static int resolve_cb(sd_resolve_query *q, int ret, const struct addrinfo *ai, void *userdata) {
+ Connection *c = userdata;
+
+ assert(q);
+ assert(c);
+
+ if (ret != 0) {
+ log_error("Failed to resolve host: %s", gai_strerror(ret));
+ goto fail;
+ }
+
+ c->resolve_query = sd_resolve_query_unref(c->resolve_query);
+
+ return connection_start(c, ai->ai_addr, ai->ai_addrlen);
+
+fail:
+ connection_free(c);
+ return 0; /* ignore errors, continue serving */
+}
+
+static int resolve_remote(Connection *c) {
+
+ static const struct addrinfo hints = {
+ .ai_family = AF_UNSPEC,
+ .ai_socktype = SOCK_STREAM,
+ .ai_flags = AI_ADDRCONFIG
+ };
+
+ union sockaddr_union sa = {};
+ const char *node, *service;
+ socklen_t salen;
+ int r;
+
+ if (path_is_absolute(arg_remote_host)) {
+ sa.un.sun_family = AF_UNIX;
+ strncpy(sa.un.sun_path, arg_remote_host, sizeof(sa.un.sun_path)-1);
+ sa.un.sun_path[sizeof(sa.un.sun_path)-1] = 0;
+
+ salen = offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path);
+
+ return connection_start(c, &sa.sa, salen);
+ }
+
+ if (arg_remote_host[0] == '@') {
+ sa.un.sun_family = AF_UNIX;
+ sa.un.sun_path[0] = 0;
+ strncpy(sa.un.sun_path+1, arg_remote_host+1, sizeof(sa.un.sun_path)-2);
+ sa.un.sun_path[sizeof(sa.un.sun_path)-1] = 0;
+
+ salen = offsetof(union sockaddr_union, un.sun_path) + 1 + strlen(sa.un.sun_path + 1);
+
+ return connection_start(c, &sa.sa, salen);
+ }
+
+ service = strrchr(arg_remote_host, ':');
+ if (service) {
+ node = strndupa(arg_remote_host, service - arg_remote_host);
+ service ++;
+ } else {
+ node = arg_remote_host;
+ service = "80";
+ }
+
+ log_debug("Looking up address info for %s:%s", node, service);
+ r = sd_resolve_getaddrinfo(c->context->resolve, &c->resolve_query, node, service, &hints, resolve_cb, c);
+ if (r < 0) {
+ log_error("Failed to resolve remote host: %s", strerror(-r));
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ connection_free(c);
+ return 0; /* ignore errors, continue serving */
+}
+
+static int add_connection_socket(Context *context, int fd) {
+ Connection *c;
+ int r;
+
+ assert(context);
+ assert(fd >= 0);
+
+ if (set_size(context->connections) > CONNECTIONS_MAX) {
+ log_warning("Hit connection limit, refusing connection.");
+ safe_close(fd);
+ return 0;
+ }
+
+ r = set_ensure_allocated(&context->connections, trivial_hash_func, trivial_compare_func);
+ if (r < 0) {
+ log_oom();
+ return 0;
+ }
+
+ c = new0(Connection, 1);
+ if (!c) {
+ log_oom();
+ return 0;
+ }
+
+ c->context = context;
+ c->server_fd = fd;
+ c->client_fd = -1;
+ c->server_to_client_buffer[0] = c->server_to_client_buffer[1] = -1;
+ c->client_to_server_buffer[0] = c->client_to_server_buffer[1] = -1;
+
+ r = set_put(context->connections, c);
+ if (r < 0) {
+ free(c);
+ log_oom();
+ return 0;
+ }
+
+ return resolve_remote(c);