/* This file is distributed as part of the SkySQL Gateway. It is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Copyright SkySQL Ab */ //////////////////////////////////////// // SKYSQL Utils // By Massimiliano Pinto 2012/2013 //////////////////////////////////////// #include "skysql_gw.h" #include "apr_sha1.h" #include "apr_general.h" #define MYSQL_PROTOCOL_VERSION41_CHAR '*' #define char_val(X) (X >= '0' && X <= '9' ? X-'0' :\ X >= 'A' && X <= 'Z' ? X-'A'+10 :\ X >= 'a' && X <= 'z' ? X-'a'+10 :\ '\177') char hex_upper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; char hex_lower[] = "0123456789abcdefghijklmnopqrstuvwxyz"; ///////////////////////////////// // binary data to hex string // output must be pre allocated ///////////////////////////////// char *bin2hex(char *out, const uint8_t *in, unsigned int len) { const uint8_t *in_end= in + len; if (len == 0 || in == NULL) { return NULL; } for (; in != in_end; ++in) { *out++= hex_upper[((uint8_t) *in) >> 4]; *out++= hex_upper[((uint8_t) *in) & 0x0F]; } *out= '\0'; return out; } ///////////////////////////////// // hex string to binary data // output must be pre allocated ///////////////////////////////// int hex2bin(uint8_t *out, const char *in, unsigned int len) { const char *in_end= in + len; if (len == 0 || in == NULL) { return 1; } while (in < in_end) { register char tmp_ptr = char_val(*in++); *out++= (tmp_ptr << 4) | char_val(*in++); } return 0; } ///////////////////////////////// // general random string // output must be pre allocated ///////////////////////////////// void skysql_set_random_str(uint8_t *output, unsigned int length) { uint8_t *ptr = output; apr_status_t rv = apr_generate_random_bytes(output, length); // this is for debug, the same scramble for every handshake //strcpy(output, "12345678abcdefjhilmn"); } ///////////////////////////////////////////////////////////// // fill a 20 bytes preallocated with SHA1 digest (160 bits) // for one input on in_len bytes ///////////////////////////////////////////////////////////// void skysql_sha1_str(const uint8_t *in, int in_len, uint8_t *out) { int l; apr_sha1_ctx_t context; apr_byte_t digest[APR_SHA1_DIGESTSIZE]; apr_sha1_init(&context); apr_sha1_update(&context, in, in_len); apr_sha1_final(digest, &context); memcpy(out, digest, APR_SHA1_DIGESTSIZE); } ///////////////////////////////////////////////////////////// // fill 20 bytes preallocated with SHA1 digest (160 bits) // for two inputs, in_len and in2_len bytes ///////////////////////////////////////////////////////////// void skysql_sha1_2_str(const uint8_t *in, int in_len, const uint8_t *in2, int in2_len, uint8_t *out) { int l; apr_sha1_ctx_t context; apr_byte_t digest[APR_SHA1_DIGESTSIZE]; apr_sha1_init(&context); apr_sha1_update(&context, in, in_len); apr_sha1_update(&context, in2, in2_len); apr_sha1_final(digest, &context); memcpy(out, digest, APR_SHA1_DIGESTSIZE); } /////////////////////////////////////////////////////// // fill a preallocated buffer with XOR(str1, str2) // XOR between 2 equal len strings // note that XOR(str1, XOR(str1 CONCAT str2)) == str2 // and that XOR(str1, str2) == XOR(str2, str1) /////////////////////////////////////////////////////// void skysql_str_xor(char *output, const uint8_t *input1, const uint8_t *input2, unsigned int len) { const uint8_t *input1_end = NULL; input1_end = input1 + len; while (input1 < input1_end) *output++= *input1++ ^ *input2++; *output = '\0'; } ////////////////////////////////////////// // get skygateway password from username // output is SHA1(SHA1(password)) ////////////////////////////////////////// char *gateway_find_user_password_sha1(char *username, void *repository, conn_rec *c, apr_pool_t *p) { uint8_t hash1[APR_SHA1_DIGESTSIZE]; uint8_t hash2[APR_SHA1_DIGESTSIZE]; skysql_sha1_str(username, strlen(username), hash1); skysql_sha1_str(hash1, APR_SHA1_DIGESTSIZE, hash2); return apr_pstrmemdup(p, hash2, APR_SHA1_DIGESTSIZE); } ///////////////////////////////////////////// // get the SHA1(SHA1(password)) from client ///////////////////////////////////////////// int skysql_check_scramble(conn_rec *c, apr_pool_t *p, uint8_t *token, unsigned int token_len, uint8_t *scramble, unsigned int scramble_len, char *username, uint8_t *stage1_hash) { uint8_t step1[APR_SHA1_DIGESTSIZE]; uint8_t step2[APR_SHA1_DIGESTSIZE +1]; uint8_t check_hash[APR_SHA1_DIGESTSIZE]; char hex_double_sha1[2 * APR_SHA1_DIGESTSIZE + 1]=""; uint8_t *password = gateway_find_user_password_sha1(username, NULL, c, p); bin2hex(hex_double_sha1, password, APR_SHA1_DIGESTSIZE); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "The Gateway stored hex(SHA1(SHA1(password))) for \"%s\" [%s]", username, hex_double_sha1); // possible, now skipped /* if (password == NULL) { ?????? } */ // step 1 skysql_sha1_2_str(scramble, scramble_len, password, APR_SHA1_DIGESTSIZE, step1); //step2 skysql_str_xor(step2, token, step1, token_len); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "skygateway SHA1(password) [%s]", step2); memcpy(stage1_hash, step2, 20); skysql_sha1_str(step2, APR_SHA1_DIGESTSIZE, check_hash); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SHA1 di SHA1(client password) [%s]", check_hash); if (1) { char inpass[100]=""; bin2hex(inpass, check_hash, 20); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "The CLIENT hex(SHA1(SHA1(password))) for \"%s\" [%s]", username, inpass); } return memcmp(password, check_hash, APR_SHA1_DIGESTSIZE); } apr_status_t gateway_reply_data(conn_rec *c, apr_pool_t *pool, void *data, int len) { apr_status_t rv = APR_SUCCESS; apr_bucket_brigade *bb; apr_bucket_brigade *r_bb; // create brigade bb = apr_brigade_create(pool, c->bucket_alloc); apr_brigade_write(bb, ap_filter_flush, c->output_filters, data, len); ap_fflush(c->output_filters, bb); apr_brigade_destroy(bb); return 1; } apr_status_t skysql_change_user(conn_rec *c, apr_pool_t *p, char *username, char *database, MYSQL_conn *conn, uint8_t *stage1_hash) { uint8_t skysql_payload_size = 0; uint8_t skysql_packet_header[4]; uint8_t skysql_packet_id = 0; uint8_t change_user_command = 0x11; uint8_t *outbuf = NULL; uint8_t token[20 + 1]=""; uint8_t charset[2]=""; uint8_t backend_scramble[20 +1]=""; int user_len = strlen(username); int database_len = strlen(database); uint8_t *password = NULL; uint8_t temp_token[20 +1] =""; uint8_t stage1_password[20 +1] =""; apr_status_t rv = -1; long bytes; //get password from repository password = gateway_find_user_password_sha1(username, NULL, c, p); memcpy(backend_scramble, conn->scramble, 20); skysql_sha1_2_str(backend_scramble, 20, password, 20, temp_token); *token = '\x14'; charset[0]='\x08'; charset[1]='\x00'; skysql_str_xor(token+1, temp_token, stage1_hash, 20); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "skygateway TO backend scramble [%s]", backend_scramble); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "skygateway SHA1(password) [%s]", stage1_hash); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "skygateway internal password [%s]", password); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "skygateway SHA1(scramble + SHA1(stage1_hash)) [%s]", temp_token); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "skygateway TO backend token [%s]", token+1); //skysql_payload_size = 1 + user_len + 1 + sizeof(token) + database_len + 1 + sizeof(charset) + 1 + sizeof("mysql_native_password") + 1; skysql_payload_size = 1 + user_len + 1 + sizeof(token) + database_len + 1 + sizeof(charset); // allocate memory for packet header + payload outbuf = (uint8_t *) apr_pcalloc(p, sizeof(skysql_packet_header) + skysql_payload_size); // write packet header with packet number skysql_set_byte3(skysql_packet_header, skysql_payload_size); skysql_packet_header[3] = skysql_packet_id; memcpy(outbuf, skysql_packet_header, sizeof(skysql_packet_header)); memcpy(outbuf + sizeof(skysql_packet_header), &change_user_command, 1); memcpy(outbuf + sizeof(skysql_packet_header) + 1, username, user_len); memcpy(outbuf + sizeof(skysql_packet_header) + 1 + strlen(username) + 1, token, 21); memcpy(outbuf + sizeof(skysql_packet_header) + 1 + strlen(username) + 1 + 21, database, database_len); memcpy(outbuf + sizeof(skysql_packet_header) + 1 + strlen(username) + 1 + 21 + database_len + 1, charset, sizeof(charset)); //memcpy(outbuf + sizeof(skysql_packet_header) + 1 + strlen(username) + 1 + 21 + database_len + 1 + sizeof(charset) + 1, "mysql_native_password", strlen("mysql_native_password")); bytes = sizeof(skysql_packet_header) + skysql_payload_size; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "skysql_change_user is %li bytes", bytes); rv = apr_socket_send(conn->socket, outbuf, &bytes); } apr_status_t skysql_read_client_autentication(conn_rec *c, apr_pool_t *pool, uint8_t *scramble, int scramble_len, skysql_client_auth *mysql_client_data, uint8_t *stage1_hash) { apr_bucket_brigade *r_bb; apr_bucket *r_b; apr_status_t rv; int seen_eos = 0; int child_stopped_reading = 0; int i; apr_bucket *auth_bucket; apr_bucket *bucket; const char *client_auth_packet = NULL; unsigned int query_ret = 0; int return_data = 0; int input_read = 0; uint8_t client_flags[4]; apr_pool_t *p = NULL; mysql_driver_details *mysql_driver = NULL; uint8_t *token = NULL; unsigned int token_len = 0; int auth_ret = 0; // use the passed pool? p = pool == NULL ? c->pool : pool; // now read the client authentication r_bb = apr_brigade_create(p, c->bucket_alloc); if (((rv = ap_get_brigade(c->input_filters, r_bb, AP_MODE_READBYTES, APR_BLOCK_READ, 8192)) != APR_SUCCESS) || APR_BRIGADE_EMPTY(r_bb)) { apr_brigade_destroy(r_bb); return input_read; } for (auth_bucket = APR_BRIGADE_FIRST(r_bb); bucket != APR_BRIGADE_SENTINEL(r_bb); bucket = APR_BUCKET_NEXT(auth_bucket)) { apr_size_t len; const char *data; if (APR_BUCKET_IS_EOS(auth_bucket)) { seen_eos = 1; break; } if (APR_BUCKET_IS_FLUSH(auth_bucket)) { continue; } if (child_stopped_reading) { break; } rv = apr_bucket_read(auth_bucket, &data, &len, APR_BLOCK_READ); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "Auth Data len [%i]", len); if (rv != APR_SUCCESS) { child_stopped_reading = 1; } client_auth_packet = apr_pstrmemdup(p, data, len); input_read = 1; } // this brigade is useless apr_brigade_destroy(r_bb); if (input_read && client_auth_packet) { // now fill data structure for client data in driver MYSQL5 if (mysql_client_data != NULL) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "Now decode MYSQL client auth packet"); mysql_driver = (mysql_driver_details *)mysql_client_data->driver_details; if (mysql_driver != NULL) { uint8_t hash_stage1[20 +1]; /* uint8_t hash_stage1[20]; uint8_t hash_stage2[20]; uint8_t temp_token[20]; uint8_t client_token[20]; uint8_t check_auth[20]; uint8_t final_hash[20]; */ // todo: insert constant values instead of numbers memcpy(mysql_driver->client_flags, client_auth_packet + 4, 4); mysql_driver->connect_with_db = SKYSQL_CAPABILITIES_CONNECT_WITH_DB & skysql_get_byte4(mysql_driver->client_flags); mysql_driver->compress = SKYSQL_CAPABILITIES_COMPRESS & skysql_get_byte4(mysql_driver->client_flags); mysql_client_data->username = apr_pstrndup(p, client_auth_packet + 4 + 4 + 4 + 1 + 23, 128); memcpy(&token_len, client_auth_packet + 4 + 4 + 4 + 1 + 23 + strlen(mysql_client_data->username) + 1, 1); token = apr_pstrmemdup(p, client_auth_packet + 4 + 4 + 4 + 1 + 23 + strlen(mysql_client_data->username) + 1 + 1, token_len); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "[client TO gateway] current username is [%s], token is [%s] len %i", mysql_client_data->username, token, token_len); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "[gateway TO client] server scramble was [%s], len %i", scramble, scramble_len); /* skysql_sha1_str(mysql_client_data->username, strlen(mysql_client_data->username), hash_stage1); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SHA1 di '%s' [%s]", mysql_client_data->username, hash_stage1); skysql_sha1_str(hash_stage1, 20, hash_stage2); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SHA1 di SHA1('%s') [%s]", mysql_client_data->username, hash_stage2); skysql_sha1_2_str(scramble, scramble_len, hash_stage2, 20, temp_token); skysql_str_xor(check_auth, hash_stage1, temp_token, 20); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "This is the client input?? [%s]", check_auth); memset(temp_token, '\0', sizeof(temp_token)); memcpy(client_token, scramble, scramble_len); memcpy(client_token + scramble_len, hash_stage2, 20); skysql_sha1_str(client_token, scramble_len, temp_token); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "This is the client input?? [%s]", temp_token); skysql_str_xor(check_auth, hash_stage2, hash_stage1, scramble_len); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "XOR( client token, stage2_hash) [%s]", check_auth); skysql_sha1_str(check_auth, 20, final_hash); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SHA1 di check_auth [%s]", final_hash); */ // decode the token and check the password auth_ret = skysql_check_scramble(c, p, token, token_len, scramble, scramble_len, mysql_client_data->username, stage1_hash); if (auth_ret == 0) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SkySQL Gateway Authentication OK for [%s]", mysql_client_data->username); } else { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "**** SkySQL Gateway Authentication ERROR [%s], retcode = [%i]", mysql_client_data->username, auth_ret); } if (mysql_driver->connect_with_db) { mysql_client_data->database = apr_pstrndup(p, client_auth_packet + 4 + 4 + 4 + 1 + 23 + strlen(mysql_client_data->username) + 1 + 1 + token_len, 128); } } } } return input_read; } apr_status_t gateway_send_error (conn_rec *c, apr_pool_t *p, uint8_t packet_number) { apr_status_t rv; rv = APR_SUCCESS; apr_bucket_brigade *bb; apr_bucket *b; uint8_t *outbuf = NULL; uint8_t skysql_payload_size = 0; uint8_t skysql_packet_header[4]; uint8_t *skysql_payload = NULL; uint8_t field_count = 0; uint8_t affected_rows = 0; uint8_t insert_id = 0; uint8_t skysql_err[2]; uint8_t skysql_statemsg[6]; unsigned int skysql_errno = 0; const char *skysql_error_msg = NULL; const char *skysql_state = NULL; skysql_errno = 6969; skysql_error_msg = "Too many queries in one connection"; skysql_state = "FA5D3"; field_count = 0xff; skysql_set_byte2(skysql_err, skysql_errno); skysql_statemsg[0]='#'; memcpy(skysql_statemsg+1, skysql_state, 5); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQL_Error: Errno [%u], ErrorMessage [%s], State [%s]", skysql_errno, skysql_error_msg, skysql_state); skysql_payload_size = sizeof(field_count) + sizeof(skysql_err) + sizeof(skysql_statemsg) + strlen(skysql_error_msg); // allocate memory for packet header + payload outbuf = (uint8_t *) apr_pcalloc(p, sizeof(skysql_packet_header) + skysql_payload_size); // write packet header with packet number skysql_set_byte3(skysql_packet_header, skysql_payload_size); skysql_packet_header[3] = packet_number; // write header memcpy(outbuf, skysql_packet_header, sizeof(skysql_packet_header)); skysql_payload = outbuf + sizeof(skysql_packet_header); // write field memcpy(skysql_payload, &field_count, sizeof(field_count)); skysql_payload = skysql_payload + sizeof(field_count); // write errno memcpy(skysql_payload, skysql_err, sizeof(skysql_err)); skysql_payload = skysql_payload + sizeof(skysql_err); // write sqlstate memcpy(skysql_payload, skysql_statemsg, sizeof(skysql_statemsg)); skysql_payload = skysql_payload + sizeof(skysql_statemsg); // write err messg memcpy(skysql_payload, skysql_error_msg, strlen(skysql_error_msg)); // create brigade bb = apr_brigade_create(p, c->bucket_alloc); b = apr_bucket_pool_create(outbuf, sizeof(skysql_packet_header) + skysql_payload_size, p, c->bucket_alloc); APR_BRIGADE_INSERT_HEAD(bb, b); b = apr_bucket_flush_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); return ap_pass_brigade(c->output_filters, bb); } apr_status_t skysql_send_error (conn_rec *c, uint8_t packet_number, MYSQL_conn *conn) { apr_status_t rv; rv = APR_SUCCESS; apr_bucket_brigade *bb; apr_bucket *b; uint8_t *outbuf = NULL; uint8_t skysql_payload_size = 0; uint8_t skysql_packet_header[4]; uint8_t *skysql_payload = NULL; uint8_t field_count = 0; uint8_t affected_rows = 0; uint8_t insert_id = 0; uint8_t skysql_err[2]; uint8_t skysql_statemsg[6]; unsigned int skysql_errno = 0; const char *skysql_error_msg = NULL; const char *skysql_state = NULL; skysql_errno = mysql_errno(conn); skysql_error_msg = mysql_error(conn); skysql_state = mysql_sqlstate(conn); field_count = 0xff; skysql_set_byte2(skysql_err, skysql_errno); skysql_statemsg[0]='#'; memcpy(skysql_statemsg+1, skysql_state, 5); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQL_Error: Errno [%u], ErrorMessage [%s], State [%s]", skysql_errno, skysql_error_msg, skysql_state); skysql_payload_size = sizeof(field_count) + sizeof(skysql_err) + sizeof(skysql_statemsg) + strlen(skysql_error_msg); // allocate memory for packet header + payload outbuf = (uint8_t *) apr_pcalloc(c->pool, sizeof(skysql_packet_header) + skysql_payload_size); // write packet header with packet number skysql_set_byte3(skysql_packet_header, skysql_payload_size); skysql_packet_header[3] = packet_number; // write header memcpy(outbuf, skysql_packet_header, sizeof(skysql_packet_header)); skysql_payload = outbuf + sizeof(skysql_packet_header); // write field memcpy(skysql_payload, &field_count, sizeof(field_count)); skysql_payload = skysql_payload + sizeof(field_count); // write errno memcpy(skysql_payload, skysql_err, sizeof(skysql_err)); skysql_payload = skysql_payload + sizeof(skysql_err); // write sqlstate memcpy(skysql_payload, skysql_statemsg, sizeof(skysql_statemsg)); skysql_payload = skysql_payload + sizeof(skysql_statemsg); // write err messg memcpy(skysql_payload, skysql_error_msg, strlen(skysql_error_msg)); // create brigade bb = apr_brigade_create(c->pool, c->bucket_alloc); b = apr_bucket_pool_create(outbuf, sizeof(skysql_packet_header) + skysql_payload_size, c->pool, c->bucket_alloc); APR_BRIGADE_INSERT_HEAD(bb, b); b = apr_bucket_flush_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); return ap_pass_brigade(c->output_filters, bb); } apr_status_t skysql_send_result(conn_rec *c, uint8_t *data, uint8_t len) { apr_status_t rv; rv = APR_SUCCESS; apr_bucket_brigade *bb; apr_bucket *b; // create brigade bb = apr_brigade_create(c->pool, c->bucket_alloc); // write apr_brigade_write(bb, ap_filter_flush, c->output_filters, data, len); //send & flush return ap_fflush(c->output_filters, bb); } apr_status_t skysql_send_eof(conn_rec *c, apr_pool_t *p, uint8_t packet_number) { apr_status_t rv; rv = APR_SUCCESS; apr_bucket_brigade *bb; apr_bucket *b; uint8_t *outbuf = NULL; uint8_t skysql_payload_size = 0; uint8_t skysql_packet_header[4]; uint8_t *skysql_payload = NULL; uint8_t field_count = 0; uint8_t skysql_server_status[2]; uint8_t skysql_warning_count[2]; field_count = 0xfe; skysql_payload_size = sizeof(field_count) + sizeof(skysql_server_status) + sizeof(skysql_warning_count); // allocate memory for packet header + payload outbuf = (uint8_t *) apr_pcalloc(p, sizeof(skysql_packet_header) + skysql_payload_size); // write packet header with packet number skysql_set_byte3(skysql_packet_header, skysql_payload_size); skysql_packet_header[3] = packet_number; // write header memcpy(outbuf, skysql_packet_header, sizeof(skysql_packet_header)); skysql_payload = outbuf + sizeof(skysql_packet_header); skysql_server_status[0] = 2; skysql_server_status[1] = 0; skysql_warning_count[0] = 0; skysql_warning_count[1] = 0; // write data memcpy(skysql_payload, &field_count, sizeof(field_count)); skysql_payload = skysql_payload + sizeof(field_count); memcpy(skysql_payload, skysql_warning_count, sizeof(skysql_warning_count)); skysql_payload = skysql_payload + sizeof(skysql_warning_count); memcpy(skysql_payload, skysql_server_status, sizeof(skysql_server_status)); skysql_payload = skysql_payload + sizeof(skysql_server_status); // create brigade bb = apr_brigade_create(p, c->bucket_alloc); // write apr_brigade_write(bb, ap_filter_flush, c->output_filters, outbuf, sizeof(skysql_packet_header) + skysql_payload_size); //send & flush return ap_fflush(c->output_filters, bb); } apr_status_t skysql_send_ok(conn_rec *c, apr_pool_t *p, uint8_t packet_number, uint8_t in_affected_rows, const char* skysql_message) { apr_status_t rv; rv = APR_SUCCESS; apr_bucket_brigade *bb; apr_bucket *b; uint8_t *outbuf = NULL; uint8_t skysql_payload_size = 0; uint8_t skysql_packet_header[4]; uint8_t *skysql_payload = NULL; uint8_t field_count = 0; uint8_t affected_rows = 0; uint8_t insert_id = 0; uint8_t skysql_server_status[2]; uint8_t skysql_warning_count[2]; affected_rows = in_affected_rows; skysql_payload_size = sizeof(field_count) + sizeof(affected_rows) + sizeof(insert_id) + sizeof(skysql_server_status) + sizeof(skysql_warning_count); if (skysql_message != NULL) { skysql_payload_size += strlen(skysql_message); } // allocate memory for packet header + payload outbuf = (uint8_t *) apr_pcalloc(p, sizeof(skysql_packet_header) + skysql_payload_size); // write packet header with packet number skysql_set_byte3(skysql_packet_header, skysql_payload_size); skysql_packet_header[3] = packet_number; // write header memcpy(outbuf, skysql_packet_header, sizeof(skysql_packet_header)); skysql_payload = outbuf + sizeof(skysql_packet_header); skysql_server_status[0] = 2; skysql_server_status[1] = 0; skysql_warning_count[0] = 0; skysql_warning_count[1] = 0; // write data memcpy(skysql_payload, &field_count, sizeof(field_count)); skysql_payload = skysql_payload + sizeof(field_count); memcpy(skysql_payload, &affected_rows, sizeof(affected_rows)); skysql_payload = skysql_payload + sizeof(affected_rows); memcpy(skysql_payload, &insert_id, sizeof(insert_id)); skysql_payload = skysql_payload + sizeof(insert_id); memcpy(skysql_payload, skysql_server_status, sizeof(skysql_server_status)); skysql_payload = skysql_payload + sizeof(skysql_server_status); memcpy(skysql_payload, skysql_warning_count, sizeof(skysql_warning_count)); skysql_payload = skysql_payload + sizeof(skysql_warning_count); if (skysql_message != NULL) { memcpy(skysql_payload, skysql_message, strlen(skysql_message)); } // create brigade bb = apr_brigade_create(p, c->bucket_alloc); /* b = apr_bucket_pool_create(outbuf, sizeof(skysql_packet_header) + skysql_payload_size, c->pool, c->bucket_alloc); APR_BRIGADE_INSERT_HEAD(bb, b); b = apr_bucket_flush_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); return ap_pass_brigade(c->output_filters, bb); */ apr_brigade_write(bb, ap_filter_flush, c->output_filters, outbuf, sizeof(skysql_packet_header) + skysql_payload_size); ap_fflush(c->output_filters, bb); apr_brigade_destroy(bb); return 1; } /////////////////////////// // scramble is 20 bytes and must be pre allocated apr_status_t skysql_send_handshake(conn_rec *c, uint8_t *scramble, int *scramble_len) { apr_status_t rv; rv = APR_SUCCESS; apr_bucket_brigade *bb; apr_bucket *b; apr_pool_t *p = c->pool; uint8_t *outbuf = NULL; uint8_t skysql_payload_size = 0; uint8_t skysql_packet_header[4]; uint8_t skysql_packet_id = 0; uint8_t skysql_filler = SKYSQL_HANDSKAKE_FILLER; uint8_t skysql_protocol_version = SKYSQL_PROTOCOL_VERSION; uint8_t *skysql_handshake_payload = NULL; uint8_t skysql_thread_id[4]; uint8_t skysql_scramble_buf[9] = ""; uint8_t skysql_plugin_data[13] = ""; uint8_t skysql_server_capabilities_one[2]; uint8_t skysql_server_capabilities_two[2]; uint8_t skysql_server_language = 8; uint8_t skysql_server_status[2]; uint8_t skysql_scramble_len = 21; uint8_t skysql_filler_ten[10]; uint8_t skysql_last_byte = 0x00; uint8_t scramble_buffer[20]=""; skysql_set_random_str(scramble_buffer, 20); // set len to the caller memset(scramble_len, 20, 1); // copy back to the caller memcpy(scramble, scramble_buffer, 20); memset(&skysql_filler_ten, 0x00, sizeof(skysql_filler_ten)); // thread id, now put the apache child PID, then a conversion map in memory is needed! skysql_set_byte4(skysql_thread_id, getpid()); memcpy(skysql_scramble_buf, scramble_buffer, 8); memcpy(skysql_plugin_data, scramble_buffer + 8, 12); skysql_payload_size = sizeof(skysql_protocol_version) + (strlen(SKYSQL_VERSION) + 1) + sizeof(skysql_thread_id) + 8 + sizeof(skysql_filler) + sizeof(skysql_server_capabilities_one) + sizeof(skysql_server_language) + sizeof(skysql_server_status) + sizeof(skysql_server_capabilities_two) + sizeof(skysql_scramble_len) + sizeof(skysql_filler_ten) + 12 + sizeof(skysql_last_byte) + strlen("mysql_native_password") + sizeof(skysql_last_byte); // allocate memory for packet header + payload outbuf = (uint8_t *) apr_pcalloc(p, sizeof(skysql_packet_header) + skysql_payload_size); // write packet heder with skysql_payload_size skysql_set_byte3(skysql_packet_header, skysql_payload_size); //skysql_packet_header[0] = skysql_payload_size; // write packent number, now is 0 skysql_packet_header[3]= skysql_packet_id; memcpy(outbuf, skysql_packet_header, sizeof(skysql_packet_header)); // current buffer pointer skysql_handshake_payload = outbuf + sizeof(skysql_packet_header); // write protocol version memcpy(skysql_handshake_payload, &skysql_protocol_version, sizeof(skysql_protocol_version)); skysql_handshake_payload = skysql_handshake_payload + sizeof(skysql_protocol_version); // write server version plus 0 filler strcpy(skysql_handshake_payload, SKYSQL_VERSION); skysql_handshake_payload = skysql_handshake_payload + strlen(SKYSQL_VERSION); *skysql_handshake_payload = 0x00; skysql_handshake_payload++; // write thread id memcpy(skysql_handshake_payload, skysql_thread_id, sizeof(skysql_thread_id)); skysql_handshake_payload = skysql_handshake_payload + sizeof(skysql_thread_id); // write scramble buf memcpy(skysql_handshake_payload, skysql_scramble_buf, 8); skysql_handshake_payload = skysql_handshake_payload + 8; *skysql_handshake_payload = SKYSQL_HANDSKAKE_FILLER; skysql_handshake_payload++; // write server capabilities part one skysql_server_capabilities_one[0] = SKYSQL_SERVER_CAPABILITIES_BYTE1; skysql_server_capabilities_one[1] = SKYSQL_SERVER_CAPABILITIES_BYTE2; memcpy(skysql_handshake_payload, skysql_server_capabilities_one, sizeof(skysql_server_capabilities_one)); skysql_handshake_payload = skysql_handshake_payload + sizeof(skysql_server_capabilities_one); // write server language memcpy(skysql_handshake_payload, &skysql_server_language, sizeof(skysql_server_language)); skysql_handshake_payload = skysql_handshake_payload + sizeof(skysql_server_language); //write server status skysql_server_status[0] = 2; skysql_server_status[1] = 0; memcpy(skysql_handshake_payload, skysql_server_status, sizeof(skysql_server_status)); skysql_handshake_payload = skysql_handshake_payload + sizeof(skysql_server_status); //write server capabilities part two skysql_server_capabilities_two[0] = 15; skysql_server_capabilities_two[1] = 128; //skysql_server_capabilities_two[0] & SKYSQL_CAPABILITIES_COMPRESS; memcpy(skysql_handshake_payload, skysql_server_capabilities_two, sizeof(skysql_server_capabilities_two)); skysql_handshake_payload = skysql_handshake_payload + sizeof(skysql_server_capabilities_two); // write scramble_len memcpy(skysql_handshake_payload, &skysql_scramble_len, sizeof(skysql_scramble_len)); skysql_handshake_payload = skysql_handshake_payload + sizeof(skysql_scramble_len); //write 10 filler memcpy(skysql_handshake_payload, skysql_filler_ten, sizeof(skysql_filler_ten)); skysql_handshake_payload = skysql_handshake_payload + sizeof(skysql_filler_ten); // write plugin data memcpy(skysql_handshake_payload, skysql_plugin_data, 12); skysql_handshake_payload = skysql_handshake_payload + 12; //write last byte, 0 *skysql_handshake_payload = 0x00; skysql_handshake_payload++; // to be understanded ???? memcpy(skysql_handshake_payload, "mysql_native_password", strlen("mysql_native_password")); skysql_handshake_payload = skysql_handshake_payload + strlen("mysql_native_password"); //write last byte, 0 *skysql_handshake_payload = 0x00; skysql_handshake_payload++; // create brigade bb = apr_brigade_create(p, c->bucket_alloc); /* b = apr_bucket_pool_create(outbuf, sizeof(skysql_packet_header) + skysql_payload_size, p, c->bucket_alloc); APR_BRIGADE_INSERT_HEAD(bb, b); b = apr_bucket_flush_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); ap_pass_brigade(c->output_filters, bb); apr_brigade_destroy(bb); */ apr_brigade_write(bb, ap_filter_flush, c->output_filters, outbuf, sizeof(skysql_packet_header) + skysql_payload_size); ap_fflush(c->output_filters, bb); apr_brigade_destroy(bb); return 1; } int skygateway_query_result(conn_rec *c, apr_pool_t *p, MYSQL_conn *conn, const char *query) { int query_ret = 0; int num_fields = 0; int return_data = 0; uint8_t result_column_count = 0; uint8_t header_result_packet[4]; apr_bucket_brigade *bb1; apr_bucket *b1; uint8_t *outbuf = NULL; apr_status_t rv; uint8_t buffer[MAX_CHUNK]; unsigned long bytes = MAX_CHUNK; unsigned long tot_bytes = 0; int cycle=0; apr_pollset_t *pset; apr_pollfd_t pfd; apr_int32_t nsocks=1; apr_status_t poll_rv; int is_eof = 0; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW is sending query to backend [%lu] ...", conn->tid); // send the query to the backend query_ret = mysql_query(conn, query); if (query_ret) { // send error, packet #1 skysql_send_error(c, 1, conn); return 1; } //poll_rv = apr_pollset_create(&pset, 1, p, 0); //pfd.p = p; //pfd.desc_type = APR_POLL_SOCKET; //pfd.reqevents = APR_POLLIN; //pfd.rtnevents = APR_POLLIN; //pfd.desc.s = conn->socket; //pfd.client_data = NULL; //rv = apr_pollset_add(pset, &pfd); //rv = apr_socket_opt_set(conn->socket, APR_SO_NONBLOCK , 1); apr_socket_timeout_set(conn->socket, 100000000); // read query resut from backend ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW is receiving query result from backend ..."); while(1) { char errmesg_p[1000]=""; bytes=MAX_CHUNK; memset(buffer, '\0', MAX_CHUNK); //rv = apr_wait_for_io_or_timeout(NULL, conn->socket, 1); //fprintf(stderr, "wait socket recv %lu\n", bytes); //apr_strerror(rv, errmesg_p, sizeof(errmesg_p)); //fprintf(stderr, "wait Errore in recv, rv is %i, [%s]\n", rv, errmesg_p); //fflush(stderr); //apr_socket_atreadeof(conn->socket, &is_eof); rv = apr_socket_recv(conn->socket, buffer, &bytes); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW received %lu bytes", bytes); if (rv) { if (APR_STATUS_IS_EAGAIN(rv)) { continue; } } tot_bytes += bytes; if (rv != APR_SUCCESS && rv != APR_EOF && rv != APR_EAGAIN) { char errmesg[1000]=""; apr_strerror(rv, errmesg, sizeof(errmesg)); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive error %i, [%s]", rv, errmesg); return 1; } if (rv == APR_EOF && bytes == 0) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive error: EOF"); } bb1 = apr_brigade_create(p, c->bucket_alloc); apr_brigade_write(bb1, ap_filter_flush, c->output_filters, buffer, bytes); ap_fflush(c->output_filters, bb1); apr_brigade_destroy(bb1); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive, brigade sent to the client with %li bytes", bytes); cycle++; if (bytes < MAX_CHUNK) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive: less bytes than buffer here, Query Result: total bytes %lu in %i", tot_bytes, cycle); return 0; } if (bytes == MAX_CHUNK) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive: ALL bytes in the buffer here, continue"); } } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive: Return from query result: total bytes %lu in %i", tot_bytes, cycle); return 0; } int skygateway_statement_prepare_result(conn_rec *c, apr_pool_t *p, MYSQL_conn *conn, const char *query, int len) { int query_ret = 0; int num_fields = 0; int return_data = 0; uint8_t result_column_count = 0; uint8_t header_result_packet[4]; apr_bucket_brigade *bb1; apr_bucket *b1; uint8_t *outbuf = NULL; apr_status_t rv; uint8_t buffer[MAX_CHUNK]; unsigned long bytes = MAX_CHUNK; unsigned long tot_bytes = 0; int cycle=0; apr_pollset_t *pset; apr_pollfd_t pfd; apr_int32_t nsocks=1; apr_status_t poll_rv; int is_eof = 0; query_ret = mysql_send_command(conn, query, 0x16, len); if (query_ret) { // send error, packet #1 skysql_send_error(c, 1, conn); return 1; } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW is sending result set ..."); poll_rv = apr_pollset_create(&pset, 1, p, 0); pfd.p = p; pfd.desc_type = APR_POLL_SOCKET; pfd.reqevents = APR_POLLIN; pfd.rtnevents = APR_POLLIN; pfd.desc.s = conn->socket; pfd.client_data = NULL; //rv = apr_pollset_add(pset, &pfd); //rv = apr_socket_opt_set(conn->socket, APR_SO_NONBLOCK , 1); apr_socket_timeout_set(conn->socket, 100000000); while(1) { char errmesg_p[1000]=""; bytes=MAX_CHUNK; memset(buffer, '\0', MAX_CHUNK); //rv = apr_wait_for_io_or_timeout(NULL, conn->socket, 1); //fprintf(stderr, "wait socket recv %lu\n", bytes); //apr_strerror(rv, errmesg_p, sizeof(errmesg_p)); //fprintf(stderr, "wait Errore in recv, rv is %i, [%s]\n", rv, errmesg_p); //fflush(stderr); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW is receiving ..."); //apr_socket_atreadeof(conn->socket, &is_eof); rv = apr_socket_recv(conn->socket, buffer, &bytes); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW received %lu bytes", bytes); if (rv) { if (APR_STATUS_IS_EAGAIN(rv)) { continue; } } tot_bytes += bytes; if (rv != APR_SUCCESS && rv != APR_EOF && rv != APR_EAGAIN) { char errmesg[1000]=""; apr_strerror(rv, errmesg, sizeof(errmesg)); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive error %i, [%s]", rv, errmesg); return 1; } if (rv == APR_EOF && bytes == 0) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive error: EOF"); } bb1 = apr_brigade_create(p, c->bucket_alloc); apr_brigade_write(bb1, ap_filter_flush, c->output_filters, buffer, bytes); ap_fflush(c->output_filters, bb1); apr_brigade_destroy(bb1); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive, brigade sent with %li bytes", bytes); cycle++; if (bytes < MAX_CHUNK) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive: less bytes than buffer here, Return from query result: total bytes %lu in %i", tot_bytes, cycle); return 0; } if (bytes == MAX_CHUNK) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive: ALL bytes in the buffer here, continue"); } } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive: Return from query result: total bytes %lu in %i", tot_bytes, cycle); return 0; } int skygateway_statement_execute_result(conn_rec *c, apr_pool_t *p, MYSQL_conn *conn, const char *query, int len) { int query_ret = 0; int num_fields = 0; int return_data = 0; uint8_t result_column_count = 0; uint8_t header_result_packet[4]; apr_bucket_brigade *bb1; apr_bucket *b1; uint8_t *outbuf = NULL; apr_status_t rv; uint8_t buffer[MAX_CHUNK]; unsigned long bytes = MAX_CHUNK; unsigned long tot_bytes = 0; int cycle=0; apr_pollset_t *pset; apr_pollfd_t pfd; apr_int32_t nsocks=1; apr_status_t poll_rv; int is_eof = 0; query_ret = mysql_send_command(conn, query, 0x17, len); if (query_ret) { // send error, packet #1 skysql_send_error(c, 1, conn); return 1; } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW is sending result set ..."); poll_rv = apr_pollset_create(&pset, 1, p, 0); pfd.p = p; pfd.desc_type = APR_POLL_SOCKET; pfd.reqevents = APR_POLLIN; pfd.rtnevents = APR_POLLIN; pfd.desc.s = conn->socket; pfd.client_data = NULL; //rv = apr_pollset_add(pset, &pfd); //rv = apr_socket_opt_set(conn->socket, APR_SO_NONBLOCK , 1); apr_socket_timeout_set(conn->socket, 100000000); while(1) { char errmesg_p[1000]=""; bytes=MAX_CHUNK; memset(buffer, '\0', MAX_CHUNK); //rv = apr_wait_for_io_or_timeout(NULL, conn->socket, 1); //fprintf(stderr, "wait socket recv %lu\n", bytes); //apr_strerror(rv, errmesg_p, sizeof(errmesg_p)); //fprintf(stderr, "wait Errore in recv, rv is %i, [%s]\n", rv, errmesg_p); //fflush(stderr); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW is receiving ..."); //apr_socket_atreadeof(conn->socket, &is_eof); rv = apr_socket_recv(conn->socket, buffer, &bytes); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW received %lu bytes", bytes); if (rv) { if (APR_STATUS_IS_EAGAIN(rv)) { continue; } } tot_bytes += bytes; if (rv != APR_SUCCESS && rv != APR_EOF && rv != APR_EAGAIN) { char errmesg[1000]=""; apr_strerror(rv, errmesg, sizeof(errmesg)); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive error %i, [%s]", rv, errmesg); return 1; } if (rv == APR_EOF && bytes == 0) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive error: EOF"); } bb1 = apr_brigade_create(p, c->bucket_alloc); apr_brigade_write(bb1, ap_filter_flush, c->output_filters, buffer, bytes); ap_fflush(c->output_filters, bb1); apr_brigade_destroy(bb1); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive, brigade sent with %li bytes", bytes); cycle++; if (bytes < MAX_CHUNK) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive: less bytes than buffer here, Return from query result: total bytes %lu in %i", tot_bytes, cycle); return 0; } if (bytes == MAX_CHUNK) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive: ALL bytes in the buffer here, continue"); } } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive: Return from query result: total bytes %lu in %i", tot_bytes, cycle); return 0; } int mysql_send_command(MYSQL_conn *conn, const char *command, int cmd, int len) { apr_status_t rv; //uint8_t *packet_buffer=NULL; uint8_t packet_buffer[SMALL_CHUNK]; long bytes; int fd; //packet_buffer = (uint8_t *) calloc(1, 5 + len + 1); memset(&packet_buffer, '\0', sizeof(packet_buffer)); packet_buffer[4]= cmd; memcpy(packet_buffer+5, command, len); skysql_set_byte3(packet_buffer, 1 + len); bytes = 4 + 1 + len; #ifdef MYSQL_CONN_DEBUG fprintf(stderr, "THE COMMAND is [%s] len %i\n", command, bytes); fprintf(stderr, "THE COMMAND TID is [%lu]", conn->tid); fprintf(stderr, "THE COMMAND scramble is [%s]", conn->scramble); if (conn->socket == NULL) { fprintf(stderr, "***** THE COMMAND sock struct is NULL\n"); } fwrite(packet_buffer, bytes, 1, stderr); fflush(stderr); #endif apr_os_sock_get(&fd,conn->socket); #ifdef MYSQL_CONN_DEBUG fprintf(stderr, "COMMAND Socket FD is %i\n", fd); fflush(stderr); #endif rv = apr_socket_send(conn->socket, packet_buffer, &bytes); #ifdef MYSQL_CONN_DEBUG fprintf(stderr, "COMMAND SENT [%x] [%s]\n", cmd, command); fflush(stderr); #endif if (rv != APR_SUCCESS) { return 1; } return 0; } int mysql_pass_packet(MYSQL_conn *conn, const char *command, int len) { apr_status_t rv; //uint8_t *packet_buffer=NULL; uint8_t packet_buffer[SMALL_CHUNK]; long bytes; int fd; //packet_buffer = (uint8_t *) calloc(1, 5 + len + 1); memset(&packet_buffer, '\0', sizeof(packet_buffer)); memcpy(packet_buffer, command, len); bytes = len; #ifdef MYSQL_CONN_DEBUG fprintf(stderr, "THE COMMAND is [%s] len %i\n", command, bytes); fprintf(stderr, "THE COMMAND TID is [%lu]", conn->tid); fprintf(stderr, "THE COMMAND scramble is [%s]", conn->scramble); if (conn->socket == NULL) { fprintf(stderr, "***** THE COMMAND sock struct is NULL\n"); } fwrite(packet_buffer, bytes, 1, stderr); fflush(stderr); #endif apr_os_sock_get(&fd,conn->socket); #ifdef MYSQL_CONN_DEBUG fprintf(stderr, "PACKET Socket FD is %i\n", fd); fflush(stderr); #endif rv = apr_socket_send(conn->socket, packet_buffer, &bytes); #ifdef MYSQL_CONN_DEBUG fprintf(stderr, "PACKET SENT [%s]\n", command); fflush(stderr); #endif if (rv != APR_SUCCESS) { return 1; } return 0; } int mysql_receive_packet(conn_rec *c, apr_pool_t *p, MYSQL_conn *conn) { apr_bucket_brigade *bb1; apr_bucket *b1; apr_status_t rv; uint8_t buffer[MAX_CHUNK]; unsigned long bytes = MAX_CHUNK; unsigned long tot_bytes = 0; int cycle=0; int is_eof = 0; apr_socket_timeout_set(conn->socket, 100000000); while(1) { char errmesg_p[1000]=""; bytes=MAX_CHUNK; memset(buffer, '\0', MAX_CHUNK); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW is receiving ..."); rv = apr_socket_recv(conn->socket, buffer, &bytes); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW received %lu bytes", bytes); if (rv) { if (APR_STATUS_IS_EAGAIN(rv)) { continue; } } tot_bytes += bytes; if (rv != APR_SUCCESS && rv != APR_EOF && rv != APR_EAGAIN) { char errmesg[1000]=""; apr_strerror(rv, errmesg, sizeof(errmesg)); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive error %i, [%s]", rv, errmesg); return 1; } if (rv == APR_EOF && bytes == 0) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive error: EOF"); } bb1 = apr_brigade_create(p, c->bucket_alloc); apr_brigade_write(bb1, ap_filter_flush, c->output_filters, buffer, bytes); ap_fflush(c->output_filters, bb1); apr_brigade_destroy(bb1); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive, brigade sent with %li bytes", bytes); cycle++; if (bytes < MAX_CHUNK) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive: less bytes than buffer here, Return from query result: total bytes %lu in %i", tot_bytes, cycle); return 0; } if (bytes == MAX_CHUNK) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive: ALL bytes in the buffer here, continue"); } } ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, c->base_server, "SKYSQLGW receive: Return from query result: total bytes %lu in %i", tot_bytes, cycle); return 0; } backend_list select_backend_servers() { backend_list l; memset(&l, '\0', sizeof(backend_list)); l.num = 2; l.list = "127.0.0.1:3307,127.0.0.1:3306,xxxx:11"; return l; }