Code

socket frontend: Close listening sockets before returning.
[sysdb.git] / src / frontend / sock.c
index fb79f105f686295c77ef4b8a332a47aa27f2840b..27a1b679c2815f17932cd3845383ff7649a9d502 100644 (file)
@@ -181,6 +181,7 @@ listener_destroy(listener_t *listener)
 
        if (listener->sock_fd >= 0)
                close(listener->sock_fd);
+       listener->sock_fd = -1;
 
        if (listener->address)
                free(listener->address);
@@ -232,6 +233,32 @@ listener_create(sdb_fe_socket_t *sock, const char *address)
        return listener;
 } /* listener_create */
 
+static int
+listener_listen(listener_t *listener)
+{
+       assert(listener);
+
+       if (listen(listener->sock_fd, /* backlog = */ 32)) {
+               char buf[1024];
+               sdb_log(SDB_LOG_ERR, "frontend: Failed to listen on socket %s: %s",
+                               listener->address, sdb_strerror(errno, buf, sizeof(buf)));
+               return -1;
+       }
+       return 0;
+} /* listener_listen */
+
+static void
+listener_close(listener_t *listener)
+{
+       assert(listener);
+
+       if (listener->sock_fd < 0)
+               return;
+
+       close(listener->sock_fd);
+       listener->sock_fd = -1;
+} /* listener_close */
+
 /*
  * private data types
  */
@@ -292,6 +319,7 @@ connection_destroy(sdb_object_t *obj)
        assert(obj);
        conn = &CONN(obj)->conn;
 
+       sdb_log(SDB_LOG_DEBUG, "frontend: Closing connection on fd=%i", conn->fd);
        close(conn->fd);
        conn->fd = -1;
 } /* connection_destroy */
@@ -363,9 +391,21 @@ connection_handler(void *data)
                        continue;
                }
 
-               /* XXX */
-               sdb_log(SDB_LOG_INFO, "frontend: Data available on connection fd=%i\n",
-                               conn->conn.fd);
+               status = connection_read(conn->conn.fd);
+               if (status <= 0) {
+                       /* error or EOF -> close connection */
+                       sdb_object_deref(SDB_OBJ(conn));
+               }
+               else {
+                       if (sdb_llist_append(sock->open_connections, SDB_OBJ(conn))) {
+                               sdb_log(SDB_LOG_ERR, "frontend: Failed to re-append "
+                                               "connection %s to list of open connections",
+                                               SDB_OBJ(conn)->name);
+                       }
+
+                       /* pass ownership back to list; or destroy in case of an error */
+                       sdb_object_deref(SDB_OBJ(conn));
+               }
        }
        return NULL;
 } /* connection_handler */
@@ -463,17 +503,16 @@ sdb_fe_sock_listen_and_serve(sdb_fe_socket_t *sock, sdb_fe_loop_t *loop)
        if ((! sock) || (! sock->listeners_num) || (! loop))
                return -1;
 
+       if (sock->chan)
+               return -1;
+
        FD_ZERO(&sockets);
 
        for (i = 0; i < sock->listeners_num; ++i) {
                listener_t *listener = sock->listeners + i;
 
-               if (listen(listener->sock_fd, /* backlog = */ 32)) {
-                       char buf[1024];
-                       sdb_log(SDB_LOG_ERR, "frontend: Failed to listen on socket %s: %s",
-                                       listener->address, sdb_strerror(errno, buf, sizeof(buf)));
+               if (listener_listen(listener))
                        return -1;
-               }
 
                FD_SET(listener->sock_fd, &sockets);
                if (listener->sock_fd > max_listen_fd)
@@ -510,7 +549,7 @@ sdb_fe_sock_listen_and_serve(sdb_fe_socket_t *sock, sdb_fe_loop_t *loop)
                if (! iter) {
                        sdb_log(SDB_LOG_ERR, "frontend: Failed to acquire iterator "
                                        "for open connections");
-                       return -1;
+                       break;
                }
 
                while (sdb_llist_iter_has_next(iter)) {
@@ -533,7 +572,7 @@ sdb_fe_sock_listen_and_serve(sdb_fe_socket_t *sock, sdb_fe_loop_t *loop)
 
                        sdb_log(SDB_LOG_ERR, "frontend: Failed to monitor sockets: %s",
                                        sdb_strerror(errno, buf, sizeof(buf)));
-                       return -1;
+                       break;
                }
 
                if (! n)
@@ -550,7 +589,7 @@ sdb_fe_sock_listen_and_serve(sdb_fe_socket_t *sock, sdb_fe_loop_t *loop)
                if (! iter) {
                        sdb_log(SDB_LOG_ERR, "frontend: Failed to acquire iterator "
                                        "for open connections");
-                       return -1;
+                       break;
                }
 
                while (sdb_llist_iter_has_next(iter)) {
@@ -561,7 +600,6 @@ sdb_fe_sock_listen_and_serve(sdb_fe_socket_t *sock, sdb_fe_loop_t *loop)
                                                CONN(obj)->conn.fd);
 
                        if (FD_ISSET(CONN(obj)->conn.fd, &ready)) {
-                               sdb_log(SDB_LOG_INFO, "Data on fd %d", CONN(obj)->conn.fd);
                                sdb_llist_iter_remove_current(iter);
                                sdb_channel_write(sock->chan, &obj);
                        }
@@ -569,12 +607,18 @@ sdb_fe_sock_listen_and_serve(sdb_fe_socket_t *sock, sdb_fe_loop_t *loop)
                sdb_llist_iter_destroy(iter);
        }
 
+       for (i = 0; i < sock->listeners_num; ++i)
+               listener_close(sock->listeners + i);
+
        sdb_log(SDB_LOG_INFO, "frontend: Waiting for connection handler threads "
                        "to terminate");
        if (! sdb_channel_shutdown(sock->chan))
                for (i = 0; i < SDB_STATIC_ARRAY_LEN(handler_threads); ++i)
                        pthread_join(handler_threads[i], NULL);
        /* else: we tried our best; let the operating system clean up */
+
+       sdb_channel_destroy(sock->chan);
+       sock->chan = NULL;
        return 0;
 } /* sdb_fe_sock_listen_and_server */