sdap_id_op.c revision 772764e048dcd15c6d9732574126eb83b53a60e2
842ae4bd224140319ae7feec1872b93dfd491143fielding LDAP ID backend operation retry logic and connection cache
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding Eugene Indenbom <eindenbom@gmail.com>
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding Copyright (C) 2008-2010 Red Hat
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd This program is free software; you can redistribute it and/or modify
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd it under the terms of the GNU General Public License as published by
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd the Free Software Foundation; either version 3 of the License, or
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd (at your option) any later version.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding This program is distributed in the hope that it will be useful,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding but WITHOUT ANY WARRANTY; without even the implied warranty of
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding GNU General Public License for more details.
b6055b7832a0e4d0818416252fff5925aaebae4brbb You should have received a copy of the GNU General Public License
2d71630471d1c23f0137309e3c3957c633ecbfd6rbb along with this program. If not, see <http://www.gnu.org/licenses/>.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding/* LDAP async connection cache */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* list of all open connections */
2d84861186d70e5396751ba308bb90c8a7db47acnd /* cached (current) connection */
2d84861186d70e5396751ba308bb90c8a7db47acnd/* LDAP async operation tracker:
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * - keeps track of connection usage
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * - keeps track of operation retries */
e991c6fc032c59eb6cb751d9d382e933a53a2866niq /* ID backend context */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* double linked list pointers */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* current connection */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* number of reconnects for this operation */
b6d2c204c150843e48f6787c1090ae75b718896ecovener /* connection request
b6d2c204c150843e48f6787c1090ae75b718896ecovener * It is required as we need to know which requests to notify
7076b40ea4800c8f91c4c0948f9c98c1bacbe96crpluem * when shared connection request to sdap_handle completes.
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * This member is cleared when sdap_id_op_connect_state
06a537b50a7a5d4f8543231d2b6067b8f6805dd3aaron * associated with request is destroyed */
7076b40ea4800c8f91c4c0948f9c98c1bacbe96crpluem/* LDAP connection cache connection attempt/established connection data */
b6d2c204c150843e48f6787c1090ae75b718896ecovener /* LDAP connection cache */
b6d2c204c150843e48f6787c1090ae75b718896ecovener /* double linked list pointers */
b6d2c204c150843e48f6787c1090ae75b718896ecovener /* sdap handle */
b6d2c204c150843e48f6787c1090ae75b718896ecovener /* connection request */
b6d2c204c150843e48f6787c1090ae75b718896ecovener /* timer for connection expiration */
63de18ba5e922ffaab500317d7d1d0ad6b27b7e2covener /* number of running connection notifies */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* list of operations using connect */
2d84861186d70e5396751ba308bb90c8a7db47acndstatic void sdap_id_release_conn_data(struct sdap_id_conn_data *conn_data);
2d84861186d70e5396751ba308bb90c8a7db47acndstatic int sdap_id_conn_data_destroy(struct sdap_id_conn_data *conn_data);
2d84861186d70e5396751ba308bb90c8a7db47acndstatic bool sdap_is_connection_expired(struct sdap_id_conn_data *conn_data, int timeout);
2d84861186d70e5396751ba308bb90c8a7db47acndstatic bool sdap_can_reuse_connection(struct sdap_id_conn_data *conn_data);
2d84861186d70e5396751ba308bb90c8a7db47acndstatic void sdap_id_conn_data_expire_handler(struct tevent_context *ev,
e991c6fc032c59eb6cb751d9d382e933a53a2866niqstatic int sdap_id_conn_data_set_expire_timer(struct sdap_id_conn_data *conn_data);
b6d2c204c150843e48f6787c1090ae75b718896ecovenerstatic void sdap_id_op_hook_conn_data(struct sdap_id_op *op, struct sdap_id_conn_data *conn_data);
2d84861186d70e5396751ba308bb90c8a7db47acndstatic bool sdap_id_op_can_reconnect(struct sdap_id_op *op);
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic void sdap_id_op_connect_req_complete(struct sdap_id_op *op, int dp_error, int ret);
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic int sdap_id_op_connect_state_destroy(void *pvt);
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingstatic int sdap_id_op_connect_step(struct tevent_req *req);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmstatic void sdap_id_op_connect_done(struct tevent_req *subreq);
06a537b50a7a5d4f8543231d2b6067b8f6805dd3aaron/* Create a connection cache */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding struct sdap_id_conn_cache *conn_cache = talloc_zero(memctx, struct sdap_id_conn_cache);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding DEBUG(1, ("talloc_zero(struct sdap_id_conn_cache) failed.\n"));
80370e62044bea458bcd0545c59cb864ed117b04niq/* Callback on BE going offline */
a1efede5943e76f1fcdf10494de41704c9ba70f1niq struct sdap_id_conn_cache *conn_cache = talloc_get_type(pvt, struct sdap_id_conn_cache);
a1efede5943e76f1fcdf10494de41704c9ba70f1niq struct sdap_id_conn_data *cached_connection = conn_cache->cached_connection;
a1efede5943e76f1fcdf10494de41704c9ba70f1niq /* Release any cached connection on going offline */
e991c6fc032c59eb6cb751d9d382e933a53a2866niq/* Release sdap_id_conn_data and destroy it if no longer needed */
e991c6fc032c59eb6cb751d9d382e933a53a2866niqstatic void sdap_id_release_conn_data(struct sdap_id_conn_data *conn_data)
e991c6fc032c59eb6cb751d9d382e933a53a2866niq if (!conn_data || conn_data->ops || conn_data->notify_lock) {
e991c6fc032c59eb6cb751d9d382e933a53a2866niq /* connection is in use */
e991c6fc032c59eb6cb751d9d382e933a53a2866niq/* Destructor for struct sdap_id_conn_data */
e991c6fc032c59eb6cb751d9d382e933a53a2866niqstatic int sdap_id_conn_data_destroy(struct sdap_id_conn_data *conn_data)
e991c6fc032c59eb6cb751d9d382e933a53a2866niq /* we clean out list of ops to make sure that order of destruction does not matter */
3f65070bf58882ab06bfa08cc4e04c7c90ac04f8wrowe/* Check whether connection will expire after timeout seconds */
3f65070bf58882ab06bfa08cc4e04c7c90ac04f8wrowestatic bool sdap_is_connection_expired(struct sdap_id_conn_data *conn_data, int timeout)
3f65070bf58882ab06bfa08cc4e04c7c90ac04f8wrowe if (!conn_data || !conn_data->sh || !conn_data->sh->connected) {
3f65070bf58882ab06bfa08cc4e04c7c90ac04f8wrowe return true;
3f65070bf58882ab06bfa08cc4e04c7c90ac04f8wrowe if ((expire_time != 0) && (expire_time < time( NULL ) + timeout) ) {
3f65070bf58882ab06bfa08cc4e04c7c90ac04f8wrowe return true;
2d84861186d70e5396751ba308bb90c8a7db47acnd return false;
e8f95a682820a599fe41b22977010636be5c2717jim/* Check whether connection can be reused for next LDAP ID operation */
3f65070bf58882ab06bfa08cc4e04c7c90ac04f8wrowestatic bool sdap_can_reuse_connection(struct sdap_id_conn_data *conn_data)
2d84861186d70e5396751ba308bb90c8a7db47acnd if (!conn_data || !conn_data->sh || !conn_data->sh->connected) {
2d84861186d70e5396751ba308bb90c8a7db47acnd return false;
e8f95a682820a599fe41b22977010636be5c2717jim timeout = dp_opt_get_int(conn_data->conn_cache->id_ctx->opts->basic,
3f65070bf58882ab06bfa08cc4e04c7c90ac04f8wrowe return !sdap_is_connection_expired(conn_data, timeout);
3f65070bf58882ab06bfa08cc4e04c7c90ac04f8wrowe/* Set expiration timer for connection if needed */
3f65070bf58882ab06bfa08cc4e04c7c90ac04f8wrowestatic int sdap_id_conn_data_set_expire_timer(struct sdap_id_conn_data *conn_data)
3f65070bf58882ab06bfa08cc4e04c7c90ac04f8wrowe timeout = dp_opt_get_int(conn_data->conn_cache->id_ctx->opts->basic,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding tevent_add_timer(conn_data->conn_cache->id_ctx->be->ev,
3f65070bf58882ab06bfa08cc4e04c7c90ac04f8wrowe/* Handler for connection expiration timer */
06a537b50a7a5d4f8543231d2b6067b8f6805dd3aaronstatic void sdap_id_conn_data_expire_handler(struct tevent_context *ev,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding struct sdap_id_conn_data *conn_data = talloc_get_type(pvt,
a4be7c7d73005dedac190ce6cb68ab4dd38383bbcolm struct sdap_id_conn_cache *conn_cache = conn_data->conn_cache;
a4be7c7d73005dedac190ce6cb68ab4dd38383bbcolm DEBUG(3, ("connection is about to expire, releasing it\n"));
eea521297270de3f9ae70d8822f8665c513de574nd/* Create an operation object */
3f65070bf58882ab06bfa08cc4e04c7c90ac04f8wrowestruct sdap_id_op *sdap_id_op_create(TALLOC_CTX *memctx, struct sdap_id_conn_cache *conn_cache)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding struct sdap_id_op *op = talloc_zero(memctx, struct sdap_id_op);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding talloc_set_destructor((void*)op, sdap_id_op_destroy);
066877f1a045103acfdd376d48cdd473c33f409bdougm/* Attach/detach connection to sdap_id_op */
06a537b50a7a5d4f8543231d2b6067b8f6805dd3aaronstatic void sdap_id_op_hook_conn_data(struct sdap_id_op *op, struct sdap_id_conn_data *conn_data)
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding DLIST_ADD_END(conn_data->ops, op, struct sdap_id_op*);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding/* Destructor for sdap_id_op */
1eda27e7224742a68c18c09a7f5ae233363465a4niq struct sdap_id_op *op = talloc_get_type(pvt, struct sdap_id_op);
1eda27e7224742a68c18c09a7f5ae233363465a4niq/* Check whether retry with reconnect can be performed for the operation */
1eda27e7224742a68c18c09a7f5ae233363465a4niqstatic bool sdap_id_op_can_reconnect(struct sdap_id_op *op)
73e8b26287de5c06fa470d36162e103dbac9c7e5wrowe /* we allow 2 retries for failover server configured:
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * - one for connection broken during request execution
1eda27e7224742a68c18c09a7f5ae233363465a4niq * - one for the following (probably failed) reconnect attempt */
fd0edaa8e3d4dd67d0604ccef2e96b071db96643fielding count = be_fo_get_server_count(op->conn_cache->id_ctx->be,
struct sdap_id_op_connect_state {
int dp_error;
int result;
struct sdap_id_op_connect_state);
int *ret_out)
if (!memctx) {
goto done;
goto done;
if (!req) {
goto done;
goto done;
goto done;
done:
if (ret_out) {
return req;
if (conn_data) {
goto done;
goto done;
if (!conn_data) {
goto done;
if (!subreq) {
goto done;
done:
return ret;
bool can_retry = false;
bool is_offline = false;
int ret;
is_offline = true;
if (current_srv_opts) {
if (can_retry) {
switch (ret) {
case EOK:
case ENOTSUP:
case EACCES:
case EIO:
case EFAULT:
case ETIMEDOUT:
can_retry = false;
is_offline = true;
int notify_count = 0;
if (!op) {
notify_count++;
bool retry = false;
if (can_retry) {
can_retry = false;
is_offline = true;
retry = true;
retry = true;
can_retry = false;
} else if (is_offline) {
if (!req) {
struct sdap_id_op_connect_state);
bool communication_error;
switch (retval) {
case EIO:
case ETIMEDOUT:
communication_error = true;
communication_error = false;
int dp_err;
} else if (communication_error) {
return retval;