]> git.ipfire.org Git - thirdparty/pdns.git/blob - modules/opendbxbackend/odbxprivate.cc
2eb0f9bab082ff3c656c06330625f6533b2f8b1f
[thirdparty/pdns.git] / modules / opendbxbackend / odbxprivate.cc
1 /*
2 * PowerDNS OpenDBX Backend
3 * Copyright (C) 2005-2007 Norbert Sendetzky <norbert@linuxnetworks.de>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation
8 *
9 * Additionally, the license of this program contains a special
10 * exception which allows to distribute the program in binary form when
11 * it is linked against OpenSSL.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include "odbxbackend.hh"
27
28
29
30 unsigned int odbx_host_index[2] = { 0, 0 };
31
32
33
34 bool OdbxBackend::connectTo( const vector<string>& hosts, QueryType type )
35 {
36 int err;
37 unsigned int h, i;
38 int idx = odbx_host_index[type]++ % hosts.size();
39
40
41 if( m_handle[type] != NULL )
42 {
43 odbx_unbind( m_handle[type] );
44 odbx_finish( m_handle[type] );
45 m_handle[type] = NULL;
46 }
47
48 if( type == WRITE && getArg( "backend" ) == "sqlite" )
49 {
50 L.log( m_myname + " Using same SQLite connection for reading and writing to '" + hosts[odbx_host_index[READ]] + "'", Logger::Notice );
51 m_handle[WRITE] = m_handle[READ];
52 return true;
53 }
54
55 for( i = 0; i < hosts.size(); i++ )
56 {
57 h = ( idx + i ) % hosts.size();
58
59 if( ( err = odbx_init( &(m_handle[type]), getArg( "backend" ).c_str(), hosts[h].c_str(), getArg( "port" ).c_str() ) ) == ODBX_ERR_SUCCESS )
60 {
61 if( ( err = odbx_bind( m_handle[type], getArg( "database" ).c_str(), getArg( "username" ).c_str(), getArg( "password" ).c_str(), ODBX_BIND_SIMPLE ) ) == ODBX_ERR_SUCCESS )
62 {
63 L.log( m_myname + " Database connection (" + (type ? "write" : "read") + ") to '" + hosts[h] + "' succeeded", Logger::Notice );
64 return true;
65 }
66
67 L.log( m_myname + " Unable to bind to database on host " + hosts[h] + " - " + string( odbx_error( m_handle[type], err ) ), Logger::Error );
68 continue;
69 }
70
71 L.log( m_myname + " Unable to connect to server on host " + hosts[h] + " - " + string( odbx_error( m_handle[type], err ) ), Logger::Error );
72 }
73
74 m_handle[type] = NULL;
75 return false;
76 }
77
78
79
80 bool OdbxBackend::execStmt( const char* stmt, unsigned long length, QueryType type )
81 {
82 int err;
83
84
85 DLOG( L.log( m_myname + " execStmt()", Logger::Debug ) );
86
87 if( m_qlog ) { L.log( m_myname + " Query: " + stmt, Logger::Info ); }
88
89 if( ( err = odbx_query( m_handle[type], stmt, length ) ) < 0 )
90 {
91 L.log( m_myname + " execStmt: Unable to execute query - " + string( odbx_error( m_handle[type], err ) ), Logger::Error );
92
93 if( err != -ODBX_ERR_PARAM && odbx_error_type( m_handle[type], err ) > 0 ) { return false; } // ODBX_ERR_PARAM workaround
94 if( !connectTo( m_hosts[type], type ) ) { return false; }
95 if( odbx_query( m_handle[type], stmt, length ) < 0 ) { return false; }
96 }
97
98 if( type == WRITE ) { while( getRecord( type ) ); }
99
100 return true;
101 }
102
103
104
105 bool OdbxBackend::getRecord( QueryType type )
106 {
107 int err = 3;
108
109
110 DLOG( L.log( m_myname + " getRecord()", Logger::Debug ) );
111
112 do
113 {
114 if( err < 0 )
115 {
116 L.log( m_myname + " getRecord: Unable to get next result - " + string( odbx_error( m_handle[type], err ) ), Logger::Error );
117 throw( PDNSException( "Error: odbx_result() failed" ) );
118 }
119
120 if( m_result != NULL )
121 {
122 if( err == 3 )
123 {
124 if( ( err = odbx_row_fetch( m_result ) ) < 0 )
125 {
126 L.log( m_myname + " getRecord: Unable to get next row - " + string( odbx_error( m_handle[type], err ) ), Logger::Error );
127 throw( PDNSException( "Error: odbx_row_fetch() failed" ) );
128 }
129
130 if( err > 0 )
131 {
132 #ifdef VERBOSELOG
133 unsigned int i;
134 string fields;
135
136 for( i = 0; i < odbx_column_count( m_result ); i++ )
137 {
138 fields += string( odbx_column_name( m_result, i ) );
139
140 if( odbx_field_value( m_result, i ) != NULL )
141 {
142 fields += "=" + string( odbx_field_value( m_result, i ) ) + ", ";
143 }
144 else
145 {
146 fields += "=NULL, ";
147 }
148 }
149
150 L.log( m_myname + " Values: " + fields, Logger::Error );
151 #endif
152 return true;
153 }
154
155 }
156
157 odbx_result_free( m_result );
158 m_result = NULL;
159 }
160 }
161 while( ( err = odbx_result( m_handle[type], &m_result, NULL, 0 ) ) != 0 );
162
163 m_result = NULL;
164 return false;
165 }
166
167
168
169 string OdbxBackend::escape( const string& str, QueryType type )
170 {
171 int err;
172 unsigned long len = sizeof( m_escbuf );
173
174
175 DLOG( L.log( m_myname + " escape(string)", Logger::Debug ) );
176
177 if( ( err = odbx_escape( m_handle[type], str.c_str(), str.size(), m_escbuf, &len ) ) < 0 )
178 {
179 L.log( m_myname + " escape(string): Unable to escape string - " + string( odbx_error( m_handle[type], err ) ), Logger::Error );
180
181 if( err != -ODBX_ERR_PARAM && odbx_error_type( m_handle[type], err ) > 0 ) { throw( runtime_error( "odbx_escape() failed" ) ); } // ODBX_ERR_PARAM workaround
182 if( !connectTo( m_hosts[type], type ) ) { throw( runtime_error( "odbx_escape() failed" ) ); }
183 if( odbx_escape( m_handle[type], str.c_str(), str.size(), m_escbuf, &len ) < 0 ) { throw( runtime_error( "odbx_escape() failed" ) ); }
184 }
185
186 return string( m_escbuf, len );
187 }
188
189
190
191 bool OdbxBackend::getDomainList( const string& stmt, vector<DomainInfo>* list, bool (*check_fcn)(uint32_t,uint32_t,SOAData*,DomainInfo*) )
192 {
193 const char* tmp;
194 uint32_t nlast, nserial;
195
196 SOAData sd;
197
198 DLOG( L.log( m_myname + " getDomainList()", Logger::Debug ) );
199
200 if( !execStmt( stmt.c_str(), stmt.size(), READ ) ) { return false; }
201 if( !getRecord( READ ) ) { return false; }
202
203 do
204 {
205 DomainInfo di;
206 nlast = 0;
207 nserial = 0;
208 sd.serial = 0;
209 sd.refresh = 0;
210
211 if( ( tmp = odbx_field_value( m_result, 6 ) ) != NULL )
212 {
213 fillSOAData( string( tmp, odbx_field_length( m_result, 6 ) ), sd );
214 }
215
216 if( !sd.serial && ( tmp = odbx_field_value( m_result, 5 ) ) != NULL )
217 {
218 sd.serial = strtol( tmp, NULL, 10 );
219 }
220
221 if( ( tmp = odbx_field_value( m_result, 4 ) ) != NULL )
222 {
223 nserial = strtol( tmp, NULL, 10 );
224 }
225
226 if( ( tmp = odbx_field_value( m_result, 3 ) ) != NULL )
227 {
228 nlast = strtol( tmp, NULL, 10 );
229 }
230
231 if( (*check_fcn)( nlast, nserial, &sd, &di ) )
232 {
233 if( ( tmp = odbx_field_value( m_result, 2 ) ) != NULL )
234 {
235 stringtok(di.masters, string( tmp, odbx_field_length( m_result, 2 )), ", \t" );
236 }
237
238 if( ( tmp = odbx_field_value( m_result, 1 ) ) != NULL )
239 {
240 di.zone = DNSName( string(tmp, odbx_field_length( m_result, 1 )) );
241 }
242
243 if( ( tmp = odbx_field_value( m_result, 0 ) ) != NULL )
244 {
245 di.id = strtol( tmp, NULL, 10 );
246 }
247
248 di.last_check = nlast;
249 di.notified_serial = nserial;
250 di.serial = sd.serial;
251 di.backend = this;
252
253 list->push_back( di );
254 }
255 }
256 while( getRecord( READ ) );
257
258 return true;
259 }
260
261
262
263 bool checkSlave( uint32_t nlast, uint32_t nserial, SOAData* sd, DomainInfo* di )
264 {
265 if( nlast + sd->refresh < (uint32_t) time( 0 ) )
266 {
267 di->kind = DomainInfo::Slave;
268 return true;
269 }
270
271 return false;
272 }
273
274
275
276 bool checkMaster( uint32_t nlast, uint32_t nserial, SOAData* sd, DomainInfo* di )
277 {
278 if( nserial != sd->serial )
279 {
280 di->kind = DomainInfo::Master;
281 return true;
282 }
283
284 return false;
285 }