libdrizzle Developer Documentation

drizzle.c
Go to the documentation of this file.
1 /*
2  * Drizzle Client & Protocol Library
3  *
4  * Copyright (C) 2008 Eric Day (eday@oddments.org)
5  * All rights reserved.
6  *
7  * Use and distribution licensed under the BSD license. See
8  * the COPYING file in this directory for full text.
9  */
10 
16 #include "common.h"
17 
27 static const char *_verbose_name[DRIZZLE_VERBOSE_MAX]=
28 {
29  "NEVER",
30  "FATAL",
31  "ERROR",
32  "INFO",
33  "DEBUG",
34  "CRAZY"
35 };
36 
39 /*
40  * Common Definitions
41  */
42 
43 const char *drizzle_version(void)
44 {
45  return PACKAGE_VERSION;
46 }
47 
48 const char *drizzle_bugreport(void)
49 {
50  return PACKAGE_BUGREPORT;
51 }
52 
54 {
55  if (verbose >= DRIZZLE_VERBOSE_MAX)
56  return "UNKNOWN";
57 
58  return _verbose_name[verbose];
59 }
60 
62 {
63  if (drizzle == NULL)
64  {
65  drizzle= malloc(sizeof(drizzle_st));
66  if (drizzle == NULL)
67  return NULL;
68 
69  drizzle->options= DRIZZLE_ALLOCATED;
70  }
71  else
72  drizzle->options= DRIZZLE_NONE;
73 
74  /* @todo remove this default free flag with new API. */
75  drizzle->options|= DRIZZLE_FREE_OBJECTS;
76  drizzle->error_code= 0;
77  /* drizzle->options set above */
79  drizzle->con_count= 0;
80  drizzle->pfds_size= 0;
81  drizzle->query_count= 0;
82  drizzle->query_new= 0;
83  drizzle->query_running= 0;
84  drizzle->last_errno= 0;
85  drizzle->timeout= -1;
86  drizzle->con_list= NULL;
87  drizzle->context= NULL;
88  drizzle->context_free_fn= NULL;
89  drizzle->event_watch_fn= NULL;
90  drizzle->event_watch_context= NULL;
91  drizzle->log_fn= NULL;
92  drizzle->log_context= NULL;
93  drizzle->pfds= NULL;
94  drizzle->query_list= NULL;
95  drizzle->sqlstate[0]= 0;
96  drizzle->last_error[0]= 0;
97 
98  return drizzle;
99 }
100 
102 {
103  drizzle_con_st *con;
104 
105  drizzle= drizzle_create(drizzle);
106  if (drizzle == NULL)
107  return NULL;
108 
109  drizzle->options|= (from->options & (drizzle_options_t)~DRIZZLE_ALLOCATED);
110 
111  for (con= from->con_list; con != NULL; con= con->next)
112  {
113  if (drizzle_con_clone(drizzle, NULL, con) == NULL)
114  {
115  drizzle_free(drizzle);
116  return NULL;
117  }
118  }
119 
120  return drizzle;
121 }
122 
123 void drizzle_free(drizzle_st *drizzle)
124 {
125  if (drizzle->context != NULL && drizzle->context_free_fn != NULL)
126  drizzle->context_free_fn(drizzle, drizzle->context);
127 
128  if (drizzle->options & DRIZZLE_FREE_OBJECTS)
129  {
130  drizzle_con_free_all(drizzle);
131  drizzle_query_free_all(drizzle);
132  }
133  else if (drizzle->options & DRIZZLE_ASSERT_DANGLING)
134  {
135  assert(drizzle->con_list == NULL);
136  assert(drizzle->con_list == NULL);
137  }
138 
139  if (drizzle->pfds != NULL)
140  free(drizzle->pfds);
141 
142  if (drizzle->options & DRIZZLE_ALLOCATED)
143  free(drizzle);
144 }
145 
146 const char *drizzle_error(const drizzle_st *drizzle)
147 {
148  return (const char *)drizzle->last_error;
149 }
150 
151 int drizzle_errno(const drizzle_st *drizzle)
152 {
153  return drizzle->last_errno;
154 }
155 
156 uint16_t drizzle_error_code(const drizzle_st *drizzle)
157 {
158  return drizzle->error_code;
159 }
160 
161 const char *drizzle_sqlstate(const drizzle_st *drizzle)
162 {
163  return drizzle->sqlstate;
164 }
165 
167 {
168  return drizzle->options;
169 }
170 
172 {
173  drizzle->options= options;
174 }
175 
177 {
178  drizzle->options|= options;
179 }
180 
182 {
183  drizzle->options&= ~options;
184 }
185 
186 void *drizzle_context(const drizzle_st *drizzle)
187 {
188  return drizzle->context;
189 }
190 
191 void drizzle_set_context(drizzle_st *drizzle, void *context)
192 {
193  drizzle->context= context;
194 }
195 
197  drizzle_context_free_fn *function)
198 {
199  drizzle->context_free_fn= function;
200 }
201 
202 int drizzle_timeout(const drizzle_st *drizzle)
203 {
204  return drizzle->timeout;
205 }
206 
207 void drizzle_set_timeout(drizzle_st *drizzle, int timeout)
208 {
209  drizzle->timeout= timeout;
210 }
211 
213 {
214  return drizzle->verbose;
215 }
216 
218 {
219  drizzle->verbose= verbose;
220 }
221 
223  void *context)
224 {
225  drizzle->log_fn= function;
226  drizzle->log_context= context;
227 }
228 
230  drizzle_event_watch_fn *function,
231  void *context)
232 {
233  drizzle->event_watch_fn= function;
234  drizzle->event_watch_context= context;
235 }
236 
238 {
239  if (con == NULL)
240  {
241  con= malloc(sizeof(drizzle_con_st));
242  if (con == NULL)
243  {
244  if (drizzle != NULL)
245  drizzle_set_error(drizzle, "drizzle_con_create", "malloc");
246  return NULL;
247  }
248 
250  }
251  else
252  con->options= 0;
253 
254  if (drizzle->con_list != NULL)
255  drizzle->con_list->prev= con;
256  con->next= drizzle->con_list;
257  con->prev= NULL;
258  drizzle->con_list= con;
259  drizzle->con_count++;
260 
261  con->packet_number= 0;
262  con->protocol_version= 0;
263  con->state_current= 0;
264  con->events= 0;
265  con->revents= 0;
267  con->charset= 0;
268  con->command= 0;
269  con->options|= DRIZZLE_CON_MYSQL;
273  con->result_count= 0;
274  con->thread_id= 0;
276  con->fd= -1;
277  con->buffer_size= 0;
278  con->command_offset= 0;
279  con->command_size= 0;
280  con->command_total= 0;
281  con->packet_size= 0;
282  con->addrinfo_next= NULL;
283  con->buffer_ptr= con->buffer;
284  con->command_buffer= NULL;
285  con->command_data= NULL;
286  con->context= NULL;
287  con->context_free_fn= NULL;
288  con->drizzle= drizzle;
289  /* con->next set above */
290  /* con->prev set above */
291  con->query= NULL;
292  /* con->result doesn't need to be set */
293  con->result_list= NULL;
294  con->scramble= NULL;
295  con->socket.tcp.addrinfo= NULL;
296  con->socket.tcp.host= NULL;
297  con->socket.tcp.port= 0;
298  /* con->buffer doesn't need to be set */
299  con->db[0]= 0;
300  con->password[0]= 0;
301  /* con->scramble_buffer doesn't need to be set */
302  con->server_version[0]= 0;
303  /* con->state_stack doesn't need to be set */
304  con->user[0]= 0;
305 
306  return con;
307 }
308 
310  const drizzle_con_st *from)
311 {
312  con= drizzle_con_create(drizzle, con);
313  if (con == NULL)
314  return NULL;
315 
316  /* Clear "operational" options such as IO status. */
317  con->options|= (from->options & (drizzle_con_options_t)~(
321  con->backlog= from->backlog;
322  strcpy(con->db, from->db);
323  strcpy(con->password, from->password);
324  strcpy(con->user, from->user);
325 
326  switch (from->socket_type)
327  {
329  drizzle_con_set_tcp(con, from->socket.tcp.host, from->socket.tcp.port);
330  break;
331 
333  drizzle_con_set_uds(con, from->socket.uds.sockaddr.sun_path);
334  break;
335 
336  default:
337  break;
338  }
339 
340  return con;
341 }
342 
344 {
345  if (con->context != NULL && con->context_free_fn != NULL)
346  con->context_free_fn(con, con->context);
347 
350  else if (con->drizzle->options & DRIZZLE_ASSERT_DANGLING)
351  assert(con->result_list == NULL);
352 
353  if (con->fd != -1)
354  drizzle_con_close(con);
355 
357 
358  if (con->drizzle->con_list == con)
359  con->drizzle->con_list= con->next;
360  if (con->prev != NULL)
361  con->prev->next= con->next;
362  if (con->next != NULL)
363  con->next->prev= con->prev;
364  con->drizzle->con_count--;
365 
366  if (con->options & DRIZZLE_CON_ALLOCATED)
367  free(con);
368 }
369 
371 {
372  while (drizzle->con_list != NULL)
373  drizzle_con_free(drizzle->con_list);
374 }
375 
377 {
378  drizzle_con_st *con;
379  struct pollfd *pfds;
380  uint32_t x;
381  int ret;
382  drizzle_return_t dret;
383 
384  if (drizzle->pfds_size < drizzle->con_count)
385  {
386  pfds= realloc(drizzle->pfds, drizzle->con_count * sizeof(struct pollfd));
387  if (pfds == NULL)
388  {
389  drizzle_set_error(drizzle, "drizzle_con_wait", "realloc");
390  return DRIZZLE_RETURN_MEMORY;
391  }
392 
393  drizzle->pfds= pfds;
394  drizzle->pfds_size= drizzle->con_count;
395  }
396  else
397  pfds= drizzle->pfds;
398 
399  x= 0;
400  for (con= drizzle->con_list; con != NULL; con= con->next)
401  {
402  if (con->events == 0)
403  continue;
404 
405  pfds[x].fd= con->fd;
406  pfds[x].events= con->events;
407  pfds[x].revents= 0;
408  x++;
409  }
410 
411  if (x == 0)
412  {
413  drizzle_set_error(drizzle, "drizzle_con_wait",
414  "no active file descriptors");
416  }
417 
418  while (1)
419  {
420  drizzle_log_crazy(drizzle, "poll count=%d timeout=%d", x,
421  drizzle->timeout);
422 
423  ret= poll(pfds, x, drizzle->timeout);
424 
425  drizzle_log_crazy(drizzle, "poll return=%d errno=%d", ret, errno);
426 
427  if (ret == -1)
428  {
429  if (errno == EINTR)
430  continue;
431 
432  drizzle_set_error(drizzle, "drizzle_con_wait", "poll:%d", errno);
433  drizzle->last_errno= errno;
434  return DRIZZLE_RETURN_ERRNO;
435  }
436 
437  break;
438  }
439 
440  if (ret == 0)
441  {
442  drizzle_set_error(drizzle, "drizzle_con_wait", "timeout reached");
443  return DRIZZLE_RETURN_TIMEOUT;
444  }
445 
446  x= 0;
447  for (con= drizzle->con_list; con != NULL; con= con->next)
448  {
449  if (con->events == 0)
450  continue;
451 
452  dret= drizzle_con_set_revents(con, pfds[x].revents);
453  if (dret != DRIZZLE_RETURN_OK)
454  return dret;
455 
456  x++;
457  }
458 
459  return DRIZZLE_RETURN_OK;
460 }
461 
463 {
464  drizzle_con_st *con;
465 
466  /* We can't keep state between calls since connections may be removed during
467  processing. If this list ever gets big, we may want something faster. */
468 
469  for (con= drizzle->con_list; con != NULL; con= con->next)
470  {
471  if (con->options & DRIZZLE_CON_IO_READY)
472  {
474  return con;
475  }
476  }
477 
478  return NULL;
479 }
480 
482 {
483  drizzle_con_st *con;
484 
485  /* We can't keep state between calls since connections may be removed during
486  processing. If this list ever gets big, we may want something faster. */
487 
488  for (con= drizzle->con_list; con != NULL; con= con->next)
489  {
492  {
494  return con;
495  }
496  }
497 
498  return NULL;
499 }
500 
501 /*
502  * Client Definitions
503  */
504 
506  const char *host, in_port_t port,
507  const char *user, const char *password,
508  const char *db,
509  drizzle_con_options_t options)
510 {
511  con= drizzle_con_create(drizzle, con);
512  if (con == NULL)
513  return NULL;
514 
515  drizzle_con_set_tcp(con, host, port);
516  drizzle_con_set_auth(con, user, password);
517  drizzle_con_set_db(con, db);
518  drizzle_con_add_options(con, options);
519 
520  return con;
521 }
522 
524  const char *uds, const char *user,
525  const char *password, const char *db,
526  drizzle_con_options_t options)
527 {
528  con= drizzle_con_create(drizzle, con);
529  if (con == NULL)
530  return NULL;
531 
532  drizzle_con_set_uds(con, uds);
533  drizzle_con_set_auth(con, user, password);
534  drizzle_con_set_db(con, db);
535  drizzle_con_add_options(con, options);
536 
537  return con;
538 }
539 
540 /*
541  * Server Definitions
542  */
543 
545  drizzle_con_st *con,
546  const char *host, in_port_t port,
547  int backlog,
548  drizzle_con_options_t options)
549 {
550  con= drizzle_con_create(drizzle, con);
551  if (con == NULL)
552  return NULL;
553 
554  drizzle_con_set_tcp(con, host, port);
555  drizzle_con_set_backlog(con, backlog);
557 
558  return con;
559 }
560 
562  drizzle_con_st *con,
563  const char *uds, int backlog,
564  drizzle_con_options_t options)
565 {
566  con= drizzle_con_create(drizzle, con);
567  if (con == NULL)
568  return NULL;
569 
570  drizzle_con_set_uds(con, uds);
571  drizzle_con_set_backlog(con, backlog);
573 
574  return con;
575 }
576 
578  drizzle_return_t *ret_ptr)
579 {
580  drizzle_con_st *ready;
581  int fd;
582 
583  while (1)
584  {
585  if ((ready= drizzle_con_ready_listen(drizzle)) != NULL)
586  {
587  fd= accept(ready->fd, NULL, NULL);
588 
589  con= drizzle_con_create(drizzle, con);
590  if (con == NULL)
591  {
592  (void)close(fd);
593  *ret_ptr= DRIZZLE_RETURN_MEMORY;
594  return NULL;
595  }
596 
597  *ret_ptr= drizzle_con_set_fd(con, fd);
598  if (*ret_ptr != DRIZZLE_RETURN_OK)
599  {
600  (void)close(fd);
601  return NULL;
602  }
603 
604  if (ready->options & DRIZZLE_CON_MYSQL)
606 
607  *ret_ptr= DRIZZLE_RETURN_OK;
608  return con;
609  }
610 
611  if (drizzle->options & DRIZZLE_NON_BLOCKING)
612  {
613  *ret_ptr= DRIZZLE_RETURN_IO_WAIT;
614  return NULL;
615  }
616 
617  for (ready= drizzle->con_list; ready != NULL; ready= ready->next)
618  {
619  if (ready->options & DRIZZLE_CON_LISTEN)
620  drizzle_con_set_events(ready, POLLIN);
621  }
622 
623  *ret_ptr= drizzle_con_wait(drizzle);
624  if (*ret_ptr != DRIZZLE_RETURN_OK)
625  return NULL;
626  }
627 }
628 
629 /*
630  * Local Definitions
631  */
632 
633 void drizzle_set_error(drizzle_st *drizzle, const char *function,
634  const char *format, ...)
635 {
636  size_t size;
637  char *ptr;
638  char log_buffer[DRIZZLE_MAX_ERROR_SIZE];
639  va_list args;
640 
641  size= strlen(function);
642  ptr= memcpy(log_buffer, function, size);
643  ptr+= size;
644  ptr[0]= ':';
645  size++;
646  ptr++;
647 
648  va_start(args, format);
649  size+= (size_t)vsnprintf(ptr, DRIZZLE_MAX_ERROR_SIZE - size, format, args);
650  va_end(args);
651 
652  if (drizzle->log_fn == NULL)
653  {
654  if (size >= DRIZZLE_MAX_ERROR_SIZE)
655  size= DRIZZLE_MAX_ERROR_SIZE - 1;
656 
657  memcpy(drizzle->last_error, log_buffer, size + 1);
658  }
659  else
660  drizzle->log_fn(log_buffer, DRIZZLE_VERBOSE_ERROR, drizzle->log_context);
661 }
662 
663 void drizzle_log(drizzle_st *drizzle, drizzle_verbose_t verbose,
664  const char *format, va_list args)
665 {
666  char log_buffer[DRIZZLE_MAX_ERROR_SIZE];
667 
668  if (drizzle->log_fn == NULL)
669  {
670  printf("%5s: ", drizzle_verbose_name(verbose));
671  vprintf(format, args);
672  printf("\n");
673  }
674  else
675  {
676  vsnprintf(log_buffer, DRIZZLE_MAX_ERROR_SIZE, format, args);
677  drizzle->log_fn(log_buffer, verbose, drizzle->log_context);
678  }
679 }