1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * Drizzle Client & Protocol Library
4 *
5 * Copyright (C) 2008-2013 Drizzle Developer Group
6 * Copyright (C) 2008 Eric Day (eday@oddments.org)
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are
11 * met:
12 *
13 * * Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * * Redistributions in binary form must reproduce the above
17 * copyright notice, this list of conditions and the following disclaimer
18 * in the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * * The names of its contributors may not be used to endorse or
22 * promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 */
38
39 /**
40 * @file
41 * @brief Drizzle Definitions
42 */
43
44 #include "config.h"
45 #include "libdrizzle/common.h"
46
47 #include <cerrno>
48 #include <pthread.h>
49
50 /**
51 * @addtogroup drizzle_static Static Drizzle Declarations
52 * @ingroup drizzle
53 * @{
54 */
55
56 /**
57 * Names of the verbose levels provided.
58 */
59 static const char *_verbose_name[DRIZZLE_VERBOSE_MAX]=
60 {
61 "NEVER",
62 "CRITICAL",
63 "ERROR",
64 "INFO",
65 "DEBUG",
66 };
67
68 /** @} */
69
70 /*
71 * Common Definitions
72 */
73
74 static pthread_once_t ssl_startup_once= PTHREAD_ONCE_INIT;
75
drizzle_library_deinit(void)76 static void drizzle_library_deinit(void)
77 {
78 #if defined(_WIN32)
79 /* if it is MS windows, invoke WSACleanup() at the end*/
80 WSACleanup();
81 #endif
82 }
83
ssl_startup_function(void)84 static void ssl_startup_function(void)
85 {
86 #ifdef USE_OPENSSL
87 SSL_library_init();
88 ERR_load_crypto_strings();
89 SSL_load_error_strings();
90 OpenSSL_add_all_algorithms();
91 #endif
92 #if defined(_WIN32)
93 /* if it is MS windows, invoke WSAStartup */
94 WSADATA wsaData;
95 if ( WSAStartup( MAKEWORD(2,2), &wsaData ) != 0 )
96 {
97 fprintf(stderr, "Error at WSAStartup()\n");
98 }
99 #endif
100
101 (void)atexit(drizzle_library_deinit);
102 }
103
drizzle_library_init(drizzle_st * connection)104 bool drizzle_library_init(drizzle_st* connection)
105 {
106 int pthread_error;
107 if ((pthread_error= pthread_once(&ssl_startup_once, ssl_startup_function)) == -1)
108 {
109 drizzle_set_error(connection, "pthread_once", "error:%s", strerror(errno));
110 return false;
111 }
112
113 return true;
114 }
115
drizzle_version(void)116 const char *drizzle_version(void)
117 {
118 return LIBDRIZZLE_VERSION_STRING;
119 }
120
drizzle_bugreport(void)121 const char *drizzle_bugreport(void)
122 {
123 return PACKAGE_BUGREPORT;
124 }
125
drizzle_verbose_name(drizzle_verbose_t verbose)126 const char *drizzle_verbose_name(drizzle_verbose_t verbose)
127 {
128 if (verbose >= DRIZZLE_VERBOSE_MAX)
129 {
130 return "UNKNOWN";
131 }
132
133 return _verbose_name[verbose];
134 }
135
drizzle_timeout(const drizzle_st * con)136 int drizzle_timeout(const drizzle_st *con)
137 {
138 if (con == NULL)
139 {
140 return -1;
141 }
142
143 return con->timeout;
144 }
145
drizzle_set_timeout(drizzle_st * con,int timeout)146 void drizzle_set_timeout(drizzle_st *con, int timeout)
147 {
148 if (con == NULL)
149 {
150 return;
151 }
152
153 con->timeout= timeout;
154 }
155
drizzle_verbose(const drizzle_st * con)156 drizzle_verbose_t drizzle_verbose(const drizzle_st *con)
157 {
158 if (con == NULL)
159 {
160 return DRIZZLE_VERBOSE_NEVER;
161 }
162
163 return con->verbose;
164 }
165
drizzle_set_verbose(drizzle_st * con,drizzle_verbose_t verbose)166 void drizzle_set_verbose(drizzle_st *con, drizzle_verbose_t verbose)
167 {
168 if (con == NULL)
169 {
170 return;
171 }
172
173 con->verbose= verbose;
174 }
175
drizzle_set_log_fn(drizzle_st * con,drizzle_log_fn * function,void * context)176 void drizzle_set_log_fn(drizzle_st *con, drizzle_log_fn *function, void *context)
177 {
178 if (con == NULL)
179 {
180 return;
181 }
182
183 con->log_fn= function;
184 con->log_context= context;
185 }
186
drizzle_clone(drizzle_st * drizzle,const drizzle_st * from)187 drizzle_st *drizzle_clone(drizzle_st *drizzle, const drizzle_st *from)
188 {
189 drizzle= new (std::nothrow) drizzle_st;
190 if (drizzle == NULL)
191 {
192 return NULL;
193 }
194
195 drizzle->capabilities= from->capabilities;
196 drizzle->options= from->options;
197
198 drizzle->backlog= from->backlog;
199 strcpy(drizzle->db, from->db);
200 strcpy(drizzle->password, from->password);
201 strcpy(drizzle->user, from->user);
202
203 switch (from->socket_type)
204 {
205 case DRIZZLE_CON_SOCKET_TCP:
206 drizzle_set_tcp(drizzle, from->socket.tcp.host, from->socket.tcp.port);
207 break;
208
209 case DRIZZLE_CON_SOCKET_UDS:
210 drizzle_set_uds(drizzle, from->socket.uds.path_buffer);
211 break;
212
213 default:
214 break;
215 }
216
217 return drizzle;
218 }
219
drizzle_free(drizzle_st * con)220 void drizzle_free(drizzle_st *con)
221 {
222 if (con == NULL)
223 {
224 return;
225 }
226
227 if (con->context != NULL && con->context_free_fn != NULL)
228 {
229 con->context_free_fn(con, con->context);
230 }
231
232 drizzle_result_free_all(con);
233
234 if (con->fd != INVALID_SOCKET)
235 {
236 drizzle_close(con);
237 }
238
239 drizzle_reset_addrinfo(con);
240
241 #ifdef USE_OPENSSL
242 if (con->ssl)
243 SSL_free(con->ssl);
244
245 if (con->ssl_context)
246 SSL_CTX_free(con->ssl_context);
247 #endif
248
249 if (con->binlog != NULL)
250 {
251 drizzle_binlog_free(con->binlog);
252 }
253
254 free(con->buffer);
255 delete con;
256 }
257
drizzle_wait(drizzle_st * con)258 drizzle_return_t drizzle_wait(drizzle_st *con)
259 {
260 if (con == NULL)
261 {
262 return DRIZZLE_RETURN_INVALID_ARGUMENT;
263 }
264
265 if (!con->events == 0)
266 {
267 con->pfds[0].fd= con->fd;
268 con->pfds[0].events= con->events;
269 con->pfds[0].revents= 0;
270 }
271 else
272 {
273 drizzle_set_error(con, __func__, "no active file descriptors");
274 return DRIZZLE_RETURN_NO_ACTIVE_CONNECTIONS;
275 }
276
277 int ret;
278 while (1)
279 {
280 drizzle_log_debug(con, "poll timeout=%d", con->timeout);
281
282 ret= poll(con->pfds, 1, con->timeout);
283
284 drizzle_log_debug(con, "poll return=%d errno=%d", ret, errno);
285
286 if (ret == -1)
287 {
288 if (errno == EINTR)
289 {
290 continue;
291 }
292
293 drizzle_set_error(con, "drizzle_wait", "poll:%d", errno);
294 con->last_errno= errno;
295 return DRIZZLE_RETURN_ERRNO;
296 }
297
298 break;
299 }
300
301 if (ret == 0)
302 {
303 drizzle_set_error(con, "drizzle_wait", "timeout reached");
304 return DRIZZLE_RETURN_TIMEOUT;
305 }
306
307 return drizzle_set_revents(con, con->pfds[0].revents);
308 }
309
drizzle_ready(drizzle_st * con)310 drizzle_st *drizzle_ready(drizzle_st *con)
311 {
312 /* We can't keep state between calls since connections may be removed during
313 processing. If this list ever gets big, we may want something faster. */
314
315 if (con->state.io_ready)
316 {
317 con->state.io_ready= false;
318 return con;
319 }
320
321 return NULL;
322 }
323
324 /*
325 * Client Definitions
326 */
327
drizzle_create(const char * host,in_port_t port,const char * user,const char * password,const char * db,drizzle_options_st * options)328 drizzle_st *drizzle_create(const char *host, in_port_t port,
329 const char *user, const char *password,
330 const char *db,
331 drizzle_options_st *options)
332 {
333 drizzle_st *con= new (std::nothrow) drizzle_st;
334 if (con == NULL)
335 {
336 return NULL;
337 }
338
339 if (drizzle_library_init(con) == false)
340 {
341 delete con;
342 return NULL;
343 }
344
345 if (host and host[0] == '/')
346 {
347 drizzle_set_uds(con, host);
348 }
349 else
350 {
351 drizzle_set_tcp(con, host, port);
352 }
353 drizzle_set_auth(con, user, password);
354 drizzle_set_db(con, db);
355 if (options != NULL)
356 {
357 con->options= *options;
358 }
359
360 return con;
361 }
362
363 /*
364 * Local Definitions
365 */
366
drizzle_set_error(drizzle_st * con,const char * function,const char * format,...)367 void drizzle_set_error(drizzle_st *con, const char *function,
368 const char *format, ...)
369 {
370 if (con == NULL)
371 {
372 return;
373 }
374
375 size_t size;
376 int written;
377 char log_buffer[DRIZZLE_MAX_ERROR_SIZE];
378 va_list args;
379
380 size= strlen(function);
381 char *ptr= (char *)memcpy(log_buffer, function, size);
382 ptr+= size;
383 ptr[0]= ':';
384 size++;
385 ptr++;
386
387 va_start(args, format);
388 written= vsnprintf(ptr, DRIZZLE_MAX_ERROR_SIZE - size, format, args);
389 va_end(args);
390
391 if (written < 0)
392 {
393 size= DRIZZLE_MAX_ERROR_SIZE;
394 }
395 else
396 {
397 size+= written;
398 }
399
400 if (size >= DRIZZLE_MAX_ERROR_SIZE)
401 {
402 size= DRIZZLE_MAX_ERROR_SIZE - 1;
403 }
404 log_buffer[size]= 0;
405
406 if (con->log_fn == NULL)
407 {
408 memcpy(con->last_error, log_buffer, size + 1);
409 }
410 else
411 {
412 con->log_fn(log_buffer, DRIZZLE_VERBOSE_ERROR, con->log_context);
413 }
414 }
415
drizzle_log(drizzle_st * con,drizzle_verbose_t verbose,const char * format,va_list args)416 void drizzle_log(drizzle_st *con, drizzle_verbose_t verbose,
417 const char *format, va_list args)
418 {
419 if (con == NULL)
420 {
421 return;
422 }
423
424 char log_buffer[DRIZZLE_MAX_ERROR_SIZE];
425
426 if (con->log_fn == NULL)
427 {
428 printf("%5s: ", drizzle_verbose_name(verbose));
429 vprintf(format, args);
430 printf("\n");
431 }
432 else
433 {
434 vsnprintf(log_buffer, DRIZZLE_MAX_ERROR_SIZE, format, args);
435 log_buffer[DRIZZLE_MAX_ERROR_SIZE-1]= 0;
436 con->log_fn(log_buffer, verbose, con->log_context);
437 }
438 }
439