Blob Blame History Raw
From b148a875bed6c32a5ffee9a23655ac0fc8227fd5 Mon Sep 17 00:00:00 2001
From: Michal Schmidt <mschmidt@redhat.com>
Date: Fri, 20 Jan 2012 23:44:22 +0100
Subject: [PATCH] socket: don't fail the socket on ENOTCONN

Albert Strasheim reported a socket unit with Accept=yes was failing
sometimes.
getpeername() returns ENOTCONN if the connection was killed by TCP RST.
The socket unit must not fail when it happens.

Reproducer available at:
https://bugzilla.redhat.com/show_bug.cgi?id=783344
(cherry picked from commit 1a710b430b7e5fa036ee5c03e14e60f725df5baf)

Conflicts:

	src/socket.c
---
 src/socket.c |   36 ++++++++++++++++++++++++++----------
 1 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/src/socket.c b/src/socket.c
index 7034436..00f0ebd 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -1368,7 +1368,8 @@ static void socket_enter_running(Socket *s, int cfd) {
                         /* Flush all sockets by closing and reopening them */
                         socket_close_fds(s);
 
-                        if ((r = socket_watch_fds(s)) < 0) {
+                        r = socket_watch_fds(s);
+                        if (r < 0) {
                                 log_warning("%s failed to watch sockets: %s", s->meta.id, strerror(-r));
                                 socket_enter_stop_pre(s, false);
                         }
@@ -1390,9 +1391,11 @@ static void socket_enter_running(Socket *s, int cfd) {
                                 break;
                         }
 
-                if (!pending)
-                        if ((r = manager_add_job(s->meta.manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, true, &error, NULL)) < 0)
+                if (!pending) {
+                        r = manager_add_job(s->meta.manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, true, &error, NULL);
+                        if (r < 0)
                                 goto fail;
+                }
 
                 socket_set_state(s, SOCKET_RUNNING);
         } else {
@@ -1405,13 +1408,23 @@ static void socket_enter_running(Socket *s, int cfd) {
                         return;
                 }
 
-                if ((r = socket_instantiate_service(s)) < 0)
+                r = socket_instantiate_service(s);
+                if (r < 0)
                         goto fail;
 
-                if ((r = instance_from_socket(cfd, s->n_accepted, &instance)) < 0)
-                        goto fail;
+                r = instance_from_socket(cfd, s->n_accepted, &instance);
+                if (r < 0) {
+                        if (r != -ENOTCONN)
+                                goto fail;
+
+                        /* ENOTCONN is legitimate if TCP RST was received.
+                         * This connection is over, but the socket unit lives on. */
+                        close_nointr_nofail(cfd);
+                        return;
+                }
 
-                if (!(prefix = unit_name_to_prefix(s->meta.id))) {
+                prefix = unit_name_to_prefix(s->meta.id);
+                if (!prefix) {
                         free(instance);
                         r = -ENOMEM;
                         goto fail;
@@ -1426,7 +1439,8 @@ static void socket_enter_running(Socket *s, int cfd) {
                         goto fail;
                 }
 
-                if ((r = unit_add_name(UNIT_DEREF(s->service), name)) < 0) {
+                r = unit_add_name(UNIT_DEREF(s->service), name);
+                if (r < 0) {
                         free(name);
                         goto fail;
                 }
@@ -1440,13 +1454,15 @@ static void socket_enter_running(Socket *s, int cfd) {
                 unit_choose_id(UNIT(service), name);
                 free(name);
 
-                if ((r = service_set_socket_fd(service, cfd, s)) < 0)
+                r = service_set_socket_fd(service, cfd, s);
+                if (r < 0)
                         goto fail;
 
                 cfd = -1;
                 s->n_connections ++;
 
-                if ((r = manager_add_job(s->meta.manager, JOB_START, UNIT(service), JOB_REPLACE, true, &error, NULL)) < 0)
+                r = manager_add_job(s->meta.manager, JOB_START, UNIT(service), JOB_REPLACE, true, &error, NULL);
+                if (r < 0)
                         goto fail;
 
                 /* Notify clients about changed counters */