/** * Submit new songs from the queue */ static gboolean as_submit(void) { gchar *querystring; gint ret; gushort num_songs; if (queue_get_length() < 1) return FALSE; num_songs = build_querystring(&querystring); if (num_songs <= 0) { g_free(querystring); return FALSE; } g_debug("querystring = %s", querystring); curl_easy_setopt(as_conn.handle, CURLOPT_WRITEDATA, buffer); curl_easy_setopt(as_conn.handle, CURLOPT_POSTFIELDS, querystring); curl_easy_setopt(as_conn.handle, CURLOPT_URL, API_URL); ret = curl_easy_perform(as_conn.handle); g_free(querystring); if (ret != 0) { g_message("Failed to connect to Audioscrobbler: %s", curl_easy_strerror(ret)); return FALSE; } if (strstr(buffer, "<lfm status=\"ok\">")) { g_message("%d song%s submitted.", num_songs, (num_songs > 1 ? "s" : "")); queue_clear_n(num_songs); } else if (strstr(buffer, "<lfm status=\"failed\">")) { as_parse_error(buffer); } else { g_message("Could not parse Audioscrobbler submit" " response."); g_debug("Response was: %s", buffer); } g_free(buffer); buffer = NULL; return TRUE; }
/*% * This function is the real core of the driver. Zone, record * and client strings are passed in (or NULL is passed if the * string is not available). The type of query we want to run * is indicated by the query flag, and the dbdata object is passed * passed in to. dbdata really holds either: * 1) a list of database instances (in multithreaded mode) OR * 2) a single database instance (in single threaded mode) * The function will construct the query and obtain an available * database instance (DBI). It will then run the query and hopefully * obtain a result set. Postgres is nice, in that once the result * set is returned, we can make the db connection available for another * thread to use, while this thread continues on. So, the DBI is made * available ASAP by unlocking the instance_lock after we have cleaned * it up properly. */ static isc_result_t postgres_get_resultset(const char *zone, const char *record, const char *client, unsigned int query, void *dbdata, PGresult **rs) { isc_result_t result; dbinstance_t *dbi = NULL; char *querystring = NULL; unsigned int i = 0; unsigned int j = 0; /* temporarily get a unique thread # */ unsigned int dlz_thread_num = 1+(int) (1000.0*rand()/(RAND_MAX+1.0)); REQUIRE(*rs == NULL); #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d Getting DBI", dlz_thread_num); #endif /* get db instance / connection */ #ifdef ISC_PLATFORM_USETHREADS /* find an available DBI from the list */ dbi = postgres_find_avail_conn((db_list_t *) dbdata); #else /* ISC_PLATFORM_USETHREADS */ /* * only 1 DBI - no need to lock instance lock either * only 1 thread in the whole process, no possible contention. */ dbi = (dbinstance_t *) dbdata; #endif /* ISC_PLATFORM_USETHREADS */ #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d Got DBI - checking query", dlz_thread_num); #endif /* if DBI is null, can't do anything else */ if (dbi == NULL) { result = ISC_R_FAILURE; goto cleanup; } /* what type of query are we going to run? */ switch(query) { case ALLNODES: /* * if the query was not passed in from the config file * then we can't run it. return not_implemented, so * it's like the code for that operation was never * built into the driver.... AHHH flexibility!!! */ if (dbi->allnodes_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case ALLOWXFR: /* same as comments as ALLNODES */ if (dbi->allowxfr_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case AUTHORITY: /* same as comments as ALLNODES */ if (dbi->authority_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case FINDZONE: /* this is required. It's the whole point of DLZ! */ if (dbi->findzone_q == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "No query specified for findzone. " "Findzone requires a query"); result = ISC_R_FAILURE; goto cleanup; } break; case LOOKUP: /* this is required. It's also a major point of DLZ! */ if (dbi->lookup_q == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "No query specified for lookup. " "Lookup requires a query"); result = ISC_R_FAILURE; goto cleanup; } break; default: /* * this should never happen. If it does, the code is * screwed up! */ UNEXPECTED_ERROR(__FILE__, __LINE__, "Incorrect query flag passed to " "postgres_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d checked query", dlz_thread_num); #endif /* * was a zone string passed? If so, make it safe for use in * queries. */ if (zone != NULL) { dbi->zone = postgres_escape_string(zone); if (dbi->zone == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { /* no string passed, set the string pointer to NULL */ dbi->zone = NULL; } #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d did zone", dlz_thread_num); #endif /* * was a record string passed? If so, make it safe for use in * queries. */ if (record != NULL) { dbi->record = postgres_escape_string(record); if (dbi->record == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { /* no string passed, set the string pointer to NULL */ dbi->record = NULL; } #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d did record", dlz_thread_num); #endif /* * was a client string passed? If so, make it safe for use in * queries. */ if (client != NULL) { dbi->client = postgres_escape_string(client); if (dbi->client == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { /* no string passed, set the string pointer to NULL */ dbi->client = NULL; } #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d did client", dlz_thread_num); #endif /* * what type of query are we going to run? * this time we build the actual query to run. */ switch(query) { case ALLNODES: querystring = build_querystring(ns_g_mctx, dbi->allnodes_q); break; case ALLOWXFR: querystring = build_querystring(ns_g_mctx, dbi->allowxfr_q); break; case AUTHORITY: querystring = build_querystring(ns_g_mctx, dbi->authority_q); break; case FINDZONE: querystring = build_querystring(ns_g_mctx, dbi->findzone_q); break; case LOOKUP: querystring = build_querystring(ns_g_mctx, dbi->lookup_q); break; default: /* * this should never happen. If it does, the code is * screwed up! */ UNEXPECTED_ERROR(__FILE__, __LINE__, "Incorrect query flag passed to " "postgres_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d built query", dlz_thread_num); #endif /* if the querystring is null, Bummer, outta RAM. UPGRADE TIME!!! */ if (querystring == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d query is '%s'", dlz_thread_num, querystring); #endif /* * output the full query string during debug so we can see * what lame error the query has. */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1), "\nQuery String: %s\n", querystring); /* attempt query up to 3 times. */ for (j=0; j < 3; j++) { #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d executing query for %d time", dlz_thread_num, j); #endif /* try to get result set */ *rs = PQexec((PGconn *)dbi->dbconn, querystring ); result = ISC_R_SUCCESS; /* * if result set is null, reset DB connection, max 3 * attempts. */ for (i=0; *rs == NULL && i < 3; i++) { #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d resetting connection", dlz_thread_num); #endif result = ISC_R_FAILURE; PQreset((PGconn *) dbi->dbconn); /* connection ok, break inner loop */ if (PQstatus((PGconn *) dbi->dbconn) == CONNECTION_OK) break; } /* result set ok, break outter loop */ if (PQresultStatus(*rs) == PGRES_TUPLES_OK) { #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d rs ok", dlz_thread_num); #endif break; } else { /* we got a result set object, but it's not right. */ #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d clearing rs", dlz_thread_num); #endif PQclear(*rs); /* get rid of it */ /* in case this was the last attempt */ result = ISC_R_FAILURE; } } cleanup: /* it's always good to cleanup after yourself */ #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d cleaning up", dlz_thread_num); #endif /* if we couldn't even allocate DBI, just return NULL */ if (dbi == NULL) return ISC_R_FAILURE; /* free dbi->zone string */ if (dbi->zone != NULL) isc_mem_free(ns_g_mctx, dbi->zone); /* free dbi->record string */ if (dbi->record != NULL) isc_mem_free(ns_g_mctx, dbi->record); /* free dbi->client string */ if (dbi->client != NULL) isc_mem_free(ns_g_mctx, dbi->client); #ifdef ISC_PLATFORM_USETHREADS #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d unlocking mutex", dlz_thread_num); #endif /* release the lock so another thread can use this dbi */ isc_mutex_unlock(&dbi->instance_lock); #endif /* ISC_PLATFORM_USETHREADS */ /* release query string */ if (querystring != NULL) isc_mem_free(ns_g_mctx, querystring ); #if 0 /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d returning", dlz_thread_num); #endif /* return result */ return result; }
static isc_result_t mysql_get_resultset(const char *zone, const char *record, const char *client, unsigned int query, void *dbdata, MYSQL_RES **rs) { isc_result_t result; dbinstance_t *dbi = NULL; char *querystring = NULL; unsigned int i = 0; unsigned int j = 0; int qres = 0; if (query != COUNTZONE) REQUIRE(*rs == NULL); else REQUIRE(rs == NULL); /* get db instance / connection */ dbi = (dbinstance_t *) dbdata; /* if DBI is null, can't do anything else */ if (dbi == NULL) { result = ISC_R_FAILURE; goto cleanup; } /* what type of query are we going to run? */ switch(query) { case ALLNODES: /* * if the query was not passed in from the config file * then we can't run it. return not_implemented, so * it's like the code for that operation was never * built into the driver.... AHHH flexibility!!! */ if (dbi->allnodes_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case ALLOWXFR: /* same as comments as ALLNODES */ if (dbi->allowxfr_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case AUTHORITY: /* same as comments as ALLNODES */ if (dbi->authority_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case FINDZONE: /* this is required. It's the whole point of DLZ! */ if (dbi->findzone_q == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "No query specified for findzone. " "Findzone requires a query"); result = ISC_R_FAILURE; goto cleanup; } break; case COUNTZONE: /* same as comments as ALLNODES */ if (dbi->countzone_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case LOOKUP: /* this is required. It's also a major point of DLZ! */ if (dbi->lookup_q == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "No query specified for lookup. " "Lookup requires a query"); result = ISC_R_FAILURE; goto cleanup; } break; default: /* * this should never happen. If it does, the code is * screwed up! */ UNEXPECTED_ERROR(__FILE__, __LINE__, "Incorrect query flag passed to " "mysql_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } /* * was a zone string passed? If so, make it safe for use in * queries. */ if (zone != NULL) { dbi->zone = mysqldrv_escape_string((MYSQL *) dbi->dbconn, zone); if (dbi->zone == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { /* no string passed, set the string pointer to NULL */ dbi->zone = NULL; } /* * was a record string passed? If so, make it safe for use in * queries. */ if (record != NULL) { dbi->record = mysqldrv_escape_string((MYSQL *) dbi->dbconn, record); if (dbi->record == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { /* no string passed, set the string pointer to NULL */ dbi->record = NULL; } /* * was a client string passed? If so, make it safe for use in * queries. */ if (client != NULL) { dbi->client = mysqldrv_escape_string((MYSQL *) dbi->dbconn, client); if (dbi->client == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { /* no string passed, set the string pointer to NULL */ dbi->client = NULL; } /* * what type of query are we going to run? this time we build * the actual query to run. */ switch(query) { case ALLNODES: querystring = build_querystring(ns_g_mctx, dbi->allnodes_q); break; case ALLOWXFR: querystring = build_querystring(ns_g_mctx, dbi->allowxfr_q); break; case AUTHORITY: querystring = build_querystring(ns_g_mctx, dbi->authority_q); break; case FINDZONE: querystring = build_querystring(ns_g_mctx, dbi->findzone_q); break; case COUNTZONE: querystring = build_querystring(ns_g_mctx, dbi->countzone_q); break; case LOOKUP: querystring = build_querystring(ns_g_mctx, dbi->lookup_q); break; default: /* * this should never happen. If it does, the code is * screwed up! */ UNEXPECTED_ERROR(__FILE__, __LINE__, "Incorrect query flag passed to " "mysql_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } /* if the querystring is null, Bummer, outta RAM. UPGRADE TIME!!! */ if (querystring == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } /* * output the full query string during debug so we can see * what lame error the query has. */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1), "\nQuery String: %s\n", querystring); /* attempt query up to 3 times. */ for (i=0; i < 3; i++) { qres = mysql_query((MYSQL *) dbi->dbconn, querystring); if (qres == 0) break; for (j=0; mysql_ping((MYSQL *) dbi->dbconn) != 0 && j < 4; j++) ; } if (qres == 0) { result = ISC_R_SUCCESS; if (query != COUNTZONE) { *rs = mysql_store_result((MYSQL *) dbi->dbconn); if (*rs == NULL) result = ISC_R_FAILURE; } } else { result = ISC_R_FAILURE; } cleanup: /* it's always good to cleanup after yourself */ /* if we couldn't even get DBI, just return NULL */ if (dbi == NULL) return ISC_R_FAILURE; /* free dbi->zone string */ if (dbi->zone != NULL) isc_mem_free(ns_g_mctx, dbi->zone); /* free dbi->record string */ if (dbi->record != NULL) isc_mem_free(ns_g_mctx, dbi->record); /* free dbi->client string */ if (dbi->client != NULL) isc_mem_free(ns_g_mctx, dbi->client); /* release query string */ if (querystring != NULL) isc_mem_free(ns_g_mctx, querystring); /* return result */ return result; }
/*% * This function is the real core of the module. Zone, record * and client strings are passed in (or NULL is passed if the * string is not available). The type of query we want to run * is indicated by the query flag, and the dbdata object is passed * passed in to. dbdata really holds a single database instance. * The function will construct and run the query, hopefully getting * a result set. */ static isc_result_t mysql_get_resultset(const char *zone, const char *record, const char *client, unsigned int query, void *dbdata, MYSQL_RES **rs) { isc_result_t result; dbinstance_t *dbi = NULL; mysql_instance_t *db = (mysql_instance_t *)dbdata; char *querystring = NULL; unsigned int i = 0; unsigned int j = 0; int qres = 0; #if PTHREADS /* find an available DBI from the list */ dbi = mysql_find_avail_conn(db); #else /* PTHREADS */ /* * only 1 DBI - no need to lock instance lock either * only 1 thread in the whole process, no possible contention. */ dbi = (dbinstance_t *)(db->db); #endif /* PTHREADS */ if (dbi == NULL) { result = ISC_R_FAILURE; goto cleanup; } /* what type of query are we going to run? */ switch(query) { case ALLNODES: if (dbi->allnodes_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case ALLOWXFR: if (dbi->allowxfr_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case AUTHORITY: if (dbi->authority_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case FINDZONE: if (dbi->findzone_q == NULL) { db->log(ISC_LOG_DEBUG(2), "No query specified for findzone. " "Findzone requires a query"); result = ISC_R_FAILURE; goto cleanup; } break; case COUNTZONE: if (dbi->countzone_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case LOOKUP: if (dbi->lookup_q == NULL) { db->log(ISC_LOG_DEBUG(2), "No query specified for lookup. " "Lookup requires a query"); result = ISC_R_FAILURE; goto cleanup; } break; default: db->log(ISC_LOG_ERROR, "Incorrect query flag passed to " "mysql_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } if (zone != NULL) { if (dbi->zone != NULL) free(dbi->zone); dbi->zone = mysqldrv_escape_string((MYSQL *) dbi->dbconn, zone); if (dbi->zone == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else dbi->zone = NULL; if (record != NULL) { if (dbi->record != NULL) free(dbi->record); dbi->record = mysqldrv_escape_string((MYSQL *) dbi->dbconn, record); if (dbi->record == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else dbi->record = NULL; if (client != NULL) { if (dbi->client != NULL) free(dbi->client); dbi->client = mysqldrv_escape_string((MYSQL *) dbi->dbconn, client); if (dbi->client == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else dbi->client = NULL; /* * what type of query are we going to run? this time we build * the actual query to run. */ switch(query) { case ALLNODES: querystring = build_querystring(dbi->allnodes_q); break; case ALLOWXFR: querystring = build_querystring(dbi->allowxfr_q); break; case AUTHORITY: querystring = build_querystring(dbi->authority_q); break; case FINDZONE: querystring = build_querystring(dbi->findzone_q); break; case COUNTZONE: querystring = build_querystring(dbi->countzone_q); break; case LOOKUP: querystring = build_querystring(dbi->lookup_q); break; default: db->log(ISC_LOG_ERROR, "Incorrect query flag passed to " "mysql_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } if (querystring == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } /* output the full query string when debugging */ db->log(ISC_LOG_DEBUG(1), "\nQuery String: %s\n", querystring); /* attempt query up to 3 times. */ for (i = 0; i < 3; i++) { qres = mysql_query((MYSQL *) dbi->dbconn, querystring); if (qres == 0) break; for (j = 0; j < 4; j++) if (mysql_ping((MYSQL *) dbi->dbconn) == 0) break; } if (qres == 0) { result = ISC_R_SUCCESS; if (query != COUNTZONE) { *rs = mysql_store_result((MYSQL *) dbi->dbconn); if (*rs == NULL) result = ISC_R_FAILURE; } } else result = ISC_R_FAILURE; cleanup: if (dbi == NULL) return (ISC_R_FAILURE); if (dbi->zone != NULL) { free(dbi->zone); dbi->zone = NULL; } if (dbi->record != NULL) { free(dbi->record); dbi->record = NULL; } if (dbi->client != NULL) { free(dbi->client); dbi->client = NULL; } /* release the lock so another thread can use this dbi */ (void) dlz_mutex_unlock(&dbi->lock); if (querystring != NULL) free(querystring); return (result); }
static isc_result_t odbc_get_resultset(const char *zone, const char *record, const char *client, unsigned int query, void *dbdata, dbinstance_t **r_dbi) { isc_result_t result; dbinstance_t *dbi = NULL; char *querystring = NULL; unsigned int j = 0; SQLRETURN sqlRes; REQUIRE(*r_dbi == NULL); /* get db instance / connection */ #ifdef ISC_PLATFORM_USETHREADS /* find an available DBI from the list */ dbi = odbc_find_avail_conn(((odbc_instance_t *) dbdata)->db); #else /* ISC_PLATFORM_USETHREADS */ /* * only 1 DBI - no need to lock instance lock either * only 1 thread in the whole process, no possible contention. */ dbi = (dbinstance_t *) ((odbc_instance_t *) dbdata)->db; #endif /* ISC_PLATFORM_USETHREADS */ /* if DBI is null, can't do anything else */ if (dbi == NULL) { result = ISC_R_FAILURE; goto cleanup; } /* what type of query are we going to run? */ switch(query) { case ALLNODES: /* * if the query was not passed in from the config file * then we can't run it. return not_implemented, so * it's like the code for that operation was never * built into the driver.... AHHH flexibility!!! */ if (dbi->allnodes_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case ALLOWXFR: /* same as comments as ALLNODES */ if (dbi->allowxfr_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case AUTHORITY: /* same as comments as ALLNODES */ if (dbi->authority_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } break; case FINDZONE: /* this is required. It's the whole point of DLZ! */ if (dbi->findzone_q == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "No query specified for findzone. " "Findzone requires a query"); result = ISC_R_FAILURE; goto cleanup; } break; case LOOKUP: /* this is required. It's also a major point of DLZ! */ if (dbi->lookup_q == NULL) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2), "No query specified for lookup. " "Lookup requires a query"); result = ISC_R_FAILURE; goto cleanup; } break; default: /* * this should never happen. If it does, the code is * screwed up! */ UNEXPECTED_ERROR(__FILE__, __LINE__, "Incorrect query flag passed to " "odbc_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } /* * was a zone string passed? If so, make it safe for use in * queries. */ if (zone != NULL) { dbi->zone = odbc_escape_string(zone); if (dbi->zone == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { /* no string passed, set the string pointer to NULL */ dbi->zone = NULL; } /* * was a record string passed? If so, make it safe for use in * queries. */ if (record != NULL) { dbi->record = odbc_escape_string(record); if (dbi->record == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { /* no string passed, set the string pointer to NULL */ dbi->record = NULL; } /* * was a client string passed? If so, make it safe for use in * queries. */ if (client != NULL) { dbi->client = odbc_escape_string(client); if (dbi->client == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else { /* no string passed, set the string pointer to NULL */ dbi->client = NULL; } /* * what type of query are we going to run? * this time we build the actual query to run. */ switch(query) { case ALLNODES: querystring = build_querystring(ns_g_mctx, dbi->allnodes_q); break; case ALLOWXFR: querystring = build_querystring(ns_g_mctx, dbi->allowxfr_q); break; case AUTHORITY: querystring = build_querystring(ns_g_mctx, dbi->authority_q); break; case FINDZONE: querystring = build_querystring(ns_g_mctx, dbi->findzone_q); break; case LOOKUP: querystring = build_querystring(ns_g_mctx, dbi->lookup_q); break; default: /* * this should never happen. If it does, the code is * screwed up! */ UNEXPECTED_ERROR(__FILE__, __LINE__, "Incorrect query flag passed to " "odbc_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } /* if the querystring is null, Bummer, outta RAM. UPGRADE TIME!!! */ if (querystring == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } /* output the full query string during debug so we can see */ /* what lame error the query has. */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1), "\nQuery String: %s\n", querystring); /* attempt query up to 3 times. */ for (j=0; j < 3; j++) { /* try to get result set */ sqlRes = SQLExecDirect(((odbc_db_t *) dbi->dbconn)->stmnt, (SQLCHAR *) querystring, (SQLINTEGER) strlen(querystring)); /* if error, reset DB connection */ if (!sqlOK(sqlRes)) { /* close cursor */ SQLCloseCursor(((odbc_db_t *) dbi->dbconn)->stmnt); /* attempt to reconnect */ result = odbc_connect((odbc_instance_t *) dbdata, (odbc_db_t **) &(dbi->dbconn)); /* check if we reconnected */ if (result != ISC_R_SUCCESS) break; /* incase this is the last time through the loop */ result = ISC_R_FAILURE; } else { result = ISC_R_SUCCESS; /* return dbi */ *r_dbi = dbi; /* result set ok, break loop */ break; } } /* end for loop */ cleanup: /* it's always good to cleanup after yourself */ /* if we couldn't even allocate DBI, just return NULL */ if (dbi == NULL) return ISC_R_FAILURE; /* free dbi->zone string */ if (dbi->zone != NULL) isc_mem_free(ns_g_mctx, dbi->zone); /* free dbi->record string */ if (dbi->record != NULL) isc_mem_free(ns_g_mctx, dbi->record); /* free dbi->client string */ if (dbi->client != NULL) isc_mem_free(ns_g_mctx, dbi->client); #ifdef ISC_PLATFORM_USETHREADS /* if we are done using this dbi, release the lock */ if (result != ISC_R_SUCCESS) isc_mutex_unlock(&dbi->instance_lock); #endif /* ISC_PLATFORM_USETHREADS */ /* release query string */ if (querystring != NULL) isc_mem_free(ns_g_mctx, querystring ); /* return result */ return result; }
/*% * This function is the real core of the driver. Zone, record * and client strings are passed in (or NULL is passed if the * string is not available). The type of query we want to run * is indicated by the query flag, and the dbdata object is passed * passed in to. dbdata really holds either: * 1) a list of database instances (in multithreaded mode) OR * 2) a single database instance (in single threaded mode) * The function will construct the query and obtain an available * database instance (DBI). It will then run the query and hopefully * obtain a result set. */ static isc_result_t ldap_get_results(const char *zone, const char *record, const char *client, unsigned int query, void *dbdata, void *ptr) { isc_result_t result; ldap_instance_t *db = (ldap_instance_t *)dbdata; dbinstance_t *dbi = NULL; char *querystring = NULL; LDAPURLDesc *ldap_url = NULL; int ldap_result = 0; LDAPMessage *ldap_msg = NULL; int i; int entries; /* get db instance / connection */ #if PTHREADS /* find an available DBI from the list */ dbi = ldap_find_avail_conn(db); #else /* PTHREADS */ /* * only 1 DBI - no need to lock instance lock either * only 1 thread in the whole process, no possible contention. */ dbi = (dbinstance_t *)(db->db); #endif /* PTHREADS */ /* if DBI is null, can't do anything else */ if (dbi == NULL) return (ISC_R_FAILURE); /* set fields */ if (zone != NULL) { dbi->zone = strdup(zone); if (dbi->zone == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else dbi->zone = NULL; if (record != NULL) { dbi->record = strdup(record); if (dbi->record == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else dbi->record = NULL; if (client != NULL) { dbi->client = strdup(client); if (dbi->client == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } } else dbi->client = NULL; /* what type of query are we going to run? */ switch (query) { case ALLNODES: /* * if the query was not passed in from the config file * then we can't run it. return not_implemented, so * it's like the code for that operation was never * built into the driver.... AHHH flexibility!!! */ if (dbi->allnodes_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } else querystring = build_querystring(dbi->allnodes_q); break; case ALLOWXFR: /* same as comments as ALLNODES */ if (dbi->allowxfr_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } else querystring = build_querystring(dbi->allowxfr_q); break; case AUTHORITY: /* same as comments as ALLNODES */ if (dbi->authority_q == NULL) { result = ISC_R_NOTIMPLEMENTED; goto cleanup; } else querystring = build_querystring(dbi->authority_q); break; case FINDZONE: /* this is required. It's the whole point of DLZ! */ if (dbi->findzone_q == NULL) { db->log(ISC_LOG_DEBUG(2), "No query specified for findzone. " "Findzone requires a query"); result = ISC_R_FAILURE; goto cleanup; } else querystring = build_querystring(dbi->findzone_q); break; case LOOKUP: /* this is required. It's also a major point of DLZ! */ if (dbi->lookup_q == NULL) { db->log(ISC_LOG_DEBUG(2), "No query specified for lookup. " "Lookup requires a query"); result = ISC_R_FAILURE; goto cleanup; } else querystring = build_querystring(dbi->lookup_q); break; default: /* * this should never happen. If it does, the code is * screwed up! */ db->log(ISC_LOG_ERROR, "Incorrect query flag passed to ldap_get_results"); result = ISC_R_UNEXPECTED; goto cleanup; } /* if the querystring is null, Bummer, outta RAM. UPGRADE TIME!!! */ if (querystring == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } /* * output the full query string during debug so we can see * what lame error the query has. */ db->log(ISC_LOG_DEBUG(1), "Query String: %s", querystring); /* break URL down into it's component parts, if error cleanup */ ldap_result = ldap_url_parse(querystring, &ldap_url); if (ldap_result != LDAP_SUCCESS || ldap_url == NULL) { result = ISC_R_FAILURE; goto cleanup; } for (i = 0; i < 3; i++) { /* * dbi->dbconn may be null if trying to reconnect on a * previous query failed. */ if (dbi->dbconn == NULL) { db->log(ISC_LOG_INFO, "LDAP driver attempting to re-connect"); result = ldap_connect((ldap_instance_t *) dbdata, dbi); if (result != ISC_R_SUCCESS) { result = ISC_R_FAILURE; continue; } } /* perform ldap search syncronously */ ldap_result = ldap_search_s((LDAP *) dbi->dbconn, ldap_url->lud_dn, ldap_url->lud_scope, ldap_url->lud_filter, ldap_url->lud_attrs, 0, &ldap_msg); /* * check return code. No such object is ok, just * didn't find what we wanted */ switch (ldap_result) { case LDAP_NO_SUCH_OBJECT: db->log(ISC_LOG_DEBUG(1), "No object found matching query requirements"); result = ISC_R_NOTFOUND; goto cleanup; break; case LDAP_SUCCESS: /* on success do nothing */ result = ISC_R_SUCCESS; i = 3; break; case LDAP_SERVER_DOWN: db->log(ISC_LOG_INFO, "LDAP driver attempting to re-connect"); result = ldap_connect((ldap_instance_t *) dbdata, dbi); if (result != ISC_R_SUCCESS) result = ISC_R_FAILURE; break; default: /* * other errors not ok. Log error message and * get out */ db->log(ISC_LOG_ERROR, "LDAP error: %s", ldap_err2string(ldap_result)); result = ISC_R_FAILURE; goto cleanup; break; } } if (result != ISC_R_SUCCESS) goto cleanup; switch (query) { case ALLNODES: result = ldap_process_results(db, (LDAP *) dbi->dbconn, ldap_msg, ldap_url->lud_attrs, ptr, ISC_TRUE); break; case AUTHORITY: case LOOKUP: result = ldap_process_results(db, (LDAP *) dbi->dbconn, ldap_msg, ldap_url->lud_attrs, ptr, ISC_FALSE); break; case ALLOWXFR: entries = ldap_count_entries((LDAP *) dbi->dbconn, ldap_msg); if (entries == 0) result = ISC_R_NOPERM; else if (entries > 0) result = ISC_R_SUCCESS; else result = ISC_R_FAILURE; break; case FINDZONE: entries = ldap_count_entries((LDAP *) dbi->dbconn, ldap_msg); if (entries == 0) result = ISC_R_NOTFOUND; else if (entries > 0) result = ISC_R_SUCCESS; else result = ISC_R_FAILURE; break; default: /* * this should never happen. If it does, the code is * screwed up! */ db->log(ISC_LOG_ERROR, "Incorrect query flag passed to ldap_get_results"); result = ISC_R_UNEXPECTED; } cleanup: /* it's always good to cleanup after yourself */ /* if we retrieved results, free them */ if (ldap_msg != NULL) ldap_msgfree(ldap_msg); if (ldap_url != NULL) ldap_free_urldesc(ldap_url); /* cleanup */ if (dbi->zone != NULL) free(dbi->zone); if (dbi->record != NULL) free(dbi->record); if (dbi->client != NULL) free(dbi->client); dbi->zone = dbi->record = dbi->client = NULL; /* release the lock so another thread can use this dbi */ (void) dlz_mutex_unlock(&dbi->lock); /* release query string */ if (querystring != NULL) free(querystring); /* return result */ return (result); }