Приветствую.
Даже спрашивать уже опасаюсь, опять отдельные личности с большим самомнением начнут объяснять какой я тупой, но все таки попробую, вдруг кому не сложно )
Код класс ниже, теста ради из одного потока все работало, пока не решил вызвать CPush::Send из другого и все упало. Думал сначала что дело в std::stringstream request, которая была локальная - поднял ее до класса и не помогло.
Хоть намек бы к пониманию, где косяк, заранее спасибо за не равнодушие )
class CPush
{
private:
std::stringstream request;
boost::asio::io_service * pio_service;
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> * psocket;
boost::asio::streambuf response;
bool verify_certificate(bool preverified, boost::asio::ssl::verify_context & ctx);
void handle_connect(const boost::system::error_code & error);
void handle_handshake(const boost::system::error_code & error);
void handle_write(const boost::system::error_code & error);//, size_t bytes_transferred
void handle_read_status(const boost::system::error_code & error);
void handle_read_header(const boost::system::error_code & error);
void handle_read_content(const boost::system::error_code & error);
public:
CPush(void){}
void LoopStart(void);
void LoopStop(void);
void Send(const std::string tokens, const std::string cmd);
};
Реализация
bool CPush::verify_certificate(bool preverified, boost::asio::ssl::verify_context & ctx)
{
char subject_name[256];
X509 * cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
std::cout << "Verifying " << subject_name << std::endl;
return preverified;
}
void CPush::handle_connect(const boost::system::error_code & error)
{
if (error)
std::cerr << "Connect failed: " << error.message() << std::endl;
else
{
// Support for Server Name Indication (SNI)
SSL_set_tlsext_host_name(psocket->native_handle(), GOOGLE_HOST);
psocket->async_handshake(boost::asio::ssl::stream_base::client,
boost::bind(&CPush::handle_handshake,
this,
boost::asio::placeholders::error));
std::cout << "Connection OK!" << std::endl;
}
}
void CPush::handle_handshake(const boost::system::error_code & error)
{
if (error)
std::cerr << "Handshake failed: " << error.message() << std::endl;
else
{ }
}
void CPush::handle_write(const boost::system::error_code & error)
{
if (error)
std::cerr << "Write failed: " << error.message() << std::endl;
else
{
boost::asio::async_read_until(*psocket,
response, "\r\n",
boost::bind(&CPush::handle_read_status,
this,
boost::asio::placeholders::error));
std::cout << "Sending request OK!" << std::endl;
}
}
void CPush::handle_read_status(const boost::system::error_code & error)
{
if (error)
std::cout << "Error read status: " << error.message() << std::endl;
else
{
// Check that response is OK.
std::istream response_stream(&response);
std::string http_version;
response_stream >> http_version;
unsigned int status_code;
response_stream >> status_code;
std::string status_message;
std::getline(response_stream, status_message);
if (!response_stream || http_version.substr(0, 5) != "HTTP/")
{
std::cout << "Invalid response\n";
return;
}
if (status_code != 200)
{
std::cout << "Response returned with status code ";
std::cout << status_code << "\n";
// return;
}
// Read the response headers, which are terminated by a blank line.
boost::asio::async_read_until(*psocket,
response, "\r\n\r\n",
boost::bind(&CPush::handle_read_header,
this,
boost::asio::placeholders::error));
}
}
void CPush::handle_read_header(const boost::system::error_code & error)
{
if (error)
std::cout << "Error read header: " << error.message() << std::endl;
else
{
// Process the response headers.
std::istream response_stream(&response);
std::string header;
while (std::getline(response_stream, header) && header != "\r")
std::cout << header << "\n";
std::cout << "\n";
// Write whatever content we already have to output.
if (response.size() > 0)
std::cout << &response;
// Start reading remaining data until EOF.
boost::asio::async_read(*psocket,
response,
boost::asio::transfer_at_least(1),
boost::bind(&CPush::handle_read_content,
this,
boost::asio::placeholders::error));
}
}
void CPush::handle_read_content(const boost::system::error_code & error)
{
if (error)
{
if (error != boost::asio::error::eof)
std::cout << "Error read content: " << error.message() << std::endl;
}
else
{
// Write all of the data that has been read so far.
std::cout << &response;
// Continue reading remaining data until EOF.
boost::asio::async_read(*psocket,
response,
boost::asio::transfer_at_least(1),
boost::bind(&CPush::handle_read_content,
this,
boost::asio::placeholders::error));
}
}
void CPush::LoopStart(void)
{
boost::asio::io_service io_service;
boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::resolver::query query(GOOGLE_HOST, GOOGLE_PORT);
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
boost::asio::ssl::context context(boost::asio::ssl::context::sslv23);
context.set_default_verify_paths();
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket(io_service, context);
socket.set_verify_mode(boost::asio::ssl::context::verify_none);
socket.set_verify_callback(boost::bind(&CPush::verify_certificate, this, _1, _2));
psocket = &socket;
pio_service = &io_service;
boost::asio::async_connect(psocket->lowest_layer(),
iterator,
boost::bind(&CPush::handle_connect,
this,
boost::asio::placeholders::error));
io_service.run();
}
void CPush::Send(const std::string tokens, const std::string cmd)
{
std::string json("{\"registration_ids\":[" + tokens + "],"
"\"notification\":null,"
....
"\"priority\":\"high\","
"\"time_to_live\":15}");
request << "POST " << GOOGLE_API << " HTTP/1.1\r\n"
<< "Host: " << GOOGLE_HOST << "\r\n" // << ":" << port
<< "Content-Type: application/json; charset=utf-8\r\n"
<< "Content-Length: " << json.size() << "\r\n"
<< "Authorization: key=" << push_key << "\r\n"
<< "\r\n"
<< json;
std::cout << "Sending request...\n" << request.str() << std::endl;
boost::asio::async_write(*psocket,
boost::asio::buffer(request.str()),
boost::bind(&CPush::handle_write,
this,
boost::asio::placeholders::error));
}
void CPush::LoopStop(void)
{
if (!pio_service->stopped()) pio_service->stop();
}