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