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 
11 /**
12  * @file
13  * @brief Connection Definitions
14  */
15 
16 #include "common.h"
17 
18 /**
19  * @addtogroup drizzle_con_static Static Connection Declarations
20  * @ingroup drizzle_con
21  * @{
22  */
23 
24 /**
25  * Set socket options for a connection.
26  *
27  * @param[in] con Connection structure previously initialized with
28  *  drizzle_con_create(), drizzle_con_clone(), or related functions.
29  * @return Standard drizzle return value.
30  */
31 static drizzle_return_t _con_setsockopt(drizzle_con_st *con);
32 
33 /** @} */
34 
35 /*
36  * Common Definitions
37  */
38 
drizzle_con_fd(const drizzle_con_st * con)39 int drizzle_con_fd(const drizzle_con_st *con)
40 {
41   return con->fd;
42 }
43 
drizzle_con_set_fd(drizzle_con_st * con,int fd)44 drizzle_return_t drizzle_con_set_fd(drizzle_con_st *con, int fd)
45 {
46   drizzle_return_t ret;
47 
48   con->fd= fd;
49 
50   ret= _con_setsockopt(con);
51   if (ret != DRIZZLE_RETURN_OK)
52     con->drizzle->last_errno= errno;
53 
54   return ret;
55 }
56 
drizzle_con_close(drizzle_con_st * con)57 void drizzle_con_close(drizzle_con_st *con)
58 {
59   if (con->fd == -1)
60     return;
61 
62   (void)close(con->fd);
63   con->fd= -1;
64 
65   con->options&= (drizzle_con_options_t)~DRIZZLE_CON_READY;
66   con->packet_number= 0;
67   con->buffer_ptr= con->buffer;
68   con->buffer_size= 0;
69   con->events= 0;
70   con->revents= 0;
71 
72   drizzle_state_reset(con);
73 }
74 
drizzle_con_set_events(drizzle_con_st * con,short events)75 drizzle_return_t drizzle_con_set_events(drizzle_con_st *con, short events)
76 {
77   drizzle_return_t ret;
78 
79   if ((con->events | events) == con->events)
80     return DRIZZLE_RETURN_OK;
81 
82   con->events|= events;
83 
84   if (con->drizzle->event_watch_fn != NULL)
85   {
86     ret= con->drizzle->event_watch_fn(con, con->events,
87                                       con->drizzle->event_watch_context);
88     if (ret != DRIZZLE_RETURN_OK)
89     {
90       drizzle_con_close(con);
91       return ret;
92     }
93   }
94 
95   return DRIZZLE_RETURN_OK;
96 }
97 
drizzle_con_set_revents(drizzle_con_st * con,short revents)98 drizzle_return_t drizzle_con_set_revents(drizzle_con_st *con, short revents)
99 {
100   drizzle_return_t ret;
101 
102   if (revents != 0)
103     con->options|= DRIZZLE_CON_IO_READY;
104 
105   con->revents= revents;
106 
107   /* Remove external POLLOUT watch if we didn't ask for it. Otherwise we spin
108      forever until another POLLIN state change. This is much more efficient
109      than removing POLLOUT on every state change since some external polling
110      mechanisms need to use a system call to change flags (like Linux epoll). */
111   if (revents & POLLOUT && !(con->events & POLLOUT) &&
112       con->drizzle->event_watch_fn != NULL)
113   {
114     ret= con->drizzle->event_watch_fn(con, con->events,
115                                       con->drizzle->event_watch_context);
116     if (ret != DRIZZLE_RETURN_OK)
117     {
118       drizzle_con_close(con);
119       return ret;
120     }
121   }
122 
123   con->events&= (short)~revents;
124 
125   return DRIZZLE_RETURN_OK;
126 }
127 
drizzle_con_drizzle(const drizzle_con_st * con)128 drizzle_st *drizzle_con_drizzle(const drizzle_con_st *con)
129 {
130   return con->drizzle;
131 }
132 
drizzle_con_error(const drizzle_con_st * con)133 const char *drizzle_con_error(const drizzle_con_st *con)
134 {
135   return drizzle_error(con->drizzle);
136 }
137 
drizzle_con_errno(const drizzle_con_st * con)138 int drizzle_con_errno(const drizzle_con_st *con)
139 {
140   return drizzle_errno(con->drizzle);
141 }
142 
drizzle_con_error_code(const drizzle_con_st * con)143 uint16_t drizzle_con_error_code(const drizzle_con_st *con)
144 {
145   return drizzle_error_code(con->drizzle);
146 }
147 
drizzle_con_sqlstate(const drizzle_con_st * con)148 const char *drizzle_con_sqlstate(const drizzle_con_st *con)
149 {
150   return drizzle_sqlstate(con->drizzle);
151 }
152 
drizzle_con_options(const drizzle_con_st * con)153 drizzle_con_options_t drizzle_con_options(const drizzle_con_st *con)
154 {
155   return con->options;
156 }
157 
drizzle_con_set_options(drizzle_con_st * con,drizzle_con_options_t options)158 void drizzle_con_set_options(drizzle_con_st *con,
159                              drizzle_con_options_t options)
160 {
161   con->options= options;
162 }
163 
drizzle_con_add_options(drizzle_con_st * con,drizzle_con_options_t options)164 void drizzle_con_add_options(drizzle_con_st *con,
165                              drizzle_con_options_t options)
166 {
167   con->options|= options;
168 
169   /* If asking for the experimental Drizzle protocol, clean the MySQL flag. */
170   if (con->options & DRIZZLE_CON_EXPERIMENTAL)
171     con->options&= (drizzle_con_options_t)~DRIZZLE_CON_MYSQL;
172 }
173 
drizzle_con_remove_options(drizzle_con_st * con,drizzle_con_options_t options)174 void drizzle_con_remove_options(drizzle_con_st *con,
175                                 drizzle_con_options_t options)
176 {
177   con->options&= ~options;
178 }
179 
drizzle_con_host(const drizzle_con_st * con)180 const char *drizzle_con_host(const drizzle_con_st *con)
181 {
182   if (con->socket_type == DRIZZLE_CON_SOCKET_TCP)
183   {
184     if (con->socket.tcp.host == NULL && !(con->options & DRIZZLE_CON_LISTEN))
185       return DRIZZLE_DEFAULT_TCP_HOST;
186 
187     return con->socket.tcp.host;
188   }
189 
190   return NULL;
191 }
192 
drizzle_con_port(const drizzle_con_st * con)193 in_port_t drizzle_con_port(const drizzle_con_st *con)
194 {
195   if (con->socket_type == DRIZZLE_CON_SOCKET_TCP)
196   {
197     if (con->socket.tcp.port != 0)
198       return con->socket.tcp.port;
199 
200     if (con->options & DRIZZLE_CON_MYSQL)
201       return DRIZZLE_DEFAULT_TCP_PORT_MYSQL;
202 
203     return DRIZZLE_DEFAULT_TCP_PORT;
204   }
205 
206   return 0;
207 }
208 
drizzle_con_set_tcp(drizzle_con_st * con,const char * host,in_port_t port)209 void drizzle_con_set_tcp(drizzle_con_st *con, const char *host, in_port_t port)
210 {
211   drizzle_con_reset_addrinfo(con);
212 
213   con->socket_type= DRIZZLE_CON_SOCKET_TCP;
214 
215   if (host == NULL)
216     con->socket.tcp.host= NULL;
217   else
218   {
219     con->socket.tcp.host= con->socket.tcp.host_buffer;
220     strncpy(con->socket.tcp.host, host, NI_MAXHOST);
221     con->socket.tcp.host[NI_MAXHOST - 1]= 0;
222   }
223 
224   con->socket.tcp.port= port;
225 }
226 
drizzle_con_user(const drizzle_con_st * con)227 const char *drizzle_con_user(const drizzle_con_st *con)
228 {
229   return con->user;
230 }
231 
drizzle_con_password(const drizzle_con_st * con)232 const char *drizzle_con_password(const drizzle_con_st *con)
233 {
234   return con->password;
235 }
236 
drizzle_con_set_auth(drizzle_con_st * con,const char * user,const char * password)237 void drizzle_con_set_auth(drizzle_con_st *con, const char *user,
238                           const char *password)
239 {
240   if (user == NULL)
241     con->user[0]= 0;
242   else
243   {
244     strncpy(con->user, user, DRIZZLE_MAX_USER_SIZE);
245     con->user[DRIZZLE_MAX_USER_SIZE - 1]= 0;
246   }
247 
248   if (password == NULL)
249     con->password[0]= 0;
250   else
251   {
252     strncpy(con->password, password, DRIZZLE_MAX_PASSWORD_SIZE);
253     con->password[DRIZZLE_MAX_PASSWORD_SIZE - 1]= 0;
254   }
255 }
256 
drizzle_con_db(const drizzle_con_st * con)257 const char *drizzle_con_db(const drizzle_con_st *con)
258 {
259   return con->db;
260 }
261 
drizzle_con_set_db(drizzle_con_st * con,const char * db)262 void drizzle_con_set_db(drizzle_con_st *con, const char *db)
263 {
264   if (db == NULL)
265     con->db[0]= 0;
266   else
267   {
268     strncpy(con->db, db, DRIZZLE_MAX_DB_SIZE);
269     con->db[DRIZZLE_MAX_DB_SIZE - 1]= 0;
270   }
271 }
272 
drizzle_con_context(const drizzle_con_st * con)273 void *drizzle_con_context(const drizzle_con_st *con)
274 {
275   return con->context;
276 }
277 
drizzle_con_set_context(drizzle_con_st * con,void * context)278 void drizzle_con_set_context(drizzle_con_st *con, void *context)
279 {
280   con->context= context;
281 }
282 
drizzle_con_set_context_free_fn(drizzle_con_st * con,drizzle_con_context_free_fn * function)283 void drizzle_con_set_context_free_fn(drizzle_con_st *con,
284                                      drizzle_con_context_free_fn *function)
285 {
286   con->context_free_fn= function;
287 }
288 
drizzle_con_protocol_version(const drizzle_con_st * con)289 uint8_t drizzle_con_protocol_version(const drizzle_con_st *con)
290 {
291   return con->protocol_version;
292 }
293 
drizzle_con_server_version(const drizzle_con_st * con)294 const char *drizzle_con_server_version(const drizzle_con_st *con)
295 {
296   return con->server_version;
297 }
298 
drizzle_con_server_version_number(const drizzle_con_st * con)299 uint32_t drizzle_con_server_version_number(const drizzle_con_st *con)
300 {
301   uint32_t major;
302   uint32_t minor;
303   uint32_t version;
304   const char *current;
305   char *end;
306 
307   current= con->server_version;
308 
309   major= (uint32_t)strtoul(current, &end, 10);
310   current= end + 1;
311   minor= (uint32_t)strtoul(current, &end, 10);
312   current= end + 1;
313   version= (uint32_t)strtoul(current, &end, 10);
314 
315   return (major * 10000) + (minor * 100) + version;
316 }
317 
drizzle_con_thread_id(const drizzle_con_st * con)318 uint32_t drizzle_con_thread_id(const drizzle_con_st *con)
319 {
320   return con->thread_id;
321 }
322 
drizzle_con_scramble(const drizzle_con_st * con)323 const uint8_t *drizzle_con_scramble(const drizzle_con_st *con)
324 {
325   return con->scramble;
326 }
327 
drizzle_con_capabilities(const drizzle_con_st * con)328 drizzle_capabilities_t drizzle_con_capabilities(const drizzle_con_st *con)
329 {
330   return con->capabilities;
331 }
332 
drizzle_con_charset(const drizzle_con_st * con)333 drizzle_charset_t drizzle_con_charset(const drizzle_con_st *con)
334 {
335   return con->charset;
336 }
337 
drizzle_con_status(const drizzle_con_st * con)338 drizzle_con_status_t drizzle_con_status(const drizzle_con_st *con)
339 {
340   return con->status;
341 }
342 
drizzle_con_max_packet_size(const drizzle_con_st * con)343 uint32_t drizzle_con_max_packet_size(const drizzle_con_st *con)
344 {
345   return con->max_packet_size;
346 }
347 
348 /*
349  * Client Definitions
350  */
351 
drizzle_con_connect(drizzle_con_st * con)352 drizzle_return_t drizzle_con_connect(drizzle_con_st *con)
353 {
354   if (con->options & DRIZZLE_CON_READY)
355     return DRIZZLE_RETURN_OK;
356 
357   if (drizzle_state_none(con))
358   {
359     if (!(con->options & DRIZZLE_CON_RAW_PACKET))
360     {
361       drizzle_state_push(con, drizzle_state_handshake_server_read);
362       drizzle_state_push(con, drizzle_state_packet_read);
363     }
364 
365     drizzle_state_push(con, drizzle_state_connect);
366     drizzle_state_push(con, drizzle_state_addrinfo);
367   }
368 
369   return drizzle_state_loop(con);
370 }
371 
drizzle_con_quit(drizzle_con_st * con,drizzle_result_st * result,drizzle_return_t * ret_ptr)372 drizzle_result_st *drizzle_con_quit(drizzle_con_st *con,
373                                     drizzle_result_st *result,
374                                     drizzle_return_t *ret_ptr)
375 {
376   return drizzle_con_command_write(con, result, DRIZZLE_COMMAND_QUIT, NULL, 0,
377                                    0, ret_ptr);
378 }
379 
drizzle_quit(drizzle_con_st * con,drizzle_result_st * result,drizzle_return_t * ret_ptr)380 drizzle_result_st *drizzle_quit(drizzle_con_st *con,
381                                 drizzle_result_st *result,
382                                 drizzle_return_t *ret_ptr)
383 {
384   return drizzle_con_quit(con, result, ret_ptr);
385 }
386 
drizzle_con_select_db(drizzle_con_st * con,drizzle_result_st * result,const char * db,drizzle_return_t * ret_ptr)387 drizzle_result_st *drizzle_con_select_db(drizzle_con_st *con,
388                                          drizzle_result_st *result,
389                                          const char *db,
390                                          drizzle_return_t *ret_ptr)
391 {
392   drizzle_con_set_db(con, db);
393   return drizzle_con_command_write(con, result, DRIZZLE_COMMAND_INIT_DB,
394                                    db, strlen(db), strlen(db), ret_ptr);
395 }
396 
drizzle_select_db(drizzle_con_st * con,drizzle_result_st * result,const char * db,drizzle_return_t * ret_ptr)397 drizzle_result_st *drizzle_select_db(drizzle_con_st *con,
398                                      drizzle_result_st *result,
399                                      const char *db,
400                                      drizzle_return_t *ret_ptr)
401 {
402   return drizzle_con_select_db(con, result, db, ret_ptr);
403 }
404 
drizzle_con_shutdown(drizzle_con_st * con,drizzle_result_st * result,drizzle_return_t * ret_ptr)405 drizzle_result_st *drizzle_con_shutdown(drizzle_con_st *con,
406                                         drizzle_result_st *result,
407                                         drizzle_return_t *ret_ptr)
408 {
409   if (con->options & DRIZZLE_CON_MYSQL)
410   {
411     return drizzle_con_command_write(con, result, DRIZZLE_COMMAND_SHUTDOWN,
412                                      "0", 1, 1, ret_ptr);
413   }
414 
415   return drizzle_con_command_write(con, result, DRIZZLE_COMMAND_SHUTDOWN, NULL,
416                                    0, 0, ret_ptr);
417 }
418 
drizzle_shutdown(drizzle_con_st * con,drizzle_result_st * result,uint32_t level,drizzle_return_t * ret_ptr)419 drizzle_result_st *drizzle_shutdown(drizzle_con_st *con,
420                                     drizzle_result_st *result, uint32_t level,
421                                     drizzle_return_t *ret_ptr)
422 {
423   (void) level;
424   return drizzle_con_shutdown(con, result, ret_ptr);
425 }
426 
drizzle_con_ping(drizzle_con_st * con,drizzle_result_st * result,drizzle_return_t * ret_ptr)427 drizzle_result_st *drizzle_con_ping(drizzle_con_st *con,
428                                     drizzle_result_st *result,
429                                     drizzle_return_t *ret_ptr)
430 {
431   return drizzle_con_command_write(con, result, DRIZZLE_COMMAND_PING, NULL, 0,
432                                    0, ret_ptr);
433 }
434 
drizzle_ping(drizzle_con_st * con,drizzle_result_st * result,drizzle_return_t * ret_ptr)435 drizzle_result_st *drizzle_ping(drizzle_con_st *con,
436                                 drizzle_result_st *result,
437                                 drizzle_return_t *ret_ptr)
438 {
439   return drizzle_con_ping(con, result, ret_ptr);
440 }
441 
drizzle_con_command_write(drizzle_con_st * con,drizzle_result_st * result,drizzle_command_t command,const void * data,size_t size,size_t total,drizzle_return_t * ret_ptr)442 drizzle_result_st *drizzle_con_command_write(drizzle_con_st *con,
443                                              drizzle_result_st *result,
444                                              drizzle_command_t command,
445                                              const void *data, size_t size,
446                                              size_t total,
447                                              drizzle_return_t *ret_ptr)
448 {
449   if (!(con->options & DRIZZLE_CON_READY))
450   {
451     if (con->options & DRIZZLE_CON_RAW_PACKET)
452     {
453       drizzle_set_error(con->drizzle, "drizzle_command_write",
454                         "connection not ready");
455       *ret_ptr= DRIZZLE_RETURN_NOT_READY;
456       return result;
457     }
458 
459     *ret_ptr= drizzle_con_connect(con);
460     if (*ret_ptr != DRIZZLE_RETURN_OK)
461       return result;
462   }
463 
464   if (drizzle_state_none(con))
465   {
466     if (con->options & (DRIZZLE_CON_RAW_PACKET | DRIZZLE_CON_NO_RESULT_READ))
467       con->result= NULL;
468     else
469     {
470       con->result= drizzle_result_create(con, result);
471       if (con->result == NULL)
472       {
473         *ret_ptr= DRIZZLE_RETURN_MEMORY;
474         return NULL;
475       }
476     }
477 
478     con->command= command;
479     con->command_data= (uint8_t *)data;
480     con->command_size= size;
481     con->command_offset= 0;
482     con->command_total= total;
483 
484     drizzle_state_push(con, drizzle_state_command_write);
485   }
486   else if (con->command_data == NULL)
487   {
488     con->command_data= (uint8_t *)data;
489     con->command_size= size;
490   }
491 
492   *ret_ptr= drizzle_state_loop(con);
493   if (*ret_ptr == DRIZZLE_RETURN_PAUSE)
494     *ret_ptr= DRIZZLE_RETURN_OK;
495   else if (*ret_ptr != DRIZZLE_RETURN_OK &&
496            *ret_ptr != DRIZZLE_RETURN_IO_WAIT &&
497            *ret_ptr != DRIZZLE_RETURN_ERROR_CODE)
498   {
499     drizzle_result_free(con->result);
500     con->result= result;
501   }
502 
503   return con->result;
504 }
505 
506 /*
507  * Server Definitions
508  */
509 
drizzle_con_listen(drizzle_con_st * con)510 drizzle_return_t drizzle_con_listen(drizzle_con_st *con)
511 {
512   if (con->options & DRIZZLE_CON_READY)
513     return DRIZZLE_RETURN_OK;
514 
515   if (drizzle_state_none(con))
516   {
517     drizzle_state_push(con, drizzle_state_listen);
518     drizzle_state_push(con, drizzle_state_addrinfo);
519   }
520 
521   return drizzle_state_loop(con);
522 }
523 
drizzle_con_backlog(const drizzle_con_st * con)524 int drizzle_con_backlog(const drizzle_con_st *con)
525 {
526   return con->backlog;
527 }
528 
drizzle_con_set_backlog(drizzle_con_st * con,int backlog)529 void drizzle_con_set_backlog(drizzle_con_st *con, int backlog)
530 {
531   con->backlog= backlog;
532 }
533 
drizzle_con_set_protocol_version(drizzle_con_st * con,uint8_t protocol_version)534 void drizzle_con_set_protocol_version(drizzle_con_st *con,
535                                       uint8_t protocol_version)
536 {
537   con->protocol_version= protocol_version;
538 }
539 
drizzle_con_set_server_version(drizzle_con_st * con,const char * server_version)540 void drizzle_con_set_server_version(drizzle_con_st *con,
541                                     const char *server_version)
542 {
543   if (server_version == NULL)
544     con->server_version[0]= 0;
545   else
546   {
547     strncpy(con->server_version, server_version,
548             DRIZZLE_MAX_SERVER_VERSION_SIZE);
549     con->server_version[DRIZZLE_MAX_SERVER_VERSION_SIZE - 1]= 0;
550   }
551 }
552 
drizzle_con_set_thread_id(drizzle_con_st * con,uint32_t thread_id)553 void drizzle_con_set_thread_id(drizzle_con_st *con, uint32_t thread_id)
554 {
555   con->thread_id= thread_id;
556 }
557 
drizzle_con_set_scramble(drizzle_con_st * con,const uint8_t * scramble)558 void drizzle_con_set_scramble(drizzle_con_st *con, const uint8_t *scramble)
559 {
560   if (scramble == NULL)
561     con->scramble= NULL;
562   else
563   {
564     con->scramble= con->scramble_buffer;
565     memcpy(con->scramble, scramble, DRIZZLE_MAX_SCRAMBLE_SIZE);
566   }
567 }
568 
drizzle_con_set_capabilities(drizzle_con_st * con,drizzle_capabilities_t capabilities)569 void drizzle_con_set_capabilities(drizzle_con_st *con,
570                                   drizzle_capabilities_t capabilities)
571 {
572   con->capabilities= capabilities;
573 }
574 
drizzle_con_set_charset(drizzle_con_st * con,drizzle_charset_t charset)575 void drizzle_con_set_charset(drizzle_con_st *con, drizzle_charset_t charset)
576 {
577   con->charset= charset;
578 }
579 
drizzle_con_set_status(drizzle_con_st * con,drizzle_con_status_t status)580 void drizzle_con_set_status(drizzle_con_st *con, drizzle_con_status_t status)
581 {
582   con->status= status;
583 }
584 
drizzle_con_set_max_packet_size(drizzle_con_st * con,uint32_t max_packet_size)585 void drizzle_con_set_max_packet_size(drizzle_con_st *con,
586                                      uint32_t max_packet_size)
587 {
588   con->max_packet_size= max_packet_size;
589 }
590 
drizzle_con_copy_handshake(drizzle_con_st * con,drizzle_con_st * from)591 void drizzle_con_copy_handshake(drizzle_con_st *con, drizzle_con_st *from)
592 {
593   drizzle_con_set_auth(con, from->user, NULL);
594   drizzle_con_set_scramble(con, from->scramble);
595   drizzle_con_set_db(con, from->db);
596   drizzle_con_set_protocol_version(con, from->protocol_version);
597   drizzle_con_set_server_version(con, from->server_version);
598   drizzle_con_set_thread_id(con, from->thread_id);
599   drizzle_con_set_scramble(con, from->scramble);
600   drizzle_con_set_capabilities(con, from->capabilities);
601   drizzle_con_set_charset(con, from->charset);
602   drizzle_con_set_status(con, from->status);
603   drizzle_con_set_max_packet_size(con, from->max_packet_size);
604 }
605 
drizzle_con_command_read(drizzle_con_st * con,drizzle_command_t * command,size_t * offset,size_t * size,size_t * total,drizzle_return_t * ret_ptr)606 void *drizzle_con_command_read(drizzle_con_st *con,
607                                drizzle_command_t *command, size_t *offset,
608                                size_t *size, size_t *total,
609                                drizzle_return_t *ret_ptr)
610 {
611   if (drizzle_state_none(con))
612   {
613     con->packet_number= 0;
614     con->command_offset= 0;
615     con->command_total= 0;
616 
617     drizzle_state_push(con, drizzle_state_command_read);
618     drizzle_state_push(con, drizzle_state_packet_read);
619   }
620 
621   *offset= con->command_offset;
622 
623   *ret_ptr= drizzle_state_loop(con);
624   if (*ret_ptr == DRIZZLE_RETURN_PAUSE)
625     *ret_ptr= DRIZZLE_RETURN_OK;
626 
627   *command= con->command;
628   *size= con->command_size;
629   *total= con->command_total;
630 
631   return con->command_data;
632 }
633 
drizzle_con_command_buffer(drizzle_con_st * con,drizzle_command_t * command,size_t * total,drizzle_return_t * ret_ptr)634 void *drizzle_con_command_buffer(drizzle_con_st *con,
635                                  drizzle_command_t *command, size_t *total,
636                                  drizzle_return_t *ret_ptr)
637 {
638   uint8_t *command_data;
639   size_t offset= 0;
640   size_t size= 0;
641 
642   command_data= drizzle_con_command_read(con, command, &offset, &size, total,
643                                          ret_ptr);
644   if (*ret_ptr != DRIZZLE_RETURN_OK)
645     return NULL;
646 
647   if (command_data == NULL)
648   {
649     *total= 0;
650     return NULL;
651   }
652 
653   if (con->command_buffer == NULL)
654   {
655     con->command_buffer= malloc((*total) + 1);
656     if (con->command_buffer == NULL)
657     {
658       drizzle_set_error(con->drizzle, "drizzle_command_buffer", "malloc");
659       *ret_ptr= DRIZZLE_RETURN_MEMORY;
660       return NULL;
661     }
662   }
663 
664   memcpy(con->command_buffer + offset, command_data, size);
665 
666   while ((offset + size) != (*total))
667   {
668     command_data= drizzle_con_command_read(con, command, &offset, &size, total,
669                                            ret_ptr);
670     if (*ret_ptr != DRIZZLE_RETURN_OK)
671       return NULL;
672 
673     memcpy(con->command_buffer + offset, command_data, size);
674   }
675 
676   command_data= con->command_buffer;
677   con->command_buffer= NULL;
678   command_data[*total]= 0;
679 
680   return command_data;
681 }
682 
683 /*
684  * Local Definitions
685  */
686 
drizzle_con_reset_addrinfo(drizzle_con_st * con)687 void drizzle_con_reset_addrinfo(drizzle_con_st *con)
688 {
689   switch (con->socket_type)
690   {
691   case DRIZZLE_CON_SOCKET_TCP:
692     if (con->socket.tcp.addrinfo != NULL)
693     {
694       freeaddrinfo(con->socket.tcp.addrinfo);
695       con->socket.tcp.addrinfo= NULL;
696     }
697     break;
698 
699   case DRIZZLE_CON_SOCKET_UDS:
700     con->socket.uds.addrinfo.ai_addr= NULL;
701     break;
702 
703   default:
704     break;
705   }
706 
707   con->addrinfo_next= NULL;
708 }
709 
710 /*
711  * State Definitions
712  */
713 
drizzle_state_addrinfo(drizzle_con_st * con)714 drizzle_return_t drizzle_state_addrinfo(drizzle_con_st *con)
715 {
716   drizzle_con_tcp_st *tcp;
717   const char *host;
718   char port[NI_MAXSERV];
719   struct addrinfo ai;
720   int ret;
721 
722   drizzle_log_debug(con->drizzle, "drizzle_state_addrinfo");
723 
724   switch (con->socket_type)
725   {
726   case DRIZZLE_CON_SOCKET_TCP:
727     tcp= &(con->socket.tcp);
728 
729     if (tcp->addrinfo != NULL)
730     {
731       freeaddrinfo(tcp->addrinfo);
732       tcp->addrinfo= NULL;
733     }
734 
735     if (tcp->port != 0)
736       snprintf(port, NI_MAXSERV, "%u", tcp->port);
737     else if (con->options & DRIZZLE_CON_MYSQL)
738       snprintf(port, NI_MAXSERV, "%u", DRIZZLE_DEFAULT_TCP_PORT_MYSQL);
739     else
740       snprintf(port, NI_MAXSERV, "%u", DRIZZLE_DEFAULT_TCP_PORT);
741 
742     memset(&ai, 0, sizeof(struct addrinfo));
743     ai.ai_socktype= SOCK_STREAM;
744     ai.ai_protocol= IPPROTO_TCP;
745 
746     if (con->options & DRIZZLE_CON_LISTEN)
747     {
748       ai.ai_flags = AI_PASSIVE;
749       ai.ai_family = AF_UNSPEC;
750       host= tcp->host;
751     }
752     else
753     {
754       if (tcp->host == NULL)
755         host= DRIZZLE_DEFAULT_TCP_HOST;
756       else
757         host= tcp->host;
758     }
759 
760     ret= getaddrinfo(host, port, &ai, &(tcp->addrinfo));
761     if (ret != 0)
762     {
763       drizzle_set_error(con->drizzle, "drizzle_state_addrinfo",
764                         "getaddrinfo:%s", gai_strerror(ret));
765       return DRIZZLE_RETURN_GETADDRINFO;
766     }
767 
768     con->addrinfo_next= tcp->addrinfo;
769 
770     break;
771 
772   case DRIZZLE_CON_SOCKET_UDS:
773     con->addrinfo_next= &(con->socket.uds.addrinfo);
774     break;
775 
776   default:
777     break;
778   }
779 
780   drizzle_state_pop(con);
781   return DRIZZLE_RETURN_OK;
782 }
783 
drizzle_state_connect(drizzle_con_st * con)784 drizzle_return_t drizzle_state_connect(drizzle_con_st *con)
785 {
786   int ret;
787   drizzle_return_t dret;
788 
789   drizzle_log_debug(con->drizzle, "drizzle_state_connect");
790 
791   if (con->fd != -1)
792   {
793     (void)close(con->fd);
794     con->fd= -1;
795   }
796 
797   if (con->addrinfo_next == NULL)
798   {
799     drizzle_set_error(con->drizzle, "drizzle_state_connect",
800                       "could not connect");
801     drizzle_state_reset(con);
802     return DRIZZLE_RETURN_COULD_NOT_CONNECT;
803   }
804 
805   con->fd= socket(con->addrinfo_next->ai_family,
806                   con->addrinfo_next->ai_socktype,
807                   con->addrinfo_next->ai_protocol);
808   if (con->fd == -1)
809   {
810     drizzle_set_error(con->drizzle, "drizzle_state_connect", "socket:%d",
811                       errno);
812     con->drizzle->last_errno= errno;
813     return DRIZZLE_RETURN_ERRNO;
814   }
815 
816   dret= _con_setsockopt(con);
817   if (dret != DRIZZLE_RETURN_OK)
818   {
819     con->drizzle->last_errno= errno;
820     return dret;
821   }
822 
823   while (1)
824   {
825     ret= connect(con->fd, con->addrinfo_next->ai_addr,
826                  con->addrinfo_next->ai_addrlen);
827 
828     drizzle_log_crazy(con->drizzle, "connect return=%d errno=%d", ret, errno);
829 
830     if (ret == 0)
831     {
832       con->addrinfo_next= NULL;
833       break;
834     }
835 
836     if (errno == EAGAIN || errno == EINTR)
837       continue;
838 
839     if (errno == EINPROGRESS)
840     {
841       drizzle_state_pop(con);
842       drizzle_state_push(con, drizzle_state_connecting);
843       return DRIZZLE_RETURN_OK;
844     }
845 
846     if (errno == ECONNREFUSED || errno == ENETUNREACH || errno == ETIMEDOUT)
847     {
848       con->addrinfo_next= con->addrinfo_next->ai_next;
849       return DRIZZLE_RETURN_OK;
850     }
851 
852     drizzle_set_error(con->drizzle, "drizzle_state_connect", "connect:%d",
853                       errno);
854     con->drizzle->last_errno= errno;
855     return DRIZZLE_RETURN_ERRNO;
856   }
857 
858   drizzle_state_pop(con);
859   return DRIZZLE_RETURN_OK;
860 }
861 
drizzle_state_connecting(drizzle_con_st * con)862 drizzle_return_t drizzle_state_connecting(drizzle_con_st *con)
863 {
864   drizzle_return_t ret;
865 
866   drizzle_log_debug(con->drizzle, "drizzle_state_connecting");
867 
868   while (1)
869   {
870     if (con->revents & POLLOUT)
871     {
872       drizzle_state_pop(con);
873       return DRIZZLE_RETURN_OK;
874     }
875     else if (con->revents & (POLLERR | POLLHUP | POLLNVAL))
876     {
877       con->revents= 0;
878       drizzle_state_pop(con);
879       drizzle_state_push(con, drizzle_state_connect);
880       con->addrinfo_next= con->addrinfo_next->ai_next;
881       return DRIZZLE_RETURN_OK;
882     }
883 
884     ret= drizzle_con_set_events(con, POLLOUT);
885     if (ret != DRIZZLE_RETURN_OK)
886       return ret;
887 
888     if (con->drizzle->options & DRIZZLE_NON_BLOCKING)
889       return DRIZZLE_RETURN_IO_WAIT;
890 
891     ret= drizzle_con_wait(con->drizzle);
892     if (ret != DRIZZLE_RETURN_OK)
893       return ret;
894   }
895 }
896 
drizzle_state_read(drizzle_con_st * con)897 drizzle_return_t drizzle_state_read(drizzle_con_st *con)
898 {
899   drizzle_return_t ret;
900   ssize_t read_size;
901 
902   drizzle_log_debug(con->drizzle, "drizzle_state_read");
903 
904   if (con->buffer_size == 0)
905     con->buffer_ptr= con->buffer;
906   else if ((con->buffer_ptr - con->buffer) > (DRIZZLE_MAX_BUFFER_SIZE / 2))
907   {
908     memmove(con->buffer, con->buffer_ptr, con->buffer_size);
909     con->buffer_ptr= con->buffer;
910   }
911 
912   while (1)
913   {
914     read_size= read(con->fd, con->buffer_ptr + con->buffer_size,
915                     (size_t)DRIZZLE_MAX_BUFFER_SIZE -
916                     ((size_t)(con->buffer_ptr - con->buffer) +
917                      con->buffer_size));
918 
919     drizzle_log_crazy(con->drizzle, "read fd=%d return=%zd errno=%d", con->fd,
920                       read_size, errno);
921 
922     if (read_size == 0)
923     {
924       drizzle_set_error(con->drizzle, "drizzle_state_read",
925                         "lost connection to server (EOF)");
926       return DRIZZLE_RETURN_LOST_CONNECTION;
927     }
928     else if (read_size == -1)
929     {
930       if (errno == EAGAIN)
931       {
932         ret= drizzle_con_set_events(con, POLLIN);
933         if (ret != DRIZZLE_RETURN_OK)
934           return 0;
935 
936         if (con->drizzle->options & DRIZZLE_NON_BLOCKING)
937           return DRIZZLE_RETURN_IO_WAIT;
938 
939         ret= drizzle_con_wait(con->drizzle);
940         if (ret != DRIZZLE_RETURN_OK)
941           return ret;
942 
943         continue;
944       }
945       else if (errno == ECONNREFUSED)
946       {
947         con->revents= 0;
948         drizzle_state_pop(con);
949         drizzle_state_push(con, drizzle_state_connect);
950         con->addrinfo_next= con->addrinfo_next->ai_next;
951         return DRIZZLE_RETURN_OK;
952       }
953       else if (errno == EINTR)
954         continue;
955       else if (errno == EPIPE || errno == ECONNRESET)
956       {
957         drizzle_set_error(con->drizzle, "drizzle_state_read",
958                           "lost connection to server (%d)", errno);
959         return DRIZZLE_RETURN_LOST_CONNECTION;
960       }
961 
962       drizzle_set_error(con->drizzle, "drizzle_state_read", "read:%d", errno);
963       con->drizzle->last_errno= errno;
964       return DRIZZLE_RETURN_ERRNO;
965     }
966 
967     con->buffer_size+= (size_t)read_size;
968     break;
969   }
970 
971   drizzle_state_pop(con);;
972   return DRIZZLE_RETURN_OK;
973 }
974 
drizzle_state_write(drizzle_con_st * con)975 drizzle_return_t drizzle_state_write(drizzle_con_st *con)
976 {
977   drizzle_return_t ret;
978   ssize_t write_size;
979 
980   drizzle_log_debug(con->drizzle, "drizzle_state_write");
981 
982   while (con->buffer_size != 0)
983   {
984     write_size= write(con->fd, con->buffer_ptr, con->buffer_size);
985 
986     drizzle_log_crazy(con->drizzle, "write fd=%d return=%zd errno=%d", con->fd,
987                       write_size, errno);
988 
989     if (write_size == 0)
990     {
991       drizzle_set_error(con->drizzle, "drizzle_state_write",
992                         "lost connection to server (EOF)");
993       return DRIZZLE_RETURN_LOST_CONNECTION;
994     }
995     else if (write_size == -1)
996     {
997       if (errno == EAGAIN)
998       {
999         ret= drizzle_con_set_events(con, POLLOUT);
1000         if (ret != DRIZZLE_RETURN_OK)
1001           return ret;
1002 
1003         if (con->drizzle->options & DRIZZLE_NON_BLOCKING)
1004           return DRIZZLE_RETURN_IO_WAIT;
1005 
1006         ret= drizzle_con_wait(con->drizzle);
1007         if (ret != DRIZZLE_RETURN_OK)
1008           return ret;
1009 
1010         continue;
1011       }
1012       else if (errno == EINTR)
1013         continue;
1014       else if (errno == EPIPE || errno == ECONNRESET)
1015       {
1016         drizzle_set_error(con->drizzle, "drizzle_state_write",
1017                           "lost connection to server (%d)", errno);
1018         return DRIZZLE_RETURN_LOST_CONNECTION;
1019       }
1020 
1021       drizzle_set_error(con->drizzle, "drizzle_state_write", "write:%d", errno);
1022       con->drizzle->last_errno= errno;
1023       return DRIZZLE_RETURN_ERRNO;
1024     }
1025 
1026     con->buffer_ptr+= write_size;
1027     con->buffer_size-= (size_t)write_size;
1028     if (con->buffer_size == 0)
1029       break;
1030   }
1031 
1032   con->buffer_ptr= con->buffer;
1033 
1034   drizzle_state_pop(con);
1035   return DRIZZLE_RETURN_OK;
1036 }
1037 
drizzle_state_listen(drizzle_con_st * con)1038 drizzle_return_t drizzle_state_listen(drizzle_con_st *con)
1039 {
1040   char host[NI_MAXHOST];
1041   char port[NI_MAXSERV];
1042   int ret;
1043   int fd;
1044   int opt;
1045   drizzle_con_st *new_con;
1046 
1047   for (; con->addrinfo_next != NULL;
1048        con->addrinfo_next= con->addrinfo_next->ai_next)
1049   {
1050     ret= getnameinfo(con->addrinfo_next->ai_addr,
1051                      con->addrinfo_next->ai_addrlen, host, NI_MAXHOST, port,
1052                      NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
1053     if (ret != 0)
1054     {
1055       drizzle_set_error(con->drizzle, "drizzle_state_listen", "getnameinfo:%s",
1056                         gai_strerror(ret));
1057       return DRIZZLE_RETURN_GETADDRINFO;
1058     }
1059 
1060     /* Call to socket() can fail for some getaddrinfo results, try another. */
1061     fd= socket(con->addrinfo_next->ai_family, con->addrinfo_next->ai_socktype,
1062                con->addrinfo_next->ai_protocol);
1063     if (fd == -1)
1064     {
1065       drizzle_log_info(con->drizzle, "could not listen on %s:%s", host, port);
1066       drizzle_set_error(con->drizzle, "drizzle_state_listen", "socket:%d",
1067                         errno);
1068       continue;
1069     }
1070 
1071     opt= 1;
1072     ret= setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
1073     if (ret == -1)
1074     {
1075       close(fd);
1076       drizzle_set_error(con->drizzle, "drizzle_state_listen", "setsockopt:%d",
1077                         errno);
1078       return DRIZZLE_RETURN_ERRNO;
1079     }
1080 
1081     ret= bind(fd, con->addrinfo_next->ai_addr, con->addrinfo_next->ai_addrlen);
1082     if (ret == -1)
1083     {
1084       close(fd);
1085       drizzle_set_error(con->drizzle, "drizzle_state_listen", "bind:%d", errno);
1086       if (errno == EADDRINUSE)
1087       {
1088         if (con->fd == -1)
1089         {
1090           drizzle_log_info(con->drizzle, "could not listen on %s:%s", host,
1091                            port);
1092         }
1093 
1094         continue;
1095       }
1096 
1097       return DRIZZLE_RETURN_ERRNO;
1098     }
1099 
1100     if (listen(fd, con->backlog) == -1)
1101     {
1102       close(fd);
1103       drizzle_set_error(con->drizzle, "drizzle_state_listen", "listen:%d",
1104                         errno);
1105       return DRIZZLE_RETURN_ERRNO;
1106     }
1107 
1108     if (con->fd == -1)
1109     {
1110       con->fd= fd;
1111       new_con= con;
1112     }
1113     else
1114     {
1115       new_con= drizzle_con_clone(con->drizzle, NULL, con);
1116       if (new_con == NULL)
1117       {
1118         close(fd);
1119         return DRIZZLE_RETURN_MEMORY;
1120       }
1121 
1122       new_con->fd= fd;
1123     }
1124 
1125     /* Wait for read events on the listening socket. */
1126     ret= drizzle_con_set_events(new_con, POLLIN);
1127     if (ret != DRIZZLE_RETURN_OK)
1128     {
1129       drizzle_con_free(new_con);
1130       return ret;
1131     }
1132 
1133     drizzle_log_info(con->drizzle, "listening on %s:%s", host, port);
1134   }
1135 
1136   /* Report last socket() error if we couldn't find an address to bind. */
1137   if (con->fd == -1)
1138     return DRIZZLE_RETURN_ERRNO;
1139 
1140   drizzle_state_pop(con);
1141   return DRIZZLE_RETURN_OK;
1142 }
1143 
1144 /*
1145  * Static Definitions
1146  */
1147 
_con_setsockopt(drizzle_con_st * con)1148 static drizzle_return_t _con_setsockopt(drizzle_con_st *con)
1149 {
1150   int ret;
1151   struct linger linger;
1152   struct timeval waittime;
1153 
1154   ret= 1;
1155   ret= setsockopt(con->fd, IPPROTO_TCP, TCP_NODELAY, &ret,
1156                   (socklen_t)sizeof(int));
1157   if (ret == -1 && errno != EOPNOTSUPP)
1158   {
1159     drizzle_set_error(con->drizzle, "_con_setsockopt",
1160                       "setsockopt:TCP_NODELAY:%d", errno);
1161     return DRIZZLE_RETURN_ERRNO;
1162   }
1163 
1164   linger.l_onoff= 1;
1165   linger.l_linger= DRIZZLE_DEFAULT_SOCKET_TIMEOUT;
1166   ret= setsockopt(con->fd, SOL_SOCKET, SO_LINGER, &linger,
1167                   (socklen_t)sizeof(struct linger));
1168   if (ret == -1)
1169   {
1170     drizzle_set_error(con->drizzle, "_con_setsockopt",
1171                       "setsockopt:SO_LINGER:%d", errno);
1172     return DRIZZLE_RETURN_ERRNO;
1173   }
1174 
1175   waittime.tv_sec= DRIZZLE_DEFAULT_SOCKET_TIMEOUT;
1176   waittime.tv_usec= 0;
1177   ret= setsockopt(con->fd, SOL_SOCKET, SO_SNDTIMEO, &waittime,
1178                   (socklen_t)sizeof(struct timeval));
1179   if (ret == -1 && errno != ENOPROTOOPT)
1180   {
1181     drizzle_set_error(con->drizzle, "_con_setsockopt",
1182                       "setsockopt:SO_SNDTIMEO:%d", errno);
1183     return DRIZZLE_RETURN_ERRNO;
1184   }
1185 
1186   ret= setsockopt(con->fd, SOL_SOCKET, SO_RCVTIMEO, &waittime,
1187                   (socklen_t)sizeof(struct timeval));
1188   if (ret == -1 && errno != ENOPROTOOPT)
1189   {
1190     drizzle_set_error(con->drizzle, "_con_setsockopt",
1191                       "setsockopt:SO_RCVTIMEO:%d", errno);
1192     return DRIZZLE_RETURN_ERRNO;
1193   }
1194 
1195   ret= DRIZZLE_DEFAULT_SOCKET_SEND_SIZE;
1196   ret= setsockopt(con->fd, SOL_SOCKET, SO_SNDBUF, &ret, (socklen_t)sizeof(int));
1197   if (ret == -1)
1198   {
1199     drizzle_set_error(con->drizzle, "_con_setsockopt",
1200                       "setsockopt:SO_SNDBUF:%d", errno);
1201     return DRIZZLE_RETURN_ERRNO;
1202   }
1203 
1204   ret= DRIZZLE_DEFAULT_SOCKET_RECV_SIZE;
1205   ret= setsockopt(con->fd, SOL_SOCKET, SO_RCVBUF, &ret, (socklen_t)sizeof(int));
1206   if (ret == -1)
1207   {
1208     drizzle_set_error(con->drizzle, "_con_setsockopt",
1209                       "setsockopt:SO_RCVBUF:%d", errno);
1210     return DRIZZLE_RETURN_ERRNO;
1211   }
1212 
1213   ret= fcntl(con->fd, F_GETFL, 0);
1214   if (ret == -1)
1215   {
1216     drizzle_set_error(con->drizzle, "_con_setsockopt", "fcntl:F_GETFL:%d",
1217                       errno);
1218     return DRIZZLE_RETURN_ERRNO;
1219   }
1220 
1221   ret= fcntl(con->fd, F_SETFL, ret | O_NONBLOCK);
1222   if (ret == -1)
1223   {
1224     drizzle_set_error(con->drizzle, "_con_setsockopt", "fcntl:F_SETFL:%d",
1225                       errno);
1226     return DRIZZLE_RETURN_ERRNO;
1227   }
1228 
1229   return DRIZZLE_RETURN_OK;
1230 }
1231