sqlite3 和 boost asio ssl 服务器 sqlite3_prepare_v2 错误
sqlite3 and boost asio ssl server sqlite3_prepare_v2 error
我使用来自这个 example 的 boost asio ssl 服务器。我已经这样修改了代码
private:
void do_handshake()
{
auto self(shared_from_this());
socket_.async_handshake(
boost::asio::ssl::stream_base::server,
[this, self](const boost::system::error_code& error)
{
if (!error)
{
std::cout << "client: " << socket_.lowest_layer().remote_endpoint().address().to_string() << std::endl;
read_header();
}
}
);
}
void read_header()
{
auto self(shared_from_this());
buffer_.clear();
buffer_.resize(protocol::header_size);
boost::asio::async_read(
socket_,
boost::asio::buffer(buffer_),
boost::bind(
&session::read_body,
shared_from_this(),
boost::asio::placeholders::error
)
);
}
void read_body(const boost::system::error_code& error)
{
auto self(shared_from_this());
std::size_t body_length = protocol::Protocol::body_length(buffer_);
buffer_.clear();
buffer_.resize(body_length);
boost::asio::async_read(
socket_,
boost::asio::buffer(buffer_),
boost::bind(
&session::handle_body,
shared_from_this(),
boost::asio::placeholders::error
)
);
}
void handle_body(const boost::system::error_code& error)
{
sqlite3* db;
std::string sql{"SELECT * FROM table1 WHERE id = ?"};
if (sqlite3_open("testdb.db", &db) == SQLITE_OK)
{
std::cout << "connection ok" << std::endl;
}
else
{
std::cout << "connection failed";
}
sqlite3_stmt* stmt;
int res_prepare = sqlite3_prepare_v2(
db,
sql.c_str(),
-1,
&stmt,
NULL
);
if (res_prepare != SQLITE_OK)
{
std::cout << "sqlite3_prepare_v2 returns an error => " << res_prepare << std::endl;
}
std::cout << "parameter count statement = " << sqlite3_bind_parameter_count(stmt) << std::endl;
...
do_write();
}
如果我启动服务器,连接到它并发送消息,我得到以下输出:
connection ok
sqlite3_prepare_v2 returns an error => 1
parameter count statement = 0
连接正常,但 sqlite3_prepare_v2 returns 错误代码 1 (SQLITE_ERROR)
The SQLITE_ERROR result code is a generic error code that is used when no other more specific error code is available.
我认为错误是 boost::asio 异步函数的结果(也许某些东西超出了范围?)但我不知道如何修复它。
您的数据库不符合预期的架构。也许它甚至不存在于您指定的路径中?
我 运行 使用此代码:
#define SQLITE_DEBUG 1
#define SQLITE_ENABLE_EXPLAIN_COMMENTS 1
#define SQLITE_ENABLE_SELECTTRACE 1
#define SQLITE_ENABLE_WHERETRACE 1
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/bind/bind.hpp>
#include <boost/endian/arithmetic.hpp>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <sqlite3.h>
using boost::asio::ip::tcp;
namespace protocol {
enum {
header_size = 4,
};
struct Protocol {
static size_t body_length(std::string const& b)
{
boost::endian::big_int32_t n = 0;
assert(b.size()>=sizeof(n));
memcpy(&n, b.data(), sizeof(n));
return n;
};
};
} // namespace protocol
class session : public std::enable_shared_from_this<session> {
public:
session(boost::asio::ssl::stream<tcp::socket> socket)
: socket_(std::move(socket))
{
}
void start() { do_handshake(); }
private:
void do_handshake()
{
auto self(shared_from_this());
socket_.async_handshake(
boost::asio::ssl::stream_base::server,
[this, self](const boost::system::error_code& error) {
if (!error) {
std::cout << "client: "
<< socket_.lowest_layer()
.remote_endpoint()
.address()
.to_string()
<< std::endl;
read_header();
}
});
}
void read_header()
{
auto self(shared_from_this());
buffer_.clear();
buffer_.resize(protocol::header_size);
boost::asio::async_read(socket_, boost::asio::buffer(buffer_),
boost::bind(&session::read_body,
shared_from_this(),
boost::asio::placeholders::error));
}
void read_body(const boost::system::error_code& error)
{
auto self(shared_from_this());
std::size_t body_length = protocol::Protocol::body_length(buffer_);
buffer_.clear();
buffer_.resize(body_length);
boost::asio::async_read(socket_, boost::asio::buffer(buffer_),
boost::bind(&session::handle_body,
shared_from_this(),
boost::asio::placeholders::error));
}
void handle_body(const boost::system::error_code& error)
{
sqlite3* db;
std::string sql{"SELECT * FROM table1 WHERE id = ?"};
if (sqlite3_open("testdb.db", &db) == SQLITE_OK) {
std::cout << "connection ok" << std::endl;
} else {
std::cout << "connection failed";
}
sqlite3_stmt* stmt;
int res_prepare = sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, NULL);
if (res_prepare != SQLITE_OK) {
std::cout << "sqlite3_prepare_v2 returns an error => "
<< res_prepare << std::endl;
}
std::cout << "parameter count statement = "
<< sqlite3_bind_parameter_count(stmt) << std::endl;
//...
//do_write();
}
void do_read()
{
auto self(shared_from_this());
socket_.async_read_some(
boost::asio::buffer(data_),
[this, self](const boost::system::error_code& ec,
std::size_t length) {
if (!ec) {
do_write(length);
}
});
}
void do_write(std::size_t length)
{
auto self(shared_from_this());
boost::asio::async_write(
socket_, boost::asio::buffer(data_, length),
[this, self](const boost::system::error_code& ec,
std::size_t /*length*/) {
if (!ec) {
do_read();
}
});
}
boost::asio::ssl::stream<tcp::socket> socket_;
char data_[1024];
std::string buffer_;
};
class server {
public:
server(boost::asio::io_context& io_context, unsigned short port)
: acceptor_(io_context, tcp::endpoint(tcp::v4(), port))
, context_(boost::asio::ssl::context::sslv23)
{
context_.set_options(boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::single_dh_use);
context_.set_password_callback(std::bind(&server::get_password, this));
context_.use_certificate_chain_file("server.pem");
context_.use_private_key_file("server.pem",
boost::asio::ssl::context::pem);
context_.use_tmp_dh_file("dh4096.pem");
do_accept();
}
private:
std::string get_password() const { return "test"; }
void do_accept()
{
acceptor_.async_accept([this](const boost::system::error_code& error,
tcp::socket socket) {
if (!error) {
std::make_shared<session>(boost::asio::ssl::stream<tcp::socket>(
std::move(socket), context_))
->start();
}
do_accept();
});
}
tcp::acceptor acceptor_;
boost::asio::ssl::context context_;
};
int main(int argc, char* argv[])
{
try {
if (argc != 2) {
std::cerr << "Usage: server <port>\n";
return 1;
}
boost::asio::io_context io_context;
using namespace std; // For atoi.
server s(io_context, atoi(argv[1]));
io_context.run();
} catch (std::exception& e) {
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
我运行服务器用
./sotest 1237
并使用
模拟客户端
printf '\x00\x00\x00\x04abcd' | openssl s_client -connect localhost:1237
并打印:
当 testdb.db
使用
等“正确”创建时
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE table1 (id int);
INSERT INTO table1 VALUES(1);
INSERT INTO table1 VALUES(2);
INSERT INTO table1 VALUES(3);
COMMIT;
输出:
client: 127.0.0.1
connection ok
parameter count statement = 1
当 test.db 被错误创建时,例如:
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE table1(oops int);
COMMIT;
client: 127.0.0.1
connection ok
sqlite3_prepare_v2 returns an error => 1
parameter count statement = 0
当文件test.db
根本不存在时,输出是一样的:
client: 127.0.0.1
connection ok
sqlite3_prepare_v2 returns an error => 1
parameter count statement = 0
因此,请检查该文件是否存在(在可执行文件 运行 所在的工作目录中)并且可以访问,并且它包含所需的架构。
我使用来自这个 example 的 boost asio ssl 服务器。我已经这样修改了代码
private:
void do_handshake()
{
auto self(shared_from_this());
socket_.async_handshake(
boost::asio::ssl::stream_base::server,
[this, self](const boost::system::error_code& error)
{
if (!error)
{
std::cout << "client: " << socket_.lowest_layer().remote_endpoint().address().to_string() << std::endl;
read_header();
}
}
);
}
void read_header()
{
auto self(shared_from_this());
buffer_.clear();
buffer_.resize(protocol::header_size);
boost::asio::async_read(
socket_,
boost::asio::buffer(buffer_),
boost::bind(
&session::read_body,
shared_from_this(),
boost::asio::placeholders::error
)
);
}
void read_body(const boost::system::error_code& error)
{
auto self(shared_from_this());
std::size_t body_length = protocol::Protocol::body_length(buffer_);
buffer_.clear();
buffer_.resize(body_length);
boost::asio::async_read(
socket_,
boost::asio::buffer(buffer_),
boost::bind(
&session::handle_body,
shared_from_this(),
boost::asio::placeholders::error
)
);
}
void handle_body(const boost::system::error_code& error)
{
sqlite3* db;
std::string sql{"SELECT * FROM table1 WHERE id = ?"};
if (sqlite3_open("testdb.db", &db) == SQLITE_OK)
{
std::cout << "connection ok" << std::endl;
}
else
{
std::cout << "connection failed";
}
sqlite3_stmt* stmt;
int res_prepare = sqlite3_prepare_v2(
db,
sql.c_str(),
-1,
&stmt,
NULL
);
if (res_prepare != SQLITE_OK)
{
std::cout << "sqlite3_prepare_v2 returns an error => " << res_prepare << std::endl;
}
std::cout << "parameter count statement = " << sqlite3_bind_parameter_count(stmt) << std::endl;
...
do_write();
}
如果我启动服务器,连接到它并发送消息,我得到以下输出:
connection ok
sqlite3_prepare_v2 returns an error => 1
parameter count statement = 0
连接正常,但 sqlite3_prepare_v2 returns 错误代码 1 (SQLITE_ERROR)
The SQLITE_ERROR result code is a generic error code that is used when no other more specific error code is available.
我认为错误是 boost::asio 异步函数的结果(也许某些东西超出了范围?)但我不知道如何修复它。
您的数据库不符合预期的架构。也许它甚至不存在于您指定的路径中?
我 运行 使用此代码:
#define SQLITE_DEBUG 1
#define SQLITE_ENABLE_EXPLAIN_COMMENTS 1
#define SQLITE_ENABLE_SELECTTRACE 1
#define SQLITE_ENABLE_WHERETRACE 1
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/bind/bind.hpp>
#include <boost/endian/arithmetic.hpp>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <sqlite3.h>
using boost::asio::ip::tcp;
namespace protocol {
enum {
header_size = 4,
};
struct Protocol {
static size_t body_length(std::string const& b)
{
boost::endian::big_int32_t n = 0;
assert(b.size()>=sizeof(n));
memcpy(&n, b.data(), sizeof(n));
return n;
};
};
} // namespace protocol
class session : public std::enable_shared_from_this<session> {
public:
session(boost::asio::ssl::stream<tcp::socket> socket)
: socket_(std::move(socket))
{
}
void start() { do_handshake(); }
private:
void do_handshake()
{
auto self(shared_from_this());
socket_.async_handshake(
boost::asio::ssl::stream_base::server,
[this, self](const boost::system::error_code& error) {
if (!error) {
std::cout << "client: "
<< socket_.lowest_layer()
.remote_endpoint()
.address()
.to_string()
<< std::endl;
read_header();
}
});
}
void read_header()
{
auto self(shared_from_this());
buffer_.clear();
buffer_.resize(protocol::header_size);
boost::asio::async_read(socket_, boost::asio::buffer(buffer_),
boost::bind(&session::read_body,
shared_from_this(),
boost::asio::placeholders::error));
}
void read_body(const boost::system::error_code& error)
{
auto self(shared_from_this());
std::size_t body_length = protocol::Protocol::body_length(buffer_);
buffer_.clear();
buffer_.resize(body_length);
boost::asio::async_read(socket_, boost::asio::buffer(buffer_),
boost::bind(&session::handle_body,
shared_from_this(),
boost::asio::placeholders::error));
}
void handle_body(const boost::system::error_code& error)
{
sqlite3* db;
std::string sql{"SELECT * FROM table1 WHERE id = ?"};
if (sqlite3_open("testdb.db", &db) == SQLITE_OK) {
std::cout << "connection ok" << std::endl;
} else {
std::cout << "connection failed";
}
sqlite3_stmt* stmt;
int res_prepare = sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, NULL);
if (res_prepare != SQLITE_OK) {
std::cout << "sqlite3_prepare_v2 returns an error => "
<< res_prepare << std::endl;
}
std::cout << "parameter count statement = "
<< sqlite3_bind_parameter_count(stmt) << std::endl;
//...
//do_write();
}
void do_read()
{
auto self(shared_from_this());
socket_.async_read_some(
boost::asio::buffer(data_),
[this, self](const boost::system::error_code& ec,
std::size_t length) {
if (!ec) {
do_write(length);
}
});
}
void do_write(std::size_t length)
{
auto self(shared_from_this());
boost::asio::async_write(
socket_, boost::asio::buffer(data_, length),
[this, self](const boost::system::error_code& ec,
std::size_t /*length*/) {
if (!ec) {
do_read();
}
});
}
boost::asio::ssl::stream<tcp::socket> socket_;
char data_[1024];
std::string buffer_;
};
class server {
public:
server(boost::asio::io_context& io_context, unsigned short port)
: acceptor_(io_context, tcp::endpoint(tcp::v4(), port))
, context_(boost::asio::ssl::context::sslv23)
{
context_.set_options(boost::asio::ssl::context::default_workarounds |
boost::asio::ssl::context::no_sslv2 |
boost::asio::ssl::context::single_dh_use);
context_.set_password_callback(std::bind(&server::get_password, this));
context_.use_certificate_chain_file("server.pem");
context_.use_private_key_file("server.pem",
boost::asio::ssl::context::pem);
context_.use_tmp_dh_file("dh4096.pem");
do_accept();
}
private:
std::string get_password() const { return "test"; }
void do_accept()
{
acceptor_.async_accept([this](const boost::system::error_code& error,
tcp::socket socket) {
if (!error) {
std::make_shared<session>(boost::asio::ssl::stream<tcp::socket>(
std::move(socket), context_))
->start();
}
do_accept();
});
}
tcp::acceptor acceptor_;
boost::asio::ssl::context context_;
};
int main(int argc, char* argv[])
{
try {
if (argc != 2) {
std::cerr << "Usage: server <port>\n";
return 1;
}
boost::asio::io_context io_context;
using namespace std; // For atoi.
server s(io_context, atoi(argv[1]));
io_context.run();
} catch (std::exception& e) {
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
我运行服务器用
./sotest 1237
并使用
模拟客户端printf '\x00\x00\x00\x04abcd' | openssl s_client -connect localhost:1237
并打印:
当
等“正确”创建时testdb.db
使用PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; CREATE TABLE table1 (id int); INSERT INTO table1 VALUES(1); INSERT INTO table1 VALUES(2); INSERT INTO table1 VALUES(3); COMMIT;
输出:
client: 127.0.0.1 connection ok parameter count statement = 1
当 test.db 被错误创建时,例如:
PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; CREATE TABLE table1(oops int); COMMIT;
client: 127.0.0.1 connection ok sqlite3_prepare_v2 returns an error => 1 parameter count statement = 0
当文件
test.db
根本不存在时,输出是一样的:client: 127.0.0.1 connection ok sqlite3_prepare_v2 returns an error => 1 parameter count statement = 0
因此,请检查该文件是否存在(在可执行文件 运行 所在的工作目录中)并且可以访问,并且它包含所需的架构。