コード例 #1
0
ファイル: pack.c プロジェクト: knielsen/mariadb
uchar *safe_net_store_length(uchar *packet, size_t packet_len, ulonglong length)
{
  if (length < 251)
  {
    if (packet_len < 1)
      return NULL;
    *packet= (uchar) length;
    return packet+1;
  }
  /* 251 is reserved for NULL */
  if (length < 65536)
  {
    if (packet_len < 3)
      return NULL;
    *packet++=252;
    int2store(packet, (uint) length);
    return packet+2;
  }
  if (length < 16777216)
  {
    if (packet_len < 4)
      return NULL;
    *packet++=253;
    int3store(packet, (ulong) length);
    return packet+3;
  }
  if (packet_len < 9)
    return NULL;
  *packet++=254;
  int8store(packet,length);
  return packet+8;
}
コード例 #2
0
ファイル: pack.c プロジェクト: knielsen/mariadb
uchar *net_store_length(uchar *packet, ulonglong length)
{
  if (length < 251)
  {
    *packet= (uchar) length;
    return packet+1;
  }
  /* 251 is reserved for NULL */
  if (length < 65536)
  {
    *packet++=252;
    int2store(packet, (uint) length);
    return packet+2;
  }
  if (length < 16777216)
  {
    *packet++=253;
    int3store(packet, (ulong) length);
    return packet+3;
  }
  *packet++=254;
  int8store(packet,length);
  return packet+8;
}
コード例 #3
0
ファイル: my_auth.c プロジェクト: MarianMMX/MarianMMX
static int send_client_reply_packet(MCPVIO_EXT *mpvio,
                                    const uchar *data, int data_len)
{
    MYSQL *mysql= mpvio->mysql;
    NET *net= &mysql->net;
    char *buff, *end;
    size_t conn_attr_len= (mysql->options.extension) ?
                          mysql->options.extension->connect_attrs_len : 0;

    /* see end= buff+32 below, fixed size of the packet is 32 bytes */
    buff= my_alloca(33 + USERNAME_LENGTH + data_len + NAME_LEN + NAME_LEN + conn_attr_len + 9);

    mysql->client_flag|= mysql->options.client_flag;
    mysql->client_flag|= CLIENT_CAPABILITIES;

    if (mysql->client_flag & CLIENT_MULTI_STATEMENTS)
        mysql->client_flag|= CLIENT_MULTI_RESULTS;

#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
    if (mysql->options.ssl_key || mysql->options.ssl_cert ||
            mysql->options.ssl_ca || mysql->options.ssl_capath ||
            mysql->options.ssl_cipher)
        mysql->options.use_ssl= 1;
    if (mysql->options.use_ssl)
        mysql->client_flag|= CLIENT_SSL;

    /* if server doesn't support SSL and verification of server certificate
       was set to mandatory, we need to return an error */
    if (mysql->options.use_ssl && !(mysql->server_capabilities & CLIENT_SSL))
    {
        if ((mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) ||
                (mysql->options.extension && (mysql->options.extension->ssl_fp ||
                                              mysql->options.extension->ssl_fp_list)))
        {
            my_set_error(mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN,
                         ER(CR_SSL_CONNECTION_ERROR),
                         "Server doesn't support SSL");
            goto error;
        }
    }

#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY*/
    if (mpvio->db)
        mysql->client_flag|= CLIENT_CONNECT_WITH_DB;

    /* Remove options that server doesn't support */
    mysql->client_flag= mysql->client_flag &
                        (~(CLIENT_COMPRESS | CLIENT_SSL | CLIENT_PROTOCOL_41)
                         | mysql->server_capabilities);

#ifndef HAVE_COMPRESS
    mysql->client_flag&= ~CLIENT_COMPRESS;
#endif

    if (mysql->client_flag & CLIENT_PROTOCOL_41)
    {
        /* 4.1 server and 4.1 client has a 32 byte option flag */
        int4store(buff,mysql->client_flag);
        int4store(buff+4, net->max_packet_size);
        buff[8]= (char) mysql->charset->nr;
        bzero(buff+9, 32-9);
        end= buff+32;
    }
    else
    {
        int2store(buff, mysql->client_flag);
        int3store(buff+2, net->max_packet_size);
        end= buff+5;
    }
#ifdef HAVE_OPENSSL
    if (mysql->options.ssl_key ||
            mysql->options.ssl_cert ||
            mysql->options.ssl_ca ||
            mysql->options.ssl_capath ||
            mysql->options.ssl_cipher
#ifdef CRL_IMPLEMENTED
            || (mysql->options.extension &&
                (mysql->options.extension->ssl_crl ||
                 mysql->options.extension->ssl_crlpath))
#endif
       )
        mysql->options.use_ssl= 1;

    if (mysql->options.use_ssl &&
            (mysql->client_flag & CLIENT_SSL))
    {
        SSL *ssl;
        /*
          Send mysql->client_flag, max_packet_size - unencrypted otherwise
          the server does not know we want to do SSL
        */
        if (my_net_write(net, (char*)buff, (size_t) (end-buff)) || net_flush(net))
        {
            my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
                         ER(CR_SERVER_LOST_EXTENDED),
                         "sending connection information to server",
                         errno);
            goto error;
        }

        /* Create SSL */
        if (!(ssl= my_ssl_init(mysql)))
            goto error;

        /* Connect to the server */
        if (my_ssl_connect(ssl))
        {
            SSL_free(ssl);
            goto error;
        }

        if (mysql->options.extension &&
                (mysql->options.extension->ssl_fp || mysql->options.extension->ssl_fp_list))
        {
            if (ma_ssl_verify_fingerprint(ssl))
                goto error;
        }

        if ((mysql->options.ssl_ca || mysql->options.ssl_capath) &&
                (mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) &&
                my_ssl_verify_server_cert(ssl))
            goto error;
    }
#endif /* HAVE_OPENSSL */

    DBUG_PRINT("info",("Server version = '%s'  capabilites: %lu  status: %u  client_flag: %lu",
                       mysql->server_version, mysql->server_capabilities,
                       mysql->server_status, mysql->client_flag));

    compile_time_assert(MYSQL_USERNAME_LENGTH == USERNAME_LENGTH);

    /* This needs to be changed as it's not useful with big packets */
    if (mysql->user[0])
        strmake(end, mysql->user, USERNAME_LENGTH);
    else
        read_user_name(end);

    /* We have to handle different version of handshake here */
    DBUG_PRINT("info",("user: %s",end));
    end= strend(end) + 1;
    if (data_len)
    {
        if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
        {
            *end++= data_len;
            memcpy(end, data, data_len);
            end+= data_len;
        }
        else
        {
            DBUG_ASSERT(data_len == SCRAMBLE_LENGTH_323 + 1); /* incl. \0 at the end */
            memcpy(end, data, data_len);
            end+= data_len;
        }
    }
    else
        *end++= 0;

    /* Add database if needed */
    if (mpvio->db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
    {
        end= strmake(end, mpvio->db, NAME_LEN) + 1;
        mysql->db= my_strdup(mpvio->db, MYF(MY_WME));
    }

    if (mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
        end= strmake(end, mpvio->plugin->name, NAME_LEN) + 1;

    end= ma_send_connect_attr(mysql, end);

    /* Write authentication package */
    if (my_net_write(net, buff, (size_t) (end-buff)) || net_flush(net))
    {
        my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
                     ER(CR_SERVER_LOST_EXTENDED),
                     "sending authentication information",
                     errno);
        goto error;
    }
    my_afree(buff);
    return 0;

error:
    my_afree(buff);
    return 1;
}
コード例 #4
0
ファイル: mysqlnd_net.c プロジェクト: PeeHaa/php-src
/*
  IMPORTANT : It's expected that buffer has place in the beginning for MYSQLND_HEADER_SIZE !!!!
			  This is done for performance reasons in the caller of this function.
			  Otherwise we will have to do send two TCP packets, or do new alloc and memcpy.
			  Neither are quick, thus the clients of this function are obligated to do
			  what they are asked for.

  `count` is actually the length of the payload data. Thus :
  count + MYSQLND_HEADER_SIZE = sizeof(buffer) (not the pointer but the actual buffer)
*/
static size_t
MYSQLND_METHOD(mysqlnd_net, send_ex)(MYSQLND_NET * const net, zend_uchar * const buffer, const size_t count,
									 MYSQLND_STATS * const conn_stats, MYSQLND_ERROR_INFO * const error_info)
{
	zend_uchar safe_buf[((MYSQLND_HEADER_SIZE) + (sizeof(zend_uchar)) - 1) / (sizeof(zend_uchar))];
	zend_uchar * safe_storage = safe_buf;
	size_t bytes_sent, packets_sent = 1;
	size_t left = count;
	zend_uchar * p = (zend_uchar *) buffer;
	zend_uchar * compress_buf = NULL;
	size_t to_be_sent;

	DBG_ENTER("mysqlnd_net::send_ex");
	DBG_INF_FMT("count=" MYSQLND_SZ_T_SPEC " compression=%u", count, net->data->compressed);

	if (net->data->compressed == TRUE) {
		size_t comp_buf_size = MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE + MIN(left, MYSQLND_MAX_PACKET_SIZE);
		DBG_INF_FMT("compress_buf_size="MYSQLND_SZ_T_SPEC, comp_buf_size);
		compress_buf = mnd_emalloc(comp_buf_size);
	}

	do {
		to_be_sent = MIN(left, MYSQLND_MAX_PACKET_SIZE);
		DBG_INF_FMT("to_be_sent=%u", to_be_sent);
		DBG_INF_FMT("packets_sent=%u", packets_sent);
		DBG_INF_FMT("compressed_envelope_packet_no=%u", net->compressed_envelope_packet_no);
		DBG_INF_FMT("packet_no=%u", net->packet_no);
#ifdef MYSQLND_COMPRESSION_ENABLED
		if (net->data->compressed == TRUE) {
			/* here we need to compress the data and then write it, first comes the compressed header */
			size_t tmp_complen = to_be_sent;
			size_t payload_size;
			zend_uchar * uncompressed_payload = p; /* should include the header */

			STORE_HEADER_SIZE(safe_storage, uncompressed_payload);
			int3store(uncompressed_payload, to_be_sent);
			int1store(uncompressed_payload + 3, net->packet_no);
			if (PASS == net->data->m.encode((compress_buf + COMPRESSED_HEADER_SIZE + MYSQLND_HEADER_SIZE), &tmp_complen,
									   uncompressed_payload, to_be_sent + MYSQLND_HEADER_SIZE))
			{
				int3store(compress_buf + MYSQLND_HEADER_SIZE, to_be_sent + MYSQLND_HEADER_SIZE);
				payload_size = tmp_complen;
			} else {
				int3store(compress_buf + MYSQLND_HEADER_SIZE, 0);
				memcpy(compress_buf + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, uncompressed_payload, to_be_sent + MYSQLND_HEADER_SIZE);
				payload_size = to_be_sent + MYSQLND_HEADER_SIZE;
			}
			RESTORE_HEADER_SIZE(uncompressed_payload, safe_storage);

			int3store(compress_buf, payload_size);
			int1store(compress_buf + 3, net->packet_no);
			DBG_INF_FMT("writing "MYSQLND_SZ_T_SPEC" bytes to the network", payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE);
			bytes_sent = net->data->m.network_write_ex(net, compress_buf, payload_size + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE,
												 conn_stats, error_info);
			net->compressed_envelope_packet_no++;
  #if WHEN_WE_NEED_TO_CHECK_WHETHER_COMPRESSION_WORKS_CORRECTLY
			if (res == Z_OK) {
				size_t decompressed_size = left + MYSQLND_HEADER_SIZE;
				zend_uchar * decompressed_data = mnd_malloc(decompressed_size);
				int error = net->data->m.decode(decompressed_data, decompressed_size,
										  compress_buf + MYSQLND_HEADER_SIZE + COMPRESSED_HEADER_SIZE, payload_size);
				if (error == Z_OK) {
					int i;
					DBG_INF("success decompressing");
					for (i = 0 ; i < decompressed_size; i++) {
						if (i && (i % 30 == 0)) {
							printf("\n\t\t");
						}
						printf("%.2X ", (int)*((char*)&(decompressed_data[i])));
						DBG_INF_FMT("%.2X ", (int)*((char*)&(decompressed_data[i])));
					}
				} else {
					DBG_INF("error decompressing");
				}
				mnd_free(decompressed_data);
			}
  #endif /* WHEN_WE_NEED_TO_CHECK_WHETHER_COMPRESSION_WORKS_CORRECTLY */
		} else
#endif /* MYSQLND_COMPRESSION_ENABLED */
		{
			DBG_INF("no compression");
			STORE_HEADER_SIZE(safe_storage, p);
			int3store(p, to_be_sent);
			int1store(p + 3, net->packet_no);
			bytes_sent = net->data->m.network_write_ex(net, p, to_be_sent + MYSQLND_HEADER_SIZE, conn_stats, error_info);
			RESTORE_HEADER_SIZE(p, safe_storage);
			net->compressed_envelope_packet_no++;
		}
		net->packet_no++;

		p += to_be_sent;
		left -= to_be_sent;
		packets_sent++;
		/*
		  if left is 0 then there is nothing more to send, but if the last packet was exactly
		  with the size MYSQLND_MAX_PACKET_SIZE we need to send additional packet, which has
		  empty payload. Thus if left == 0 we check for to_be_sent being the max size. If it is
		  indeed it then loop once more, then to_be_sent will become 0, left will stay 0. Empty
		  packet will be sent and this loop will end.
		*/
	} while (bytes_sent && (left > 0 || to_be_sent == MYSQLND_MAX_PACKET_SIZE));

	DBG_INF_FMT("packet_size="MYSQLND_SZ_T_SPEC" packet_no=%u", left, net->packet_no);

	MYSQLND_INC_CONN_STATISTIC_W_VALUE3(conn_stats,
			STAT_BYTES_SENT, count + packets_sent * MYSQLND_HEADER_SIZE,
			STAT_PROTOCOL_OVERHEAD_OUT, packets_sent * MYSQLND_HEADER_SIZE,
			STAT_PACKETS_SENT, packets_sent);

	if (compress_buf) {
		mnd_efree(compress_buf);
	}

	/* Even for zero size payload we have to send a packet */
	if (!bytes_sent) {
		DBG_ERR_FMT("Can't %u send bytes", count);
		SET_CLIENT_ERROR(*error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
	}
	DBG_RETURN(bytes_sent);
}