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