Commit message: None
CVE: CVE-2015-8838
CWE: CWE-284
Vulnerability description: ext/mysqlnd/mysqlnd.c in PHP before 5.4.43, 5.5.x before 5.5.27, and 5.6.x before 5.6.11 uses a client SSL option to mean that SSL is optional, which allows man-in-the-middle attackers to spoof servers via a cleartext-downgrade attack, a related issue to CVE-2015-3152.

Project: php

MYSQLND_METHOD(mysqlnd_conn_data, free_options)(MYSQLND_CONN_DATA * conn TSRMLS_DC)
{
	zend_bool pers = conn->persistent;

	if (conn->options->charset_name) {
		mnd_pefree(conn->options->charset_name, pers);
		conn->options->charset_name = NULL;
	}
	if (conn->options->auth_protocol) {
		mnd_pefree(conn->options->auth_protocol, pers);
		conn->options->auth_protocol = NULL;
	}
	if (conn->options->num_commands) {
		unsigned int i;
		for (i = 0; i < conn->options->num_commands; i++) {
			/* allocated with pestrdup */
			mnd_pefree(conn->options->init_commands[i], pers);
		}
		mnd_pefree(conn->options->init_commands, pers);
		conn->options->init_commands = NULL;
	}
	if (conn->options->cfg_file) {
		mnd_pefree(conn->options->cfg_file, pers);
		conn->options->cfg_file = NULL;
	}
	if (conn->options->cfg_section) {
		mnd_pefree(conn->options->cfg_section, pers);
		conn->options->cfg_section = NULL;
	}
}

Project: php

MYSQLND_METHOD(mysqlnd_conn_data, free_contents)(MYSQLND_CONN_DATA * conn TSRMLS_DC)
{
	zend_bool pers = conn->persistent;

	DBG_ENTER("mysqlnd_conn_data::free_contents");

	mysqlnd_local_infile_default(conn);
	if (conn->current_result) {
		conn->current_result->m.free_result(conn->current_result, TRUE TSRMLS_CC);
		conn->current_result = NULL;
	}

	if (conn->net) {
		conn->net->m.free_contents(conn->net TSRMLS_CC);
	}

	DBG_INF("Freeing memory of members");

	if (conn->host) {
		mnd_pefree(conn->host, pers);
		conn->host = NULL;
	}
	if (conn->user) {
		mnd_pefree(conn->user, pers);
		conn->user = NULL;
	}
	if (conn->passwd) {
		mnd_pefree(conn->passwd, pers);
		conn->passwd = NULL;
	}
	if (conn->connect_or_select_db) {
		mnd_pefree(conn->connect_or_select_db, pers);
		conn->connect_or_select_db = NULL;
	}
	if (conn->unix_socket) {
		mnd_pefree(conn->unix_socket, pers);
		conn->unix_socket = NULL;
	}
	DBG_INF_FMT("scheme=%s", conn->scheme);
	if (conn->scheme) {
		mnd_pefree(conn->scheme, pers);
		conn->scheme = NULL;
	}
	if (conn->server_version) {
		mnd_pefree(conn->server_version, pers);
		conn->server_version = NULL;
	}
	if (conn->host_info) {
		mnd_pefree(conn->host_info, pers);
		conn->host_info = NULL;
	}
	if (conn->auth_plugin_data) {
		mnd_pefree(conn->auth_plugin_data, pers);
		conn->auth_plugin_data = NULL;
	}
	if (conn->last_message) {
		mnd_pefree(conn->last_message, pers);
		conn->last_message = NULL;
	}
	if (conn->error_info->error_list) {
		zend_llist_clean(conn->error_info->error_list);
		mnd_pefree(conn->error_info->error_list, pers);
		conn->error_info->error_list = NULL;
	}
	conn->charset = NULL;
	conn->greet_charset = NULL;

	DBG_VOID_RETURN;
}

Project: php

MYSQLND_METHOD(mysqlnd_conn_data, simple_command_handle_response)(MYSQLND_CONN_DATA * conn, enum mysqlnd_packet_type ok_packet,
															 zend_bool silent, enum php_mysqlnd_server_command command,
															 zend_bool ignore_upsert_status TSRMLS_DC)
{
	enum_func_status ret = FAIL;

	DBG_ENTER("mysqlnd_conn_data::simple_command_handle_response");
	DBG_INF_FMT("silent=%u packet=%u command=%s", silent, ok_packet, mysqlnd_command_to_text[command]);

	switch (ok_packet) {
		case PROT_OK_PACKET:{
			MYSQLND_PACKET_OK * ok_response = conn->protocol->m.get_ok_packet(conn->protocol, FALSE TSRMLS_CC);
			if (!ok_response) {
				SET_OOM_ERROR(*conn->error_info);
				break;
			}
			if (FAIL == (ret = PACKET_READ(ok_response, conn))) {
				if (!silent) {
					DBG_ERR_FMT("Error while reading %s's OK packet", mysqlnd_command_to_text[command]);
					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading %s's OK packet. PID=%u",
									 mysqlnd_command_to_text[command], getpid());
				}
			} else {
				DBG_INF_FMT("OK from server");
				if (0xFF == ok_response->field_count) {
					/* The server signalled error. Set the error */
					SET_CLIENT_ERROR(*conn->error_info, ok_response->error_no, ok_response->sqlstate, ok_response->error);
					ret = FAIL;
					/*
					  Cover a protocol design error: error packet does not
					  contain the server status. Therefore, the client has no way
					  to find out whether there are more result sets of
					  a multiple-result-set statement pending. Luckily, in 5.0 an
					  error always aborts execution of a statement, wherever it is
					  a multi-statement or a stored procedure, so it should be
					  safe to unconditionally turn off the flag here.
					*/
					conn->upsert_status->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
					SET_ERROR_AFF_ROWS(conn);
				} else {
					SET_NEW_MESSAGE(conn->last_message, conn->last_message_len,
									ok_response->message, ok_response->message_len,
									conn->persistent);

					if (!ignore_upsert_status) {
						memset(conn->upsert_status, 0, sizeof(*conn->upsert_status));
						conn->upsert_status->warning_count = ok_response->warning_count;
						conn->upsert_status->server_status = ok_response->server_status;
						conn->upsert_status->affected_rows = ok_response->affected_rows;
						conn->upsert_status->last_insert_id = ok_response->last_insert_id;
					}
				}
			}
			PACKET_FREE(ok_response);
			break;
		}
		case PROT_EOF_PACKET:{
			MYSQLND_PACKET_EOF * ok_response = conn->protocol->m.get_eof_packet(conn->protocol, FALSE TSRMLS_CC);
			if (!ok_response) {
				SET_OOM_ERROR(*conn->error_info);
				break;
			}
			if (FAIL == (ret = PACKET_READ(ok_response, conn))) {
				SET_CLIENT_ERROR(*conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE,
								 "Malformed packet");
				if (!silent) {
					DBG_ERR_FMT("Error while reading %s's EOF packet", mysqlnd_command_to_text[command]);
					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading %s's EOF packet. PID=%d",
									 mysqlnd_command_to_text[command], getpid());
				}
			} else if (0xFF == ok_response->field_count) {
				/* The server signalled error. Set the error */
				SET_CLIENT_ERROR(*conn->error_info, ok_response->error_no, ok_response->sqlstate, ok_response->error);
				SET_ERROR_AFF_ROWS(conn);
			} else if (0xFE != ok_response->field_count) {
				SET_CLIENT_ERROR(*conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet");
				if (!silent) {
					DBG_ERR_FMT("EOF packet expected, field count wasn't 0xFE but 0x%2X", ok_response->field_count);
					php_error_docref(NULL TSRMLS_CC, E_WARNING, "EOF packet expected, field count wasn't 0xFE but 0x%2X",
									ok_response->field_count);
				}
			} else {
				DBG_INF_FMT("OK from server");
			}
			PACKET_FREE(ok_response);
			break;
		}
		default:
			SET_CLIENT_ERROR(*conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet");
			php_error_docref(NULL TSRMLS_CC, E_ERROR, "Wrong response packet %u passed to the function", ok_packet);
			break;
	}
	DBG_INF(ret == PASS ? "PASS":"FAIL");
	DBG_RETURN(ret);
}

Project: php

MYSQLND_METHOD(mysqlnd_conn_data, simple_command)(MYSQLND_CONN_DATA * conn, enum php_mysqlnd_server_command command,
			   const zend_uchar * const arg, size_t arg_len, enum mysqlnd_packet_type ok_packet, zend_bool silent,
			   zend_bool ignore_upsert_status TSRMLS_DC)
{
	enum_func_status ret = PASS;
	MYSQLND_PACKET_COMMAND * cmd_packet;

	DBG_ENTER("mysqlnd_conn_data::simple_command");
	DBG_INF_FMT("command=%s ok_packet=%u silent=%u", mysqlnd_command_to_text[command], ok_packet, silent);
	DBG_INF_FMT("conn->server_status=%u", conn->upsert_status->server_status);

	switch (CONN_GET_STATE(conn)) {
		case CONN_READY:
			break;
		case CONN_QUIT_SENT:
			SET_CLIENT_ERROR(*conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
			DBG_ERR("Server is gone");
			DBG_RETURN(FAIL);
		default:
			SET_CLIENT_ERROR(*conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
			DBG_ERR_FMT("Command out of sync. State=%u", CONN_GET_STATE(conn));
			DBG_RETURN(FAIL);
	}

	SET_ERROR_AFF_ROWS(conn);
	SET_EMPTY_ERROR(*conn->error_info);

	cmd_packet = conn->protocol->m.get_command_packet(conn->protocol, FALSE TSRMLS_CC);
	if (!cmd_packet) {
		SET_OOM_ERROR(*conn->error_info);
		DBG_RETURN(FAIL);
	}

	cmd_packet->command = command;
	if (arg && arg_len) {
		cmd_packet->argument = arg;
		cmd_packet->arg_len  = arg_len;
	}

	MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_COM_QUIT + command - 1 /* because of COM_SLEEP */ );

	if (! PACKET_WRITE(cmd_packet, conn)) {
		if (!silent) {
			DBG_ERR_FMT("Error while sending %s packet", mysqlnd_command_to_text[command]);
			php_error(E_WARNING, "Error while sending %s packet. PID=%d", mysqlnd_command_to_text[command], getpid());
		}
		CONN_SET_STATE(conn, CONN_QUIT_SENT);
		DBG_ERR("Server is gone");
		ret = FAIL;
	} else if (ok_packet != PROT_LAST) {
		ret = conn->m->simple_command_handle_response(conn, ok_packet, silent, command, ignore_upsert_status TSRMLS_CC);
	}

	PACKET_FREE(cmd_packet);
	DBG_INF(ret == PASS ? "PASS":"FAIL");
	DBG_RETURN(ret);
}

Project: php

MYSQLND_METHOD(mysqlnd_conn_data, restart_psession)(MYSQLND_CONN_DATA * conn TSRMLS_DC)
{
	DBG_ENTER("mysqlnd_conn_data::restart_psession");
	MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_CONNECT_REUSED);
	/* Free here what should not be seen by the next script */
	if (conn->last_message) {
		mnd_pefree(conn->last_message, conn->persistent);
		conn->last_message = NULL;
	}
	DBG_RETURN(PASS);
}

Project: php

MYSQLND_METHOD(mysqlnd_conn_data, end_psession)(MYSQLND_CONN_DATA * conn TSRMLS_DC)
{
	DBG_ENTER("mysqlnd_conn_data::end_psession");
	DBG_RETURN(PASS);
}

Project: php

MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn_handle,
						 const char * host, const char * user,
						 const char * passwd, unsigned int passwd_len,
						 const char * db, unsigned int db_len,
						 unsigned int port,
						 const char * socket_or_pipe,
						 unsigned int mysql_flags
						 TSRMLS_DC)
{
	size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, connect);
	enum_func_status ret = FAIL;
	MYSQLND_CONN_DATA * conn = conn_handle->data;

	DBG_ENTER("mysqlnd_conn::connect");

	if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
		ret = conn->m->connect(conn, host, user, passwd, passwd_len, db, db_len, port, socket_or_pipe, mysql_flags TSRMLS_CC);

		conn->m->local_tx_end(conn, this_func, FAIL TSRMLS_CC);
	}
	DBG_RETURN(ret);
}

Project: php

MYSQLND_METHOD(mysqlnd_conn_data, query)(MYSQLND_CONN_DATA * conn, const char * query, unsigned int query_len TSRMLS_DC)
{
	size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, query);
	enum_func_status ret = FAIL;
	DBG_ENTER("mysqlnd_conn_data::query");
	DBG_INF_FMT("conn=%llu query=%s", conn->thread_id, query);

	if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
		if (PASS == conn->m->send_query(conn, query, query_len TSRMLS_CC) &&
			PASS == conn->m->reap_query(conn TSRMLS_CC))
		{
			ret = PASS;
			if (conn->last_query_type == QUERY_UPSERT && conn->upsert_status->affected_rows) {
				MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn->stats, STAT_ROWS_AFFECTED_NORMAL, conn->upsert_status->affected_rows);
			}
		}
		conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);
	}
	DBG_RETURN(ret);
}

Project: php

MYSQLND_METHOD(mysqlnd_conn_data, send_query)(MYSQLND_CONN_DATA * conn, const char * query, unsigned int query_len TSRMLS_DC)
{
	size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, send_query);
	enum_func_status ret = FAIL;
	DBG_ENTER("mysqlnd_conn_data::send_query");
	DBG_INF_FMT("conn=%llu query=%s", conn->thread_id, query);
	DBG_INF_FMT("conn->server_status=%u", conn->upsert_status->server_status);

	if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
		ret = conn->m->simple_command(conn, COM_QUERY, (zend_uchar *) query, query_len,
											 PROT_LAST /* we will handle the OK packet*/,
											 FALSE, FALSE TSRMLS_CC);
		if (PASS == ret) {
			CONN_SET_STATE(conn, CONN_QUERY_SENT);
		}
		conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);
	}
	DBG_INF_FMT("conn->server_status=%u", conn->upsert_status->server_status);
	DBG_RETURN(ret);
}

Project: php

MYSQLND_METHOD(mysqlnd_conn_data, reap_query)(MYSQLND_CONN_DATA * conn TSRMLS_DC)
{
	size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, reap_query);
	enum_mysqlnd_connection_state state = CONN_GET_STATE(conn);
	enum_func_status ret = FAIL;
	DBG_ENTER("mysqlnd_conn_data::reap_query");
	DBG_INF_FMT("conn=%llu", conn->thread_id);

	DBG_INF_FMT("conn->server_status=%u", conn->upsert_status->server_status);
	if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
		if (state <= CONN_READY || state == CONN_QUIT_SENT) {
			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connection not opened, clear or has been closed");
			DBG_ERR_FMT("Connection not opened, clear or has been closed. State=%u", state);
			DBG_RETURN(ret);
		}
		ret = conn->m->query_read_result_set_header(conn, NULL TSRMLS_CC);

		conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);
	}
	DBG_INF_FMT("conn->server_status=%u", conn->upsert_status->server_status);
	DBG_RETURN(ret);
}

Project: php

MYSQLND_METHOD(mysqlnd_conn_data, list_fields)(MYSQLND_CONN_DATA * conn, const char *table, const char *achtung_wild TSRMLS_DC)
{
	size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, list_fields);
	/* db + \0 + wild + \0 (for wild) */
	zend_uchar buff[MYSQLND_MAX_ALLOWED_DB_LEN * 2 + 1 + 1], *p;
	size_t table_len, wild_len;
	MYSQLND_RES * result = NULL;
	DBG_ENTER("mysqlnd_conn_data::list_fields");
	DBG_INF_FMT("conn=%llu table=%s wild=%s", conn->thread_id, table? table:"",achtung_wild? achtung_wild:"");

	if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
		do {
			p = buff;
			if (table && (table_len = strlen(table))) {
				size_t to_copy = MIN(table_len, MYSQLND_MAX_ALLOWED_DB_LEN);
				memcpy(p, table, to_copy);
				p += to_copy;
				*p++ = '\0';
			}

			if (achtung_wild && (wild_len = strlen(achtung_wild))) {
				size_t to_copy = MIN(wild_len, MYSQLND_MAX_ALLOWED_DB_LEN);
				memcpy(p, achtung_wild, to_copy);
				p += to_copy;
				*p++ = '\0';
			}

			if (PASS != conn->m->simple_command(conn, COM_FIELD_LIST, buff, p - buff,
											   PROT_LAST /* we will handle the OK packet*/,
											   FALSE, TRUE TSRMLS_CC)) {
				conn->m->local_tx_end(conn, 0, FAIL TSRMLS_CC);
				break;
			}

			/*
			   Prepare for the worst case.
			   MyISAM goes to 2500 BIT columns, double it for safety.
			*/
			result = conn->m->result_init(5000, conn->persistent TSRMLS_CC);
			if (!result) {
				break;
			}

			if (FAIL == result->m.read_result_metadata(result, conn TSRMLS_CC)) {
				DBG_ERR("Error occurred while reading metadata");
				result->m.free_result(result, TRUE TSRMLS_CC);
				result = NULL;
				break;
			}

			result->type = MYSQLND_RES_NORMAL;
			result->m.fetch_row = result->m.fetch_row_normal_unbuffered;
			result->unbuf = mnd_ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
			if (!result->unbuf) {
				/* OOM */
				SET_OOM_ERROR(*conn->error_info);
				result->m.free_result(result, TRUE TSRMLS_CC);
				result = NULL;
				break;
			}
			result->unbuf->eof_reached = TRUE;
		} while (0);
		conn->m->local_tx_end(conn, this_func, result == NULL? FAIL:PASS TSRMLS_CC);
	}

	DBG_RETURN(result);
}

Project: php

MYSQLND_METHOD(mysqlnd_conn_data, list_method)(MYSQLND_CONN_DATA * conn, const char * query, const char *achtung_wild, char *par1 TSRMLS_DC)
{
	size_t this_func = STRUCT_OFFSET(struct st_mysqlnd_conn_data_methods, list_method);
	char * show_query = NULL;
	size_t show_query_len;
	MYSQLND_RES * result = NULL;

	DBG_ENTER("mysqlnd_conn_data::list_method");
	DBG_INF_FMT("conn=%llu query=%s wild=%u", conn->thread_id, query, achtung_wild);

	if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
		if (par1) {
			if (achtung_wild) {
				show_query_len = mnd_sprintf(&show_query, 0, query, par1, achtung_wild);
			} else {
				show_query_len = mnd_sprintf(&show_query, 0, query, par1);
			}
		} else {
			if (achtung_wild) {
				show_query_len = mnd_sprintf(&show_query, 0, query, achtung_wild);
			} else {
				show_query_len = strlen(show_query = (char *)query);
			}
		}

		if (PASS == conn->m->query(conn, show_query, show_query_len TSRMLS_CC)) {
			result = conn->m->store_result(conn TSRMLS_CC);
		}
		if (show_query != query) {
			mnd_sprintf_free(show_query);
		}
		conn->m->local_tx_end(conn, this_func, result == NULL? FAIL:PASS TSRMLS_CC);
	}
	DBG_RETURN(result);
}

Project: php

MYSQLND_METHOD(mysqlnd_conn_data, errno)(const MYSQLND_CONN_DATA * const conn TSRMLS_DC)
{
	return conn->error_info->error_no;
}

Project: php

MYSQLND_METHOD(mysqlnd_conn_data, error)(const MYSQLND_CONN_DATA * const conn TSRMLS_DC)
{
	return conn->error_info->error;
}

Project: php

MYSQLND_METHOD(mysqlnd_conn_data, sqlstate)(const MYSQLND_CONN_DATA * const conn TSRMLS_DC)
{
	return conn->error_info->sqlstate[0] ? conn->error_info->sqlstate:MYSQLND_SQLSTATE_NULL;
}

Project: php

MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, dtor)(MYSQLND_CONN_DATA * conn TSRMLS_DC)
{
	DBG_ENTER("mysqlnd_conn_data::dtor");
	DBG_INF_FMT("conn=%llu", conn->thread_id);

	conn->m->free_contents(conn TSRMLS_CC);
	conn->m->free_options(conn TSRMLS_CC);

	if (conn->net) {
		mysqlnd_net_free(conn->net, conn->stats, conn->error_info TSRMLS_CC);
		conn->net = NULL;
	}

	if (conn->protocol) {
		mysqlnd_protocol_free(conn->protocol TSRMLS_CC);
		conn->protocol = NULL;
	}

	if (conn->stats) {
		mysqlnd_stats_end(conn->stats);
	}

	mnd_pefree(conn, conn->persistent);

	DBG_VOID_RETURN;
}

Project: php

_mysqlnd_poll(MYSQLND **r_array, MYSQLND **e_array, MYSQLND ***dont_poll, long sec, long usec, int * desc_num TSRMLS_DC)
{
	struct timeval	tv;
	struct timeval *tv_p = NULL;
	fd_set			rfds, wfds, efds;
	php_socket_t	max_fd = 0;
	int				retval, sets = 0;
	int				set_count, max_set_count = 0;

	DBG_ENTER("_mysqlnd_poll");
	if (sec < 0 || usec < 0) {
		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Negative values passed for sec and/or usec");
		DBG_RETURN(FAIL);
	}

	*dont_poll = mysqlnd_stream_array_check_for_readiness(r_array TSRMLS_CC);

	FD_ZERO(&rfds);
	FD_ZERO(&wfds);
	FD_ZERO(&efds);

	if (r_array != NULL) {
		set_count = mysqlnd_stream_array_to_fd_set(r_array, &rfds, &max_fd TSRMLS_CC);
		if (set_count > max_set_count) {
			max_set_count = set_count;
		}
		sets += set_count;
	}

	if (e_array != NULL) {
		set_count = mysqlnd_stream_array_to_fd_set(e_array, &efds, &max_fd TSRMLS_CC);
		if (set_count > max_set_count) {
			max_set_count = set_count;
		}
		sets += set_count;
	}

	if (!sets) {
		php_error_docref(NULL TSRMLS_CC, E_WARNING, *dont_poll ? "All arrays passed are clear":"No stream arrays were passed");
		DBG_ERR_FMT(*dont_poll ? "All arrays passed are clear":"No stream arrays were passed");
		DBG_RETURN(FAIL);
	}

	PHP_SAFE_MAX_FD(max_fd, max_set_count);

	/* Solaris + BSD do not like microsecond values which are >= 1 sec */
	if (usec > 999999) {
		tv.tv_sec = sec + (usec / 1000000);
		tv.tv_usec = usec % 1000000;
	} else {
		tv.tv_sec = sec;
		tv.tv_usec = usec;
	}

	tv_p = &tv;

	retval = php_select(max_fd + 1, &rfds, &wfds, &efds, tv_p);

	if (retval == -1) {
		php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to select [%d]: %s (max_fd=%d)",
						errno, strerror(errno), max_fd);
		DBG_RETURN(FAIL);
	}

	if (r_array != NULL) {
		mysqlnd_stream_array_from_fd_set(r_array, &rfds TSRMLS_CC);
	}
	if (e_array != NULL) {
		mysqlnd_stream_array_from_fd_set(e_array, &efds TSRMLS_CC);
	}

	*desc_num = retval;
	DBG_RETURN(PASS);
}

Project: php

PHPAPI MYSQLND * mysqlnd_connect(MYSQLND * conn_handle,
						 const char * host, const char * user,
						 const char * passwd, unsigned int passwd_len,
						 const char * db, unsigned int db_len,
						 unsigned int port,
						 const char * socket_or_pipe,
						 unsigned int mysql_flags
						 TSRMLS_DC)
{
	enum_func_status ret = FAIL;
	zend_bool self_alloced = FALSE;

	DBG_ENTER("mysqlnd_connect");
	DBG_INF_FMT("host=%s user=%s db=%s port=%u flags=%u", host?host:"", user?user:"", db?db:"", port, mysql_flags);

	if (!conn_handle) {
		self_alloced = TRUE;
		if (!(conn_handle = mysqlnd_init(FALSE))) {
			/* OOM */
			DBG_RETURN(NULL);
		}
	}

	ret = conn_handle->m->connect(conn_handle, host, user, passwd, passwd_len, db, db_len, port, socket_or_pipe, mysql_flags TSRMLS_CC);

	if (ret == FAIL) {
		if (self_alloced) {
			/*
			  We have alloced, thus there are no references to this
			  object - we are free to kill it!
			*/
			conn_handle->m->dtor(conn_handle TSRMLS_CC);
		}
		DBG_RETURN(NULL);
	}
	DBG_RETURN(conn_handle);
}

Project: php

mysqlnd_old_escape_string(char * newstr, const char * escapestr, size_t escapestr_len TSRMLS_DC)
{
	DBG_ENTER("mysqlnd_old_escape_string");
	DBG_RETURN(mysqlnd_cset_escape_slashes(mysqlnd_find_charset_name("latin1"), newstr, escapestr, escapestr_len TSRMLS_CC));
}

Project: php

MYSQLND ** mysqlnd_stream_array_check_for_readiness(MYSQLND ** conn_array TSRMLS_DC)
{
	int cnt = 0;
	MYSQLND **p = conn_array, **p_p;
	MYSQLND **ret = NULL;

	while (*p) {
		if (CONN_GET_STATE((*p)->data) <= CONN_READY || CONN_GET_STATE((*p)->data) == CONN_QUIT_SENT) {
			cnt++;
		}
		p++;
	}
	if (cnt) {
		MYSQLND **ret_p = ret = ecalloc(cnt + 1, sizeof(MYSQLND *));
		p_p = p = conn_array;
		while (*p) {
			if (CONN_GET_STATE((*p)->data) <= CONN_READY || CONN_GET_STATE((*p)->data) == CONN_QUIT_SENT) {
				*ret_p = *p;
				*p = NULL;
				ret_p++;
			} else {
				*p_p = *p;
				p_p++;
			}
			p++;
		}
		*ret_p = NULL;
	}
	return ret;
}

Project: php

static int mysqlnd_stream_array_from_fd_set(MYSQLND ** conn_array, fd_set * fds TSRMLS_DC)
{
	php_socket_t this_fd;
	php_stream *stream = NULL;
	int ret = 0;
	zend_bool disproportion = FALSE;


	MYSQLND **fwd = conn_array, **bckwd = conn_array;

	while (*fwd) {
		stream = (*fwd)->data->net->stream;
		if (stream != NULL && SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL,
										(void*)&this_fd, 1) && this_fd >= 0) {
			if (PHP_SAFE_FD_ISSET(this_fd, fds)) {
				if (disproportion) {
					*bckwd = *fwd;
				}
				bckwd++;
				fwd++;
				ret++;
				continue;
			}
		}
		disproportion = TRUE;
		fwd++;
	}
	*bckwd = NULL;/* NULL-terminate the list */

	return ret;
}

Project: php

static int mysqlnd_stream_array_to_fd_set(MYSQLND ** conn_array, fd_set * fds, php_socket_t * max_fd TSRMLS_DC)
{
	php_socket_t this_fd;
	php_stream *stream = NULL;
	int cnt = 0;
	MYSQLND **p = conn_array;

	while (*p) {
		/* get the fd.
		 * NB: Most other code will NOT use the PHP_STREAM_CAST_INTERNAL flag
		 * when casting.  It is only used here so that the buffered data warning
		 * is not displayed.
		 * */
		stream = (*p)->data->net->stream;
		if (stream != NULL && SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD_FOR_SELECT | PHP_STREAM_CAST_INTERNAL,
										(void*)&this_fd, 1) && this_fd >= 0) {

			PHP_SAFE_FD_SET(this_fd, fds);

			if (this_fd > *max_fd) {
				*max_fd = this_fd;
			}
			cnt++;
		}
		p++;
	}
	return cnt ? 1 : 0;
}