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 Command definitions
14  */
15 
16 #include "common.h"
17 
18 /*
19  * Private variables.
20  */
21 
22 static drizzle_command_drizzle_t _command_drizzle_map[]=
23 {
24  DRIZZLE_COMMAND_DRIZZLE_END,
25  DRIZZLE_COMMAND_DRIZZLE_QUIT,
26  DRIZZLE_COMMAND_DRIZZLE_INIT_DB,
27  DRIZZLE_COMMAND_DRIZZLE_QUERY,
28  DRIZZLE_COMMAND_DRIZZLE_END,
29  DRIZZLE_COMMAND_DRIZZLE_END,
30  DRIZZLE_COMMAND_DRIZZLE_END,
31  DRIZZLE_COMMAND_DRIZZLE_END,
32  DRIZZLE_COMMAND_DRIZZLE_SHUTDOWN,
33  DRIZZLE_COMMAND_DRIZZLE_END,
34  DRIZZLE_COMMAND_DRIZZLE_END,
35  DRIZZLE_COMMAND_DRIZZLE_END,
36  DRIZZLE_COMMAND_DRIZZLE_END,
37  DRIZZLE_COMMAND_DRIZZLE_END,
38  DRIZZLE_COMMAND_DRIZZLE_PING,
39  DRIZZLE_COMMAND_DRIZZLE_END,
40  DRIZZLE_COMMAND_DRIZZLE_END,
41  DRIZZLE_COMMAND_DRIZZLE_END,
42  DRIZZLE_COMMAND_DRIZZLE_END,
43  DRIZZLE_COMMAND_DRIZZLE_END,
44  DRIZZLE_COMMAND_DRIZZLE_END,
45  DRIZZLE_COMMAND_DRIZZLE_END,
46  DRIZZLE_COMMAND_DRIZZLE_END,
47  DRIZZLE_COMMAND_DRIZZLE_END,
48  DRIZZLE_COMMAND_DRIZZLE_END,
49  DRIZZLE_COMMAND_DRIZZLE_END,
50  DRIZZLE_COMMAND_DRIZZLE_END,
51  DRIZZLE_COMMAND_DRIZZLE_END,
52  DRIZZLE_COMMAND_DRIZZLE_END,
53  DRIZZLE_COMMAND_DRIZZLE_END,
54  DRIZZLE_COMMAND_DRIZZLE_END
55 };
56 
57 /*
58  * State Definitions
59  */
60 
drizzle_state_command_read(drizzle_con_st * con)61 drizzle_return_t drizzle_state_command_read(drizzle_con_st *con)
62 {
63   drizzle_log_debug(con->drizzle, "drizzle_state_command_read");
64 
65   if (con->buffer_size == 0)
66   {
67     drizzle_state_push(con, drizzle_state_read);
68     return DRIZZLE_RETURN_OK;
69   }
70 
71   if (con->command_total == 0)
72   {
73     con->command= (drizzle_command_t)(con->buffer_ptr[0]);
74     con->buffer_ptr++;
75     con->buffer_size--;
76 
77     con->command_total= (con->packet_size - 1);
78   }
79 
80   if (con->buffer_size < (con->command_total - con->command_offset))
81   {
82     con->command_size= con->buffer_size;
83     con->command_offset+= con->command_size;
84   }
85   else
86   {
87     con->command_size= (con->command_total - con->command_offset);
88     con->command_offset= con->command_total;
89   }
90 
91   con->command_data= con->buffer_ptr;
92   con->buffer_ptr+= con->command_size;
93   con->buffer_size-= con->command_size;
94 
95   if (con->command_offset == con->command_total)
96     drizzle_state_pop(con);
97   else
98     return DRIZZLE_RETURN_PAUSE;
99 
100   return DRIZZLE_RETURN_OK;
101 }
102 
drizzle_state_command_write(drizzle_con_st * con)103 drizzle_return_t drizzle_state_command_write(drizzle_con_st *con)
104 {
105   uint8_t *start;
106   uint8_t *ptr;
107   size_t free_size;
108   drizzle_return_t ret;
109 
110   drizzle_log_debug(con->drizzle, "drizzle_state_command_write");
111 
112   if (con->command_data == NULL && con->command_total != 0 &&
113       con->command != DRIZZLE_COMMAND_CHANGE_USER)
114   {
115     return DRIZZLE_RETURN_PAUSE;
116   }
117 
118   if (con->buffer_size == 0)
119   {
120     con->buffer_ptr= con->buffer;
121     start= con->buffer;
122   }
123   else
124     start= con->buffer_ptr + con->buffer_size;
125 
126   if (con->command_offset == 0)
127   {
128     /* Make sure we can fit the largest non-streaming packet, currently a
129        DRIZZLE_COMMAND_CHANGE_USER command. */
130 
131     con->packet_size= 1  /* Command */
132                     + strlen(con->user) + 1
133                     + 1  /* Scramble size */
134                     + DRIZZLE_MAX_SCRAMBLE_SIZE
135                     + strlen(con->db) + 1;
136 
137     /* Flush buffer if there is not enough room. */
138     free_size= (size_t)DRIZZLE_MAX_BUFFER_SIZE - (size_t)(start - con->buffer);
139     if (free_size < con->packet_size)
140     {
141       drizzle_state_push(con, drizzle_state_write);
142       return DRIZZLE_RETURN_OK;
143     }
144 
145     /* Store packet size at the end since it may change. */
146     con->packet_number= 1;
147     ptr= start;
148     ptr[3]= 0;
149     if (con->options & DRIZZLE_CON_MYSQL)
150       ptr[4]= (uint8_t)(con->command);
151     else
152       ptr[4]= (uint8_t)(_command_drizzle_map[con->command]);
153     ptr+= 5;
154 
155     if (con->command == DRIZZLE_COMMAND_CHANGE_USER)
156     {
157       ptr= drizzle_pack_auth(con, ptr, &ret);
158       if (ret != DRIZZLE_RETURN_OK)
159         return ret;
160 
161       con->buffer_size+= (4 + con->packet_size);
162     }
163     else if (con->command_total == 0)
164     {
165       con->packet_size= 1;
166       con->buffer_size+= 5;
167     }
168     else
169     {
170       con->packet_size= 1 + con->command_total;
171       free_size-= 5;
172 
173       /* Copy as much of the data in as we can into the write buffer. */
174       if (con->command_size <= free_size)
175       {
176         memcpy(ptr, con->command_data, con->command_size);
177         con->command_offset= con->command_size;
178         con->command_data= NULL;
179         con->buffer_size+= 5 + con->command_size;
180       }
181       else
182       {
183         memcpy(ptr, con->command_data, free_size);
184         con->command_offset= free_size;
185         con->command_data+= free_size;
186         con->command_size-= free_size;
187         con->buffer_size+= 5 + free_size;
188       }
189     }
190 
191     /* Store packet size now. */
192     drizzle_set_byte3(start, con->packet_size);
193   }
194   else
195   {
196     /* Write directly from the caller buffer for the rest. */
197     con->buffer_ptr= con->command_data;
198     con->buffer_size= con->command_size;
199     con->command_offset+= con->command_size;
200     con->command_data= NULL;
201   }
202 
203   if (con->command_offset == con->command_total)
204   {
205     drizzle_state_pop(con);
206 
207     if (!(con->options & (DRIZZLE_CON_RAW_PACKET |
208                           DRIZZLE_CON_NO_RESULT_READ)) &&
209         con->command != DRIZZLE_COMMAND_FIELD_LIST)
210     {
211       drizzle_state_push(con, drizzle_state_result_read);
212       drizzle_state_push(con, drizzle_state_packet_read);
213     }
214   }
215 
216   drizzle_state_push(con, drizzle_state_write);
217 
218   return DRIZZLE_RETURN_OK;
219 }
220