handle_modern_connection(GArray *const servers, const int sock)
{
        int net;
        pid_t pid;
        CLIENT *client = NULL;
        int sock_flags_old;
        int sock_flags_new;

        net = socket_accept(sock);
        if (net < 0)
                return;

        if (!dontfork) {
                pid = spawn_child();
                if (pid) {
                        if (pid > 0)
                                msg(LOG_INFO, "Spawned a child process");
                        if (pid < 0)
                                msg(LOG_ERR, "Failed to spawn a child process");
                        close(net);
                        return;
                }
                /* Child just continues. */
        }

        client = negotiate(net, NULL, servers, NEG_INIT | NEG_MODERN);
        if (!client) {
                msg(LOG_ERR, "Modern initial negotiation failed");
                goto handler_err;
        }

        if (client->server->max_connections > 0 &&
           g_hash_table_size(children) >= client->server->max_connections) {
                msg(LOG_ERR, "Max connections (%d) reached",
                    client->server->max_connections);
                goto handler_err;
        }

        sock_flags_old = fcntl(net, F_GETFL, 0);
        if (sock_flags_old == -1) {
                msg(LOG_ERR, "Failed to get socket flags");
                goto handler_err;
        }

        sock_flags_new = sock_flags_old & ~O_NONBLOCK;
        if (sock_flags_new != sock_flags_old &&
            fcntl(net, F_SETFL, sock_flags_new) == -1) {
                msg(LOG_ERR, "Failed to set socket to blocking mode");
                goto handler_err;
        }

        if (set_peername(net, client)) {
                msg(LOG_ERR, "Failed to set peername");
                goto handler_err;
        }

        if (!authorized_client(client)) {
                msg(LOG_INFO, "Client '%s' is not authorized to access",
                    client->clientname);
                goto handler_err;
        }

        if (!dontfork) {
                int i;

                /* Free all root server resources here, because we are
                 * currently in the child process serving one specific
                 * connection. These are not simply needed anymore. */
                g_hash_table_destroy(children);
                children = NULL;
                for (i = 0; i < modernsocks->len; i++) {
                        close(g_array_index(modernsocks, int, i));
                }
                g_array_free(modernsocks, TRUE);

                /* Now that we are in the child process after a
                 * succesful negotiation, we do not need the list of
                 * servers anymore, get rid of it.*/

                for (i = 0; i < servers->len; i++) {
                        const SERVER *const server = &g_array_index(servers, SERVER, i);
                        close(server->socket);
                }

                /* FALSE does not free the
                   actual data. This is required,
                   because the client has a
                   direct reference into that
                   data, and otherwise we get a
                   segfault... */
                g_array_free(servers, FALSE);
        }

        msg(LOG_INFO, "Starting to serve");
        serveconnection(client);
        exit(EXIT_SUCCESS);

handler_err:
        g_free(client);
        close(net);

        if (!dontfork) {
                exit(EXIT_FAILURE);
        }
}
handle_modern_connection(GArray *const servers, const int sock)
{
        int net;
        pid_t pid;
        CLIENT *client = NULL;
        int sock_flags_old;
        int sock_flags_new;

        net = socket_accept(sock);
        if (net < 0)
                return;

        if (!dontfork) {
                pid = spawn_child();
                if (pid) {
                        if (pid > 0)
                                msg(LOG_INFO, "Spawned a child process");
                        if (pid < 0)
                                msg(LOG_ERR, "Failed to spawn a child process");
                        close(net);
                        return;
                }
                 
        }

        client = negotiate(net, NULL, servers, NEG_INIT | NEG_MODERN);
        if (!client) {
                msg(LOG_ERR, "Modern initial negotiation failed");
                goto handler_err;
        }

        if (client->server->max_connections > 0 &&
           g_hash_table_size(children) >= client->server->max_connections) {
                msg(LOG_ERR, "Max connections (%d) reached",
                    client->server->max_connections);
                goto handler_err;
        }

        sock_flags_old = fcntl(net, F_GETFL, 0);
        if (sock_flags_old == -1) {
                msg(LOG_ERR, "Failed to get socket flags");
                goto handler_err;
        }

        sock_flags_new = sock_flags_old & ~O_NONBLOCK;
        if (sock_flags_new != sock_flags_old &&
            fcntl(net, F_SETFL, sock_flags_new) == -1) {
                msg(LOG_ERR, "Failed to set socket to blocking mode");
                goto handler_err;
        }

        if (set_peername(net, client)) {
                msg(LOG_ERR, "Failed to set peername");
                goto handler_err;
        }

        if (!authorized_client(client)) {
                msg(LOG_INFO, "Client '%s' is not authorized to access",
                    client->clientname);
                goto handler_err;
        }

        if (!dontfork) {
                int i;

                 
                g_hash_table_destroy(children);
                children = NULL;
                for (i = 0; i < modernsocks->len; i++) {
                        close(g_array_index(modernsocks, int, i));
                }
                g_array_free(modernsocks, TRUE);

                 

                for (i = 0; i < servers->len; i++) {
                        const SERVER *const server = &g_array_index(servers, SERVER, i);
                        close(server->socket);
                }

                 
                g_array_free(servers, FALSE);
        }

        msg(LOG_INFO, "Starting to serve");
        serveconnection(client);
        exit(EXIT_SUCCESS);

handler_err:
        g_free(client);
        close(net);

        if (!dontfork) {
                exit(EXIT_FAILURE);
        }
}