1 /* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #ifndef MYSQL_ASYNC_INCLUDED
24 #define MYSQL_ASYNC_INCLUDED
25 
26 #include <mysql.h>
27 
28 /**
29   @file mysql_async.h
30 
31   Declarations for asynchronous client communication.
32 
33   @note this file should not be included as part of packaging.
34 */
35 
36 /**
37   This enum is to represent different asynchronous operations like reading the
38   network, writing to network, idle state, or complete state.
39 */
40 enum net_async_operation {
41   NET_ASYNC_OP_IDLE = 0, /**< default state */
42   NET_ASYNC_OP_READING,  /**< used by my_net_read calls */
43   NET_ASYNC_OP_WRITING,  /**< used by my_net_write calls */
44   NET_ASYNC_OP_COMPLETE  /**< network read or write is complete */
45 };
46 
47 /** Reading a packet is a multi-step process, so we have a state machine. */
48 enum net_async_read_packet_state {
49   NET_ASYNC_PACKET_READ_IDLE = 0, /**< default packet read state */
50   NET_ASYNC_PACKET_READ_HEADER,   /**< read packet header */
51   NET_ASYNC_PACKET_READ_BODY,     /**< read packet contents */
52   NET_ASYNC_PACKET_READ_COMPLETE  /**< state to define if packet is
53                                        completely read */
54 };
55 
56 /** Different states when reading a query result. */
57 enum net_read_query_result_status {
58   NET_ASYNC_READ_QUERY_RESULT_IDLE = 0,    /**< default state */
59   NET_ASYNC_READ_QUERY_RESULT_FIELD_COUNT, /**< read Ok or read field
60                                                 count sent as part of
61                                                 COM_QUERY */
62   NET_ASYNC_READ_QUERY_RESULT_FIELD_INFO   /**< read result of above
63                                                 COM_* command */
64 };
65 
66 /** Sending a command involves the write as well as reading the status. */
67 enum net_send_command_status {
68   NET_ASYNC_SEND_COMMAND_IDLE = 0,      /**< default send command state */
69   NET_ASYNC_SEND_COMMAND_WRITE_COMMAND, /**< send COM_* command */
70   NET_ASYNC_SEND_COMMAND_READ_STATUS    /**< read result of above COM_*
71                                              command */
72 };
73 
74 /**
75   Async operations are broadly classified into 3 phases:
76   Connection phase, phase of sending data to server (which is writing phase)
77   and reading data from server (which is reading phase). Below enum describes
78   the same
79 */
80 enum net_async_block_state {
81   NET_NONBLOCKING_CONNECT = 0,
82   NET_NONBLOCKING_READ,
83   NET_NONBLOCKING_WRITE
84 };
85 
86 /**
87   Represents the packet to be sent on wire asynchronously.
88 */
89 struct io_vec {
90   void *iov_base; /**< Starting address */
91   size_t iov_len; /**< Number of bytes to transfer */
92 };
93 
94 typedef struct NET_ASYNC {
95   /**
96     The position in buff we continue reads from when data is next
97     available
98   */
99   unsigned char *cur_pos;
100   /** Blocking state */
101   enum net_async_block_state async_blocking_state;
102   /** Our current operation */
103   enum net_async_operation async_operation;
104   /** How many bytes we want to read */
105   size_t async_bytes_wanted;
106   /**
107     Simple state to know if we're reading the first row, and
108     command/query statuses.
109   */
110   bool read_rows_is_first_read;
111   enum net_send_command_status async_send_command_status;
112   enum net_read_query_result_status async_read_query_result_status;
113 
114   /** State when waiting on an async read */
115   enum net_async_read_packet_state async_packet_read_state;
116   /** Size of the packet we're currently reading */
117   size_t async_packet_length;
118 
119   /**
120     Headers and vector for our async writes; see net_serv.c for
121     detailed description.
122   */
123   unsigned char *async_write_headers;
124   struct io_vec *async_write_vector;
125   size_t async_write_vector_size;
126   size_t async_write_vector_current;
127 
128   /**
129     If the packet length is less than MAX_PACKET_LENGTH then use a static array
130     to hold the meta packet header. The array either holds the usual packet
131     header or a compressed meta packet header as following. The compressed
132     meta packet header is followwed by usual compresses packet heder that is
133     7 bytes in length.
134 
135 
136     Packet
137 
138         Header
139     ~~~~~~~~~~~~~~~~~~~
140     B1 B2 B3  : Packet length
141     B4        : Packet number
142     ~~~~~~~~~~~~~~~~~~~
143 
144         Payload
145     ~~~~~~~~~~~~~~~~~~~
146     B5        : COM_COMMAND
147     ~~~~~~~~~~~~~~~~~~~
148 
149     Compressed Packet
150 
151         Header
152     ~~~~~~~~~~~~~~~~~~~
153     B1 B2 B3  : Compress packet length
154     B4        : Compress Packet Nunmber
155     00 00 00  : Indicates following payload is uncompressed
156     ~~~~~~~~~~~~~~~~~~~
157 
158         Payload
159     ~~~~~~~~~~~~~~~~~~~
160     B8 B9 B10 : Packet size
161     B11       : Packet number
162     B12       : COM_COMMAND
163     ~~~~~~~~~~~~~~~~~~~
164   */
165   unsigned char inline_async_write_header[NET_HEADER_SIZE + COMP_HEADER_SIZE +
166                                           NET_HEADER_SIZE + 1];
167   struct io_vec inline_async_write_vector[3];
168 
169   /** Keep track of compressed buffers */
170   unsigned char **compressed_write_buffers;
171   /** Size of the compressed buffer */
172   size_t compressed_buffers_size;
173 } NET_ASYNC;
174 
175 struct NET_EXTENSION {
176   NET_ASYNC *net_async_context;
177   mysql_compress_context compress_ctx;
178 };
179 
180 NET_EXTENSION *net_extension_init();
181 void net_extension_free(NET *);
182 
183 #define NET_EXTENSION_PTR(N) \
184   ((NET_EXTENSION *)((N)->extension ? (N)->extension : NULL))
185 
186 #define NET_ASYNC_DATA(M) \
187   ((NET_EXTENSION_PTR(M)) ? (NET_EXTENSION_PTR(M)->net_async_context) : NULL)
188 
189 /**
190   Asynchronous operations are broadly classified into 2 categories.
191   1. Connection
192   2. Query execution
193   This classification is defined in below enum
194 */
195 enum mysql_async_operation_status {
196   ASYNC_OP_UNSET = 0,
197   ASYNC_OP_CONNECT,
198   ASYNC_OP_QUERY
199 };
200 
201 /**
202   Query execution in an asynchronous fashion is broadly divided into 3 states
203   which is described in below enum
204 */
205 enum mysql_async_query_state_enum {
206   QUERY_IDLE = 0,
207   QUERY_SENDING,
208   QUERY_READING_RESULT
209 };
210 
211 typedef struct MYSQL_ASYNC {
212   /** Buffer storing the rows result for cli_read_rows_nonblocking */
213   MYSQL_DATA *rows_result_buffer;
214   /** a pointer to keep track of the previous row of the current result row */
215   MYSQL_ROWS **prev_row_ptr;
216   /** Context needed to track the state of a connection being established */
217   struct mysql_async_connect *connect_context;
218   /** Status of the current async op */
219   enum mysql_async_operation_status async_op_status;
220   /** Size of the current running async query */
221   size_t async_query_length;
222   /** If a query is running, this is its state */
223   enum mysql_async_query_state_enum async_query_state;
224   /** context needed to support metadata read operation */
225   unsigned long *async_read_metadata_field_len;
226   MYSQL_FIELD *async_read_metadata_fields;
227   MYSQL_ROWS async_read_metadata_data;
228   unsigned int async_read_metadata_cur_field;
229   /** a pointer to keep track of the result sets */
230   struct MYSQL_RES *async_store_result_result;
231 } MYSQL_ASYNC;
232 
233 enum net_async_status my_net_write_nonblocking(NET *net,
234                                                const unsigned char *packet,
235                                                size_t len, bool *res);
236 enum net_async_status net_write_command_nonblocking(
237     NET *net, unsigned char command, const unsigned char *prefix,
238     size_t prefix_len, const unsigned char *packet, size_t packet_len,
239     bool *res);
240 enum net_async_status my_net_read_nonblocking(NET *net, unsigned long *len_ptr);
241 
242 int mysql_get_socket_descriptor(MYSQL *mysql);
243 
244 #endif /* MYSQL_ASYNC_INCLUDED */
245