📄 mysqlnd_wireprotocol.c
字号:
const unsigned char *s1_end= s1 + len; while (s1 < s1_end) { *buffer++= *s1++ ^ *s2++; }}/* }}} *//* {{{ php_mysqlnd_scramble */void php_mysqlnd_scramble(zend_uchar * const buffer, const zend_uchar * const scramble, const zend_uchar * const password){ PHP_SHA1_CTX context; unsigned char sha1[SHA1_MAX_LENGTH]; unsigned char sha2[SHA1_MAX_LENGTH]; /* Phase 1: hash password */ PHP_SHA1Init(&context); PHP_SHA1Update(&context, password, strlen((char *)password)); PHP_SHA1Final(sha1, &context); /* Phase 2: hash sha1 */ PHP_SHA1Init(&context); PHP_SHA1Update(&context, (unsigned char*)sha1, SHA1_MAX_LENGTH); PHP_SHA1Final(sha2, &context); /* Phase 3: hash scramble + sha2 */ PHP_SHA1Init(&context); PHP_SHA1Update(&context, scramble, SCRAMBLE_LENGTH); PHP_SHA1Update(&context, (unsigned char*)sha2, SHA1_MAX_LENGTH); PHP_SHA1Final(buffer, &context); /* let's crypt buffer now */ php_mysqlnd_crypt(buffer, (const unsigned char *)buffer, (const unsigned char *)sha1, SHA1_MAX_LENGTH);}/* }}} *//* {{{ php_mysqlnd_auth_write */staticsize_t php_mysqlnd_auth_write(void *_packet, MYSQLND *conn TSRMLS_DC){ char buffer[1024]; register char *p= buffer + MYSQLND_HEADER_SIZE; /* start after the header */ int len; register php_mysql_packet_auth *packet= (php_mysql_packet_auth *) _packet; packet->client_flags |= MYSQLND_CAPABILITIES; if (packet->db) { packet->client_flags |= CLIENT_CONNECT_WITH_DB; } if (PG(open_basedir) && strlen(PG(open_basedir))) { packet->client_flags ^= CLIENT_LOCAL_FILES; } /* don't allow multi_queries via connect parameter */ packet->client_flags ^= CLIENT_MULTI_STATEMENTS; int4store(p, packet->client_flags); p+= 4; int4store(p, packet->max_packet_size); p+= 4; int1store(p, packet->charset_no); p++; memset(p, 0, 23); /* filler */ p+= 23; len= strlen(packet->user); strncpy(p, packet->user, len); p+= len; *p++ = '\0'; /* copy scrambled pass*/ if (packet->password && packet->password[0]) { /* In 4.1 we use CLIENT_SECURE_CONNECTION and thus the len of the buf should be passed */ int1store(p, 20); p++; php_mysqlnd_scramble((unsigned char*)p, packet->server_scramble_buf, (unsigned char *)packet->password); p+= 20; } else { /* Zero length */ int1store(p, 0); p++; } if (packet->db) { memcpy(p, packet->db, packet->db_len); p+= packet->db_len; *p++= '\0'; } /* Handle CLIENT_CONNECT_WITH_DB */ /* no \0 for no DB */ return mysqlnd_stream_write_w_header(conn, buffer, p - buffer - MYSQLND_HEADER_SIZE TSRMLS_CC);}/* }}} *//* {{{ php_mysqlnd_auth_free_mem */staticvoid php_mysqlnd_auth_free_mem(void *_packet, zend_bool alloca){ if (!alloca) { efree((php_mysql_packet_auth *) _packet); }}/* }}} *//* {{{ php_mysqlnd_ok_read */static enum_func_statusphp_mysqlnd_ok_read(void *_packet, MYSQLND *conn TSRMLS_DC){ zend_uchar buf[1024]; zend_uchar *p= buf; int i; register php_mysql_packet_ok *packet= (php_mysql_packet_ok *) _packet; PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "OK"); /* Should be always 0x0 or 0xFF for error */ packet->field_count= uint1korr(p); p++; if (0xFF == packet->field_count) { php_mysqlnd_read_error_from_line(p, packet->header.size - 1, packet->error, sizeof(packet->error), &packet->error_no, packet->sqlstate); return PASS; } /* Everything was fine! */ packet->affected_rows = php_mysqlnd_net_field_length_ll(&p); packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p); packet->server_status = uint2korr(p); p+= 2; packet->warning_count = uint2korr(p); p+= 2; /* There is a message */ if (packet->header.size > p - buf && (i = php_mysqlnd_net_field_length(&p))) { packet->message = estrndup((char *)p, MIN(i, sizeof(buf) - (p - buf))); packet->message_len = i; } else { packet->message = NULL; } return PASS;}/* }}} *//* {{{ php_mysqlnd_ok_free_mem */staticvoid php_mysqlnd_ok_free_mem(void *_packet, zend_bool alloca){ php_mysql_packet_ok *p= (php_mysql_packet_ok *) _packet; if (p->message) { efree(p->message); p->message = NULL; } if (!alloca) { efree(p); }}/* }}} *//* {{{ php_mysqlnd_eof_read */static enum_func_statusphp_mysqlnd_eof_read(void *_packet, MYSQLND *conn TSRMLS_DC){ /* EOF packet is since 4.1 five bytes long, but we can get also an error, make it bigger. Error : error_code + '#' + sqlstate + MYSQLND_ERRMSG_SIZE */ php_mysql_packet_eof *packet= (php_mysql_packet_eof *) _packet; zend_uchar buf[5 + 10 + sizeof(packet->sqlstate) + sizeof(packet->error)]; zend_uchar *p= buf; PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "EOF"); /* Should be always 0xFE */ packet->field_count= uint1korr(p); p++; if (0xFF == packet->field_count) { php_mysqlnd_read_error_from_line(p, packet->header.size - 1, packet->error, sizeof(packet->error), &packet->error_no, packet->sqlstate); return PASS; } packet->warning_count = uint2korr(p); p+= 2; packet->server_status = uint2korr(p); return PASS;}/* }}} *//* {{{ php_mysqlnd_eof_free_mem */staticvoid php_mysqlnd_eof_free_mem(void *_packet, zend_bool alloca){ if (!alloca) { efree(_packet); }}/* }}} *//* {{{ php_mysqlnd_cmd_write */size_t php_mysqlnd_cmd_write(void *_packet, MYSQLND *conn TSRMLS_DC){ /* Let's have some space, which we can use, if not enough, we will allocate new buffer */ php_mysql_packet_command *packet= (php_mysql_packet_command *) _packet; MYSQLND_NET *net = &conn->net; /* Reset packet_no, or we will get bad handshake! Every command starts a new TX and packet numbers are reset to 0. */ net->packet_no = 0;#if MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND php_mysqlnd_consume_uneaten_data(conn, packet->command TSRMLS_CC);#endif if (!packet->argument || !packet->arg_len) { char buffer[MYSQLND_HEADER_SIZE + 1]; int1store(buffer + MYSQLND_HEADER_SIZE, packet->command); return mysqlnd_stream_write_w_header(conn, buffer, 1 TSRMLS_CC); } else {#if USE_CORK && defined(TCP_CORK) return mysqlnd_stream_write_w_command(conn, packet->command, packet->argument, packet->arg_len TSRMLS_CC);#else size_t tmp_len = packet->arg_len + 1 + MYSQLND_HEADER_SIZE, ret; zend_uchar *tmp, *p; tmp = (tmp_len > net->cmd_buffer.length)? emalloc(tmp_len):net->cmd_buffer.buffer; p = tmp + MYSQLND_HEADER_SIZE; /* skip the header */ int1store(p, packet->command); p++; memcpy(p, packet->argument, packet->arg_len); ret = mysqlnd_stream_write_w_header(conn, (char *)tmp, tmp_len - MYSQLND_HEADER_SIZE TSRMLS_CC); if (tmp != net->cmd_buffer.buffer) { MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_CMD_BUFFER_TOO_SMALL); efree(tmp); } return ret;#endif }}/* }}} *//* {{{ php_mysqlnd_cmd_free_mem */staticvoid php_mysqlnd_cmd_free_mem(void *_packet, zend_bool alloca){ if (!alloca) { efree((php_mysql_packet_command *) _packet); }}/* }}} *//* {{{ php_mysqlnd_rset_header_read */static enum_func_statusphp_mysqlnd_rset_header_read(void *_packet, MYSQLND *conn TSRMLS_DC){ zend_uchar buf[1024]; zend_uchar *p= buf; size_t len; php_mysql_packet_rset_header *packet= (php_mysql_packet_rset_header *) _packet; PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "resultset header"); /* Don't increment. First byte is 0xFF on error, but otherwise is starting byte of encoded sequence for length. */ if (*p == 0xFF) { /* Error */ p++; php_mysqlnd_read_error_from_line(p, packet->header.size - 1, packet->error_info.error, sizeof(packet->error_info.error), &packet->error_info.error_no, packet->error_info.sqlstate); return PASS; } packet->field_count= php_mysqlnd_net_field_length(&p); switch (packet->field_count) { case MYSQLND_NULL_LENGTH: /* First byte in the packet is the field count. Thus, the name is size - 1. And we add 1 for a trailing \0. */ len = packet->header.size - 1; packet->info_or_local_file = emalloc(len + 1); memcpy(packet->info_or_local_file, p, len); packet->info_or_local_file[len] = '\0'; packet->info_or_local_file_len = len; break; case 0x00: packet->affected_rows = php_mysqlnd_net_field_length_ll(&p); packet->last_insert_id= php_mysqlnd_net_field_length_ll(&p); packet->server_status = uint2korr(p); p+=2; packet->warning_count = uint2korr(p); p+=2; /* Check for additional textual data */ if (packet->header.size > (p - buf) && (len = php_mysqlnd_net_field_length(&p))) { packet->info_or_local_file = emalloc(len + 1); memcpy(packet->info_or_local_file, p, len); packet->info_or_local_file[len] = '\0'; packet->info_or_local_file_len = len; } break; default: /* Result set */ break; } return PASS;}/* }}} *//* {{{ php_mysqlnd_rset_header_free_mem */staticvoid php_mysqlnd_rset_header_free_mem(void *_packet, zend_bool alloca){ php_mysql_packet_rset_header *p= (php_mysql_packet_rset_header *) _packet; if (p->info_or_local_file) { efree(p->info_or_local_file); p->info_or_local_file = NULL; } if (!alloca) { efree(p); }}/* }}} *//* {{{ php_mysqlnd_rset_field_read */static enum_func_statusphp_mysqlnd_rset_field_read(void *_packet, MYSQLND *conn TSRMLS_DC){ /* Should be enough for the metadata of a single row */ php_mysql_packet_res_field *packet= (php_mysql_packet_res_field *) _packet; zend_uchar *buf = (zend_uchar *) conn->net.cmd_buffer.buffer; zend_uchar *p = buf; char *root_ptr; size_t buf_len = conn->net.cmd_buffer.length, len, total_len = 0; MYSQLND_FIELD *meta; PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "field"); if (packet->skip_parsing) { return PASS; } meta = packet->metadata; if ((len = php_mysqlnd_net_field_length(&p))) { meta->catalog = (char *)p; p += (meta->catalog_length = len); total_len += len + 1; } if ((len = php_mysqlnd_net_field_length(&p))) { meta->db = (char *)p; p += (meta->db_length = len); total_len += len + 1; } if ((len = php_mysqlnd_net_field_length(&p))) { meta->table = (char *)p; p += (meta->table_length = len); total_len += len + 1; } if ((len = php_mysqlnd_net_field_length(&p))) { meta->org_table = (char *)p; p += (meta->org_table_length = len); total_len += len + 1; } if ((len = php_mysqlnd_net_field_length(&p))) { meta->name = (char *)p; p += (meta->name_length = len); total_len += len + 1; } if ((len = php_mysqlnd_net_field_length(&p))) { meta->org_name = (char *)p; p += (meta->org_name_length = len); total_len += len + 1; } /* 1 byte filler */ p++; meta->charsetnr = uint2korr(p); p += 2; meta->length = uint4korr(p); p += 4; meta->type = uint1korr(p); p += 1; meta->flags = uint2korr(p); p += 2; meta->decimals = uint2korr(p); p += 1; /* 2 byte filler */ p +=2; /* Should we set NUM_FLAG (libmysql does it) ? */ if ( (meta->type <= MYSQL_TYPE_INT24 && (meta->type != MYSQL_TYPE_TIMESTAMP || meta->length == 14 || meta->length == 8) ) || meta->type == MYSQL_TYPE_YEAR) { meta->flags |= NUM_FLAG; } /* def could be empty, thus don't allocate on the root */ if (packet->header.size > (p - buf) && (len = php_mysqlnd_net_field_length(&p))) { meta->def = emalloc(len + 1); memcpy(meta->def, p, len); meta->def[len] = '\0'; meta->def_length = len; p += len; } root_ptr = meta->root = emalloc(total_len); meta->root_len = total_len; /* Now do allocs */ if (meta->catalog) { len = meta->catalog_length; meta->catalog = memcpy(root_ptr, meta->catalog, len); *(root_ptr +=len) = '\0'; root_ptr++; } if (meta->db) { len = meta->db_length; meta->db = memcpy(root_ptr, meta->db, len); *(root_ptr + len) = '\0'; } if (meta->table) { len = meta->table_length; meta->table = memcpy(root_ptr, meta->table, len); *(root_ptr +=len) = '\0'; root_ptr++; } if (meta->org_table) { len = meta->org_table_length; meta->org_table = memcpy(root_ptr, meta->org_table, len); *(root_ptr +=len) = '\0'; root_ptr++; } if (meta->name) { len = meta->name_length; meta->name = memcpy(root_ptr, meta->name, len); *(root_ptr +=len) = '\0'; root_ptr++; } if (meta->org_name) { len = meta->org_name_length; meta->org_name = memcpy(root_ptr, meta->org_name, len); *(root_ptr +=len) = '\0'; root_ptr++; }#ifndef MYSQLND_SILENT php_printf("\tFIELD=[%s.%s.%s]\n", meta->db? meta->db:"*NA*", meta->table? meta->table:"*NA*", meta->name? meta->name:"*NA*");#endif return PASS;}/* }}} *//* {{{ php_mysqlnd_rset_field_free_mem */staticvoid php_mysqlnd_rset_field_free_mem(void *_packet, zend_bool alloca){ php_mysql_packet_res_field *p= (php_mysql_packet_res_field *) _packet; /* p->metadata was passed to us as temporal buffer */ if (!alloca) { efree(p); }}/* }}} */static enum_func_statusphp_mysqlnd_read_row_ex(MYSQLND *conn, zend_uchar **buf, int buf_size, size_t *data_size TSRMLS_DC){ enum_func_status ret = PASS; mysqlnd_packet_header header; zend_uchar *new_buf = NULL, *p = *buf; zend_bool first_iteration = TRUE; MYSQLND_NET *net = &conn->net; /* To ease the process the server splits everything in packets up to 2^24 - 1. Even in the case the payload is evenly divisible by this value, the last packet will be empty, namely 0 bytes. Thus, we can read every packet and ask for next one if they have 2^24 - 1 sizes. But just read the header of a zero-length byte, don't read the body, there is no such. */ *data_size = 0; while (1) { if (FAIL == mysqlnd_read_header(conn , &header TSRMLS_CC)) { ret = FAIL; break; } *data_size += header.size;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -