(sizeof(struct auth_client_request_continue) + \
AUTH_CLIENT_MAX_REQUEST_DATA_SIZE)
+static void auth_server_connection_unref(struct auth_server_connection *conn);
+
static void update_available_auth_mechs(struct auth_client *client)
{
struct auth_server_connection *conn;
return;
/* we've got a full reply */
+ conn->refcount++;
conn->reply_received = FALSE;
+
auth_server_request_handle_reply(conn, &conn->reply, data);
i_stream_skip(conn->input, conn->reply.data_size);
+
+ auth_server_connection_unref(conn);
}
struct auth_server_connection *
pool = pool_alloconly_create("Auth connection", 1024);
conn = p_new(pool, struct auth_server_connection, 1);
+ conn->refcount = 1;
conn->pool = pool;
conn->client = client;
struct auth_client *client = conn->client;
struct auth_server_connection **pos;
+ if (conn->fd == -1)
+ return;
+
pos = &conn->client->connections;
for (; *pos != NULL; pos = &(*pos)->next) {
if (*pos == conn) {
client->conn_waiting_handshake_count--;
io_remove(conn->io);
+ conn->io = NULL;
+
+ i_stream_close(conn->input);
+ o_stream_close(conn->output);
+
if (close(conn->fd) < 0)
i_error("close(auth) failed: %m");
conn->fd = -1;
auth_server_requests_remove_all(conn);
- hash_destroy(conn->requests);
-
- i_stream_unref(conn->input);
- o_stream_unref(conn->output);
- pool_unref(conn->pool);
+ auth_server_connection_unref(conn);
if (reconnect)
auth_client_connect_missing_servers(client);
}
}
+static void auth_server_connection_unref(struct auth_server_connection *conn)
+{
+ if (--conn->refcount > 0)
+ return;
+
+ hash_destroy(conn->requests);
+
+ i_stream_unref(conn->input);
+ o_stream_unref(conn->output);
+ pool_unref(conn->pool);
+}
+
struct auth_server_connection *
auth_server_connection_find_path(struct auth_client *client, const char *path)
{
return TRUE;
}
+static void auth_server_send_continue(struct auth_server_connection *conn,
+ struct auth_request *request,
+ const unsigned char *data, size_t size)
+{
+ struct auth_client_request_continue auth_request;
+
+ /* send continued request to auth */
+ auth_request.type = AUTH_CLIENT_REQUEST_CONTINUE;
+ auth_request.id = request->id;
+ auth_request.data_size = size;
+
+ if (o_stream_send(conn->output, &auth_request,
+ sizeof(auth_request)) < 0 ||
+ o_stream_send(conn->output, data, size) < 0) {
+ errno = conn->output->stream_errno;
+ i_warning("Error sending continue request to auth server: %m");
+ auth_server_connection_destroy(conn, TRUE);
+ }
+}
+
static struct auth_server_connection *
get_next_plain_server(struct auth_server_connection *conn)
{
request = hash_lookup(conn->requests, POINTER_CAST(reply->id));
if (request == NULL) {
- i_error("BUG: Auth server sent us reply with unknown ID %u",
- reply->id);
+ /* We've already destroyed the request */
return;
}
switch (reply->result) {
case AUTH_CLIENT_RESULT_SUCCESS:
- if (conn == request->conn)
- request->next_conn = NULL;
- else {
- i_assert(request->next_conn == conn);
- request->conn = request->next_conn;
- request->next_conn = NULL;
+ hash_remove(request->conn->requests, POINTER_CAST(request->id));
+ if (request->next_conn != NULL) {
+ hash_remove(request->next_conn->requests,
+ POINTER_CAST(request->id));
}
+ request->conn = conn;
+ request->next_conn = NULL;
break;
case AUTH_CLIENT_RESULT_FAILURE:
- if (request->plaintext_data == NULL)
- break;
-
- next = get_next_plain_server(conn);
- if (next == NULL)
+ hash_remove(conn->requests, POINTER_CAST(request->id));
+ if (!request->retrying)
break;
- hash_remove(conn->requests, POINTER_CAST(request->id));
- hash_insert(next->requests, POINTER_CAST(request->id), request);
+ next = request->next_conn == NULL ? NULL :
+ get_next_plain_server(request->next_conn);
if (conn == request->conn)
request->conn = request->next_conn;
+ request->next_conn = NULL;
+
+ if (next == NULL) {
+ if (request->conn != NULL) {
+ /* the other one hasn't replied yet */
+ return;
+ }
+ request->conn = conn;
+ break;
+ }
+ hash_insert(next->requests, POINTER_CAST(request->id), request);
request->next_conn = next;
- request->retrying = TRUE;
auth_server_send_new_request(next, request);
return;
if (!request->retrying)
break;
- auth_client_request_continue(request, request->plaintext_data,
- request->plaintext_data_size);
+ auth_server_send_continue(conn, request,
+ request->plaintext_data,
+ request->plaintext_data_size);
return;
}
request->callback(request, reply, data, request->context);
if (reply->result != AUTH_CLIENT_RESULT_CONTINUE) {
- hash_remove(conn->requests, POINTER_CAST(request->id));
i_free(request->plaintext_data);
i_free(request);
}
void auth_client_request_continue(struct auth_request *request,
const unsigned char *data, size_t data_size)
{
- struct auth_client_request_continue auth_request;
+ auth_server_send_continue(request->conn, request, data, data_size);
if (request->mech == AUTH_MECH_PLAIN &&
request->plaintext_data == NULL) {
POINTER_CAST(request->id), request);
auth_server_send_new_request(request->next_conn,
request);
+ request->retrying = TRUE;
}
}
-
- /* send continued request to auth */
- auth_request.type = AUTH_CLIENT_REQUEST_CONTINUE;
- auth_request.id = request->id;
- auth_request.data_size = data_size;
-
- if (o_stream_send(request->conn->output, &auth_request,
- sizeof(auth_request)) < 0 ||
- o_stream_send(request->conn->output, data, data_size) < 0) {
- errno = request->conn->output->stream_errno;
- i_warning("Error sending continue request to auth server: %m");
- auth_server_connection_destroy(request->conn, TRUE);
- }
}
void auth_client_request_abort(struct auth_request *request)