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