1

I write a websocket though boost, and I receive the message though the client in chrome. When I use ws, it works well, I can receive correct msg. but when I use wss, it works bad, and said could not decode a text frame as UTF 8.

the picture is what's wrong is ssl mode. wrong msg in ssl mode

c++ send msg code

  Json::Value jsonMsg;
        jsonMsg["msgType"] = Json::Value("MspServiceStartUp");
        jsonMsg["version"] = Json::Value(std::string(MSP_VERSION));
        ws_->async_write(boost::asio::buffer((void *) jsonMsg.toStyledString().data(), jsonMsg.toStyledString().size()),
                         boost::asio::bind_executor(*strand_, [&, sp](boost::system::error_code ec1,
                                                                      std::size_t bytes_transferred1) {
                             boost::ignore_unused(bytes_transferred1);
                             if (ec1) {
                                 LOG_ERR << "async write failed, ec = " << ec1 << ", msg = "
                                         << ec1.message();
                                 return;
                             }
                             // Clear the buffer
                             buffer_->consume(buffer_->size());
                             task();
                         }));
    }

js code

var ws=new WebSocket("wss://localhost.com:17801/");
ws.onopen=()=>{console.log('ws open')};
ws.onclose=()=>{console.log('ws close')};
ws.onmessage=(msg)=>{console.log('ws onMessage');console.log(msg)};

Where does this odd character come from? What is the problem? How to fix this ?

vainman
  • 377
  • 1
  • 5
  • 18
  • I don't get it how it can work. First `toStyledString` returns string by value, so affer `data()` you have dangling pointer. Second, `async_write` returns immediately so jsonMsg can be destroyed before message will be sent. – rafix07 Jun 26 '19 at 12:35

1 Answers1

3

The problem is with sending data. async_write() ends immediately, it doesn't make a copy of data buffer, you have to ensure that data passed into boost::asio::buffer lives until the full message will be sent.

Even if we added some delay code between async_write and ending brace {:

async_write(boost::asio::buffer((void *) jsonMsg.toStyledString().data(), ..));
... some code waiting until write is completed
}

this code will not work also, because toStyledString returns string by value. So temporary string is created, string::data() is called, async_write() ends, and you have dangling pointer inside task initiated by async_write().

Quick solution, prolong lifetime of string for example by using smart pointer:

std::shared_ptr<std::string> buf(std::make_shared<std::string>(jsonMsg.toStyledString()));
ws_->async_write(boost::asio::buffer(*buf),
                 boost::asio::bind_executor(*strand_, 
                 [&, sp, buf](boost::system::error_code ec1,
                             std::size_t bytes_transferred1) 
                 {
                         boost::ignore_unused(bytes_transferred1);
                         if (ec1) {
                             LOG_ERR << "async write failed, ec = " << ec1 << ", msg = "
                                     << ec1.message();
                             return;
                         }
                         // Clear the buffer
                         buffer_->consume(buffer_->size());
                         task();
                 }));

pass buf by boost::asio::buffer(*buf), and capture it by value inside lambda: [&,sp,buf].

rafix07
  • 20,001
  • 3
  • 20
  • 33
  • 1
    Bro, I gotta thank you ,this solve my problem, but I haven't figure out. If this is wrong ,why it works well in WS in all computer ,and in WSS, it works well in most of our classmates' device except one. – vainman Jun 27 '19 at 06:58
  • 1
    It is hard to say why it works. The issues in your original code introduce undefined behabiour. With UB everything may happen, even the code may look like working, but it is just lucky break. – rafix07 Jun 27 '19 at 10:31
  • Because WS is much faster than WSS, so the I/O finishes before the temporary goes out of scope. – Vinnie Falco Nov 09 '19 at 17:41