libdrizzle Developer Documentation

libdrizzle/drizzle.c
Go to the documentation of this file.
00001 /*
00002  * Drizzle Client & Protocol Library
00003  *
00004  * Copyright (C) 2008 Eric Day (eday@oddments.org)
00005  * All rights reserved.
00006  *
00007  * Use and distribution licensed under the BSD license.  See
00008  * the COPYING file in this directory for full text.
00009  */
00010 
00016 #include "common.h"
00017 
00027 static const char *_verbose_name[DRIZZLE_VERBOSE_MAX]=
00028 {
00029   "NEVER",
00030   "FATAL",
00031   "ERROR",
00032   "INFO",
00033   "DEBUG",
00034   "CRAZY"
00035 };
00036 
00039 /*
00040  * Common Definitions
00041  */
00042 
00043 const char *drizzle_version(void)
00044 {
00045   return PACKAGE_VERSION;
00046 }
00047 
00048 const char *drizzle_bugreport(void)
00049 {
00050   return PACKAGE_BUGREPORT;
00051 }
00052 
00053 const char *drizzle_verbose_name(drizzle_verbose_t verbose)
00054 {
00055   if (verbose >= DRIZZLE_VERBOSE_MAX)
00056     return "UNKNOWN";
00057 
00058   return _verbose_name[verbose];
00059 }
00060 
00061 drizzle_st *drizzle_create(drizzle_st *drizzle)
00062 {
00063   if (drizzle == NULL)
00064   {
00065     drizzle= malloc(sizeof(drizzle_st));
00066     if (drizzle == NULL)
00067       return NULL;
00068 
00069     drizzle->options= DRIZZLE_ALLOCATED;
00070   }
00071   else
00072     drizzle->options= DRIZZLE_NONE;
00073 
00074   /* @todo remove this default free flag with new API. */
00075   drizzle->options|= DRIZZLE_FREE_OBJECTS;
00076   drizzle->error_code= 0;
00077   /* drizzle->options set above */
00078   drizzle->verbose= DRIZZLE_VERBOSE_NEVER;
00079   drizzle->con_count= 0;
00080   drizzle->pfds_size= 0;
00081   drizzle->query_count= 0;
00082   drizzle->query_new= 0;
00083   drizzle->query_running= 0;
00084   drizzle->last_errno= 0;
00085   drizzle->timeout= -1;
00086   drizzle->con_list= NULL;
00087   drizzle->context= NULL;
00088   drizzle->context_free_fn= NULL;
00089   drizzle->event_watch_fn= NULL;
00090   drizzle->event_watch_context= NULL;
00091   drizzle->log_fn= NULL;
00092   drizzle->log_context= NULL;
00093   drizzle->pfds= NULL;
00094   drizzle->query_list= NULL;
00095   drizzle->sqlstate[0]= 0;
00096   drizzle->last_error[0]= 0;
00097 
00098   return drizzle;
00099 }
00100 
00101 drizzle_st *drizzle_clone(drizzle_st *drizzle, const drizzle_st *from)
00102 {
00103   drizzle_con_st *con;
00104 
00105   drizzle= drizzle_create(drizzle);
00106   if (drizzle == NULL)
00107     return NULL;
00108 
00109   drizzle->options|= (from->options & (drizzle_options_t)~DRIZZLE_ALLOCATED);
00110 
00111   for (con= from->con_list; con != NULL; con= con->next)
00112   {
00113     if (drizzle_con_clone(drizzle, NULL, con) == NULL)
00114     {
00115       drizzle_free(drizzle);
00116       return NULL;
00117     }
00118   }
00119 
00120   return drizzle;
00121 }
00122 
00123 void drizzle_free(drizzle_st *drizzle)
00124 {
00125   if (drizzle->context != NULL && drizzle->context_free_fn != NULL)
00126     drizzle->context_free_fn(drizzle, drizzle->context);
00127 
00128   if (drizzle->options & DRIZZLE_FREE_OBJECTS)
00129   {
00130     drizzle_con_free_all(drizzle);
00131     drizzle_query_free_all(drizzle);
00132   }
00133   else if (drizzle->options & DRIZZLE_ASSERT_DANGLING)
00134   {
00135     assert(drizzle->con_list == NULL);
00136     assert(drizzle->con_list == NULL);
00137   }
00138 
00139   if (drizzle->pfds != NULL)
00140     free(drizzle->pfds);
00141 
00142   if (drizzle->options & DRIZZLE_ALLOCATED)
00143     free(drizzle);
00144 }
00145 
00146 const char *drizzle_error(const drizzle_st *drizzle)
00147 {
00148   return (const char *)drizzle->last_error;
00149 }
00150 
00151 int drizzle_errno(const drizzle_st *drizzle)
00152 {
00153   return drizzle->last_errno;
00154 }
00155 
00156 uint16_t drizzle_error_code(const drizzle_st *drizzle)
00157 {
00158   return drizzle->error_code;
00159 }
00160 
00161 const char *drizzle_sqlstate(const drizzle_st *drizzle)
00162 {
00163   return drizzle->sqlstate;
00164 }
00165 
00166 drizzle_options_t drizzle_options(const drizzle_st *drizzle)
00167 {
00168   return drizzle->options;
00169 }
00170 
00171 void drizzle_set_options(drizzle_st *drizzle, drizzle_options_t options)
00172 {
00173   drizzle->options= options;
00174 }
00175 
00176 void drizzle_add_options(drizzle_st *drizzle, drizzle_options_t options)
00177 {
00178   drizzle->options|= options;
00179 }
00180 
00181 void drizzle_remove_options(drizzle_st *drizzle, drizzle_options_t options)
00182 {
00183   drizzle->options&= ~options;
00184 }
00185 
00186 void *drizzle_context(const drizzle_st *drizzle)
00187 {
00188   return drizzle->context;
00189 }
00190 
00191 void drizzle_set_context(drizzle_st *drizzle, void *context)
00192 {
00193   drizzle->context= context;
00194 }
00195 
00196 void drizzle_set_context_free_fn(drizzle_st *drizzle,
00197                                  drizzle_context_free_fn *function)
00198 {
00199   drizzle->context_free_fn= function;
00200 }
00201 
00202 int drizzle_timeout(const drizzle_st *drizzle)
00203 {
00204   return drizzle->timeout;
00205 }
00206 
00207 void drizzle_set_timeout(drizzle_st *drizzle, int timeout)
00208 {
00209   drizzle->timeout= timeout;
00210 }
00211 
00212 drizzle_verbose_t drizzle_verbose(const drizzle_st *drizzle)
00213 {
00214   return drizzle->verbose;
00215 }
00216 
00217 void drizzle_set_verbose(drizzle_st *drizzle, drizzle_verbose_t verbose)
00218 {
00219   drizzle->verbose= verbose;
00220 }
00221 
00222 void drizzle_set_log_fn(drizzle_st *drizzle, drizzle_log_fn *function,
00223                         void *context)
00224 {
00225   drizzle->log_fn= function;
00226   drizzle->log_context= context;
00227 }
00228 
00229 void drizzle_set_event_watch_fn(drizzle_st *drizzle,
00230                                 drizzle_event_watch_fn *function,
00231                                 void *context)
00232 {
00233   drizzle->event_watch_fn= function;
00234   drizzle->event_watch_context= context;
00235 }
00236 
00237 drizzle_con_st *drizzle_con_create(drizzle_st *drizzle, drizzle_con_st *con)
00238 {
00239   if (con == NULL)
00240   {
00241     con= malloc(sizeof(drizzle_con_st));
00242     if (con == NULL)
00243     {
00244       if (drizzle != NULL)
00245         drizzle_set_error(drizzle, "drizzle_con_create", "malloc");
00246       return NULL;
00247     }
00248 
00249     con->options= DRIZZLE_CON_ALLOCATED;
00250   }
00251   else
00252     con->options= 0;
00253 
00254   if (drizzle->con_list != NULL)
00255     drizzle->con_list->prev= con;
00256   con->next= drizzle->con_list;
00257   con->prev= NULL;
00258   drizzle->con_list= con;
00259   drizzle->con_count++;
00260 
00261   con->packet_number= 0;
00262   con->protocol_version= 0;
00263   con->state_current= 0;
00264   con->events= 0;
00265   con->revents= 0;
00266   con->capabilities= DRIZZLE_CAPABILITIES_NONE;
00267   con->charset= 0;
00268   con->command= 0;
00269   con->options|= DRIZZLE_CON_MYSQL;
00270   con->socket_type= DRIZZLE_CON_SOCKET_TCP;
00271   con->status= DRIZZLE_CON_STATUS_NONE;
00272   con->max_packet_size= DRIZZLE_MAX_PACKET_SIZE;
00273   con->result_count= 0;
00274   con->thread_id= 0;
00275   con->backlog= DRIZZLE_DEFAULT_BACKLOG;
00276   con->fd= -1;
00277   con->buffer_size= 0;
00278   con->command_offset= 0;
00279   con->command_size= 0;
00280   con->command_total= 0;
00281   con->packet_size= 0;
00282   con->addrinfo_next= NULL;
00283   con->buffer_ptr= con->buffer;
00284   con->command_buffer= NULL;
00285   con->command_data= NULL;
00286   con->context= NULL;
00287   con->context_free_fn= NULL;
00288   con->drizzle= drizzle;
00289   /* con->next set above */
00290   /* con->prev set above */
00291   con->query= NULL;
00292   /* con->result doesn't need to be set */
00293   con->result_list= NULL;
00294   con->scramble= NULL;
00295   con->socket.tcp.addrinfo= NULL;
00296   con->socket.tcp.host= NULL;
00297   con->socket.tcp.port= 0;
00298   /* con->buffer doesn't need to be set */
00299   con->db[0]= 0;
00300   con->password[0]= 0;
00301   /* con->scramble_buffer doesn't need to be set */
00302   con->server_version[0]= 0;
00303   /* con->state_stack doesn't need to be set */
00304   con->user[0]= 0;
00305 
00306   return con;
00307 }
00308 
00309 drizzle_con_st *drizzle_con_clone(drizzle_st *drizzle, drizzle_con_st *con,
00310                                   const drizzle_con_st *from)
00311 {
00312   con= drizzle_con_create(drizzle, con);
00313   if (con == NULL)
00314     return NULL;
00315 
00316   /* Clear "operational" options such as IO status. */
00317   con->options|= (from->options & (drizzle_con_options_t)~(
00318                   DRIZZLE_CON_ALLOCATED|DRIZZLE_CON_READY|
00319                   DRIZZLE_CON_NO_RESULT_READ|DRIZZLE_CON_IO_READY|
00320                   DRIZZLE_CON_LISTEN));
00321   con->backlog= from->backlog;
00322   strcpy(con->db, from->db);
00323   strcpy(con->password, from->password);
00324   strcpy(con->user, from->user);
00325 
00326   switch (from->socket_type)
00327   {
00328   case DRIZZLE_CON_SOCKET_TCP:
00329     drizzle_con_set_tcp(con, from->socket.tcp.host, from->socket.tcp.port);
00330     break;
00331 
00332   case DRIZZLE_CON_SOCKET_UDS:
00333     drizzle_con_set_uds(con, from->socket.uds.sockaddr.sun_path);
00334     break;
00335 
00336   default:
00337     break;
00338   }
00339 
00340   return con;
00341 }
00342 
00343 void drizzle_con_free(drizzle_con_st *con)
00344 {
00345   if (con->context != NULL && con->context_free_fn != NULL)
00346     con->context_free_fn(con, con->context);
00347 
00348   if (con->drizzle->options & DRIZZLE_FREE_OBJECTS)
00349     drizzle_result_free_all(con);
00350   else if (con->drizzle->options & DRIZZLE_ASSERT_DANGLING)
00351     assert(con->result_list == NULL);
00352 
00353   if (con->fd != -1)
00354     drizzle_con_close(con);
00355 
00356   drizzle_con_reset_addrinfo(con);
00357 
00358   if (con->drizzle->con_list == con)
00359     con->drizzle->con_list= con->next;
00360   if (con->prev != NULL)
00361     con->prev->next= con->next;
00362   if (con->next != NULL)
00363     con->next->prev= con->prev;
00364   con->drizzle->con_count--;
00365 
00366   if (con->options & DRIZZLE_CON_ALLOCATED)
00367     free(con);
00368 }
00369 
00370 void drizzle_con_free_all(drizzle_st *drizzle)
00371 {
00372   while (drizzle->con_list != NULL)
00373     drizzle_con_free(drizzle->con_list);
00374 }
00375 
00376 drizzle_return_t drizzle_con_wait(drizzle_st *drizzle)
00377 {
00378   drizzle_con_st *con;
00379   struct pollfd *pfds;
00380   uint32_t x;
00381   int ret;
00382   drizzle_return_t dret;
00383 
00384   if (drizzle->pfds_size < drizzle->con_count)
00385   {
00386     pfds= realloc(drizzle->pfds, drizzle->con_count * sizeof(struct pollfd));
00387     if (pfds == NULL)
00388     {
00389       drizzle_set_error(drizzle, "drizzle_con_wait", "realloc");
00390       return DRIZZLE_RETURN_MEMORY;
00391     }
00392 
00393     drizzle->pfds= pfds;
00394     drizzle->pfds_size= drizzle->con_count;
00395   }
00396   else
00397     pfds= drizzle->pfds;
00398 
00399   x= 0;
00400   for (con= drizzle->con_list; con != NULL; con= con->next)
00401   {
00402     if (con->events == 0)
00403       continue;
00404 
00405     pfds[x].fd= con->fd;
00406     pfds[x].events= con->events;
00407     pfds[x].revents= 0;
00408     x++;
00409   }
00410 
00411   if (x == 0)
00412   {
00413     drizzle_set_error(drizzle, "drizzle_con_wait",
00414                       "no active file descriptors");
00415     return DRIZZLE_RETURN_NO_ACTIVE_CONNECTIONS;
00416   }
00417 
00418   while (1)
00419   {
00420     drizzle_log_crazy(drizzle, "poll count=%d timeout=%d", x,
00421                       drizzle->timeout);
00422 
00423     ret= poll(pfds, x, drizzle->timeout);
00424 
00425     drizzle_log_crazy(drizzle, "poll return=%d errno=%d", ret, errno);
00426 
00427     if (ret == -1)
00428     {
00429       if (errno == EINTR)
00430         continue;
00431 
00432       drizzle_set_error(drizzle, "drizzle_con_wait", "poll:%d", errno);
00433       drizzle->last_errno= errno;
00434       return DRIZZLE_RETURN_ERRNO;
00435     }
00436 
00437     break;
00438   }
00439 
00440   if (ret == 0)
00441   {
00442     drizzle_set_error(drizzle, "drizzle_con_wait", "timeout reached");
00443     return DRIZZLE_RETURN_TIMEOUT;
00444   }
00445 
00446   x= 0;
00447   for (con= drizzle->con_list; con != NULL; con= con->next)
00448   {
00449     if (con->events == 0)
00450       continue;
00451 
00452     dret= drizzle_con_set_revents(con, pfds[x].revents);
00453     if (dret != DRIZZLE_RETURN_OK)
00454       return dret;
00455 
00456     x++;
00457   }
00458 
00459   return DRIZZLE_RETURN_OK;
00460 }
00461 
00462 drizzle_con_st *drizzle_con_ready(drizzle_st *drizzle)
00463 {
00464   drizzle_con_st *con;
00465 
00466   /* We can't keep state between calls since connections may be removed during
00467      processing. If this list ever gets big, we may want something faster. */
00468 
00469   for (con= drizzle->con_list; con != NULL; con= con->next)
00470   {
00471     if (con->options & DRIZZLE_CON_IO_READY)
00472     {
00473       con->options&= (drizzle_con_options_t)~DRIZZLE_CON_IO_READY;
00474       return con;
00475     }
00476   }
00477 
00478   return NULL;
00479 }
00480 
00481 drizzle_con_st *drizzle_con_ready_listen(drizzle_st *drizzle)
00482 {
00483   drizzle_con_st *con;
00484 
00485   /* We can't keep state between calls since connections may be removed during
00486      processing. If this list ever gets big, we may want something faster. */
00487 
00488   for (con= drizzle->con_list; con != NULL; con= con->next)
00489   {
00490     if ((con->options & (DRIZZLE_CON_IO_READY | DRIZZLE_CON_LISTEN)) ==
00491         (DRIZZLE_CON_IO_READY | DRIZZLE_CON_LISTEN))
00492     {
00493       con->options&= (drizzle_con_options_t)~DRIZZLE_CON_IO_READY;
00494       return con;
00495     }
00496   }
00497 
00498   return NULL;
00499 }
00500 
00501 /*
00502  * Client Definitions
00503  */
00504 
00505 drizzle_con_st *drizzle_con_add_tcp(drizzle_st *drizzle, drizzle_con_st *con,
00506                                     const char *host, in_port_t port,
00507                                     const char *user, const char *password,
00508                                     const char *db,
00509                                     drizzle_con_options_t options)
00510 {
00511   con= drizzle_con_create(drizzle, con);
00512   if (con == NULL)
00513     return NULL;
00514 
00515   drizzle_con_set_tcp(con, host, port);
00516   drizzle_con_set_auth(con, user, password);
00517   drizzle_con_set_db(con, db);
00518   drizzle_con_add_options(con, options);
00519 
00520   return con;
00521 }
00522 
00523 drizzle_con_st *drizzle_con_add_uds(drizzle_st *drizzle, drizzle_con_st *con,
00524                                     const char *uds, const char *user,
00525                                     const char *password, const char *db,
00526                                     drizzle_con_options_t options)
00527 {
00528   con= drizzle_con_create(drizzle, con);
00529   if (con == NULL)
00530     return NULL;
00531 
00532   drizzle_con_set_uds(con, uds);
00533   drizzle_con_set_auth(con, user, password);
00534   drizzle_con_set_db(con, db);
00535   drizzle_con_add_options(con, options);
00536 
00537   return con;
00538 }
00539 
00540 /*
00541  * Server Definitions
00542  */
00543 
00544 drizzle_con_st *drizzle_con_add_tcp_listen(drizzle_st *drizzle,
00545                                            drizzle_con_st *con,
00546                                            const char *host, in_port_t port,
00547                                            int backlog,
00548                                            drizzle_con_options_t options)
00549 {
00550   con= drizzle_con_create(drizzle, con);
00551   if (con == NULL)
00552     return NULL;
00553 
00554   drizzle_con_set_tcp(con, host, port);
00555   drizzle_con_set_backlog(con, backlog);
00556   drizzle_con_add_options(con, DRIZZLE_CON_LISTEN | options);
00557 
00558   return con;
00559 }
00560 
00561 drizzle_con_st *drizzle_con_add_uds_listen(drizzle_st *drizzle,
00562                                            drizzle_con_st *con,
00563                                            const char *uds, int backlog,
00564                                            drizzle_con_options_t options)
00565 {
00566   con= drizzle_con_create(drizzle, con);
00567   if (con == NULL)
00568     return NULL;
00569 
00570   drizzle_con_set_uds(con, uds);
00571   drizzle_con_set_backlog(con, backlog);
00572   drizzle_con_add_options(con, DRIZZLE_CON_LISTEN | options);
00573 
00574   return con;
00575 }
00576 
00577 drizzle_con_st *drizzle_con_accept(drizzle_st *drizzle, drizzle_con_st *con,
00578                                    drizzle_return_t *ret_ptr)
00579 {
00580   drizzle_con_st *ready;
00581   int fd;
00582 
00583   while (1)
00584   {
00585     if ((ready= drizzle_con_ready_listen(drizzle)) != NULL)
00586     {
00587       fd= accept(ready->fd, NULL, NULL);
00588 
00589       con= drizzle_con_create(drizzle, con);
00590       if (con == NULL)
00591       {
00592         (void)close(fd);
00593         *ret_ptr= DRIZZLE_RETURN_MEMORY;
00594         return NULL;
00595       }
00596 
00597       *ret_ptr= drizzle_con_set_fd(con, fd);
00598       if (*ret_ptr != DRIZZLE_RETURN_OK)
00599       {
00600         (void)close(fd);
00601         return NULL;
00602       }
00603 
00604       if (ready->options & DRIZZLE_CON_MYSQL)
00605         drizzle_con_add_options(con, DRIZZLE_CON_MYSQL);
00606 
00607       *ret_ptr= DRIZZLE_RETURN_OK;
00608       return con;
00609     }
00610 
00611     if (drizzle->options & DRIZZLE_NON_BLOCKING)
00612     {
00613       *ret_ptr= DRIZZLE_RETURN_IO_WAIT;
00614       return NULL;
00615     }
00616 
00617     for (ready= drizzle->con_list; ready != NULL; ready= ready->next)
00618     {
00619       if (ready->options & DRIZZLE_CON_LISTEN)
00620         drizzle_con_set_events(ready, POLLIN);
00621     }
00622 
00623     *ret_ptr= drizzle_con_wait(drizzle);
00624     if (*ret_ptr != DRIZZLE_RETURN_OK)
00625       return NULL;
00626   }
00627 }
00628 
00629 /*
00630  * Local Definitions
00631  */
00632 
00633 void drizzle_set_error(drizzle_st *drizzle, const char *function,
00634                        const char *format, ...)
00635 {
00636   size_t size;
00637   char *ptr;
00638   char log_buffer[DRIZZLE_MAX_ERROR_SIZE];
00639   va_list args;
00640 
00641   size= strlen(function);
00642   ptr= memcpy(log_buffer, function, size);
00643   ptr+= size;
00644   ptr[0]= ':';
00645   size++;
00646   ptr++;
00647 
00648   va_start(args, format);
00649   size+= (size_t)vsnprintf(ptr, DRIZZLE_MAX_ERROR_SIZE - size, format, args);
00650   va_end(args);
00651 
00652   if (drizzle->log_fn == NULL)
00653   {
00654     if (size >= DRIZZLE_MAX_ERROR_SIZE)
00655       size= DRIZZLE_MAX_ERROR_SIZE - 1;
00656 
00657     memcpy(drizzle->last_error, log_buffer, size + 1);
00658   }
00659   else
00660     drizzle->log_fn(log_buffer, DRIZZLE_VERBOSE_ERROR, drizzle->log_context);
00661 }
00662 
00663 void drizzle_log(drizzle_st *drizzle, drizzle_verbose_t verbose,
00664                  const char *format, va_list args)
00665 {
00666   char log_buffer[DRIZZLE_MAX_ERROR_SIZE];
00667 
00668   if (drizzle->log_fn == NULL)
00669   {
00670     printf("%5s: ", drizzle_verbose_name(verbose));
00671     vprintf(format, args);
00672     printf("\n");
00673   }
00674   else
00675   {
00676     vsnprintf(log_buffer, DRIZZLE_MAX_ERROR_SIZE, format, args);
00677     drizzle->log_fn(log_buffer, verbose, drizzle->log_context);
00678   }
00679 }