10

I've recently decided to use boost::asio for my sockets, but now I'm running into a problem: documentation seems to be lacking.

What I want to do is write a function that will send a message consisting of the following structure:

  • 2 bytes of an unsigned integer (uint16_t) for an opcode all bytes
  • all bytes after that (a flexible amount) being any type of data (cast to void*). This data will be operated upon based on the opcode

For example, if the opcode is 1, perhaps defined as OPCODE_LOGIN, then the bytes following the opcode could contain a string containing login information, etc.

bool sendMessage(tcp::socket* sock, uint16_t opcode, void* data)
{
    void* fullData = malloc(sizeof(uint16_t) + sizeof(data));
    memcpy(fullData, (void*)opcode, sizeof(opcode));
    memcpy(&fullData + sizeof(uint16_t), data, sizeof(data));
    boost::asio::write(sock, boost::asio::buffer(fullData, sizeof(fullData)));
    // by the way, at this point, is it safe to delete fullData to prevent memory leaks?
    return true;

}

This does not compile, however. I get a cryptic compilation error regarding the call to write:

1>------ Build started: Project: client, Configuration: Debug Win32 ------
1>  main.cpp
1>c:\boost\boost_1_47\boost\asio\impl\write.hpp(46): error C2228: left of '.write_some' must have class/struct/union
1>          type is 'boost::asio::basic_stream_socket<Protocol> '
1>          with
1>          [
1>              Protocol=boost::asio::ip::tcp
1>          ]
1>          did you intend to use '->' instead?
1>          c:\boost\boost_1_47\boost\asio\impl\write.hpp(59) : see reference to function template instantiation 'size_t boost::asio::write<SyncWriteStream,ConstBufferSequence,boost::asio::detail::transfer_all_t>(SyncWriteStream &,const ConstBufferSequence &,CompletionCondition,boost::system::error_code &)' being compiled
1>          with
1>          [
1>              SyncWriteStream=boost::asio::ip::tcp::socket *,
1>              ConstBufferSequence=boost::asio::mutable_buffers_1,
1>              CompletionCondition=boost::asio::detail::transfer_all_t
1>          ]
1>          c:\users\josh\documents\visual studio 2010\projects\client\client\main.cpp(53) : see reference to function template instantiation 'size_t boost::asio::write<boost::asio::ip::tcp::socket*,boost::asio::mutable_buffers_    1>(SyncWriteStream &,const ConstBufferSequence &)' being compiled
1>          with
1>          [
1>              SyncWriteStream=boost::asio::ip::tcp::socket *,
1>              ConstBufferSequence=boost::asio::mutable_buffers_1
1>          ]
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

As you can see, the error message points directly into Boost's write.hpp file, and not to any of my own code.. I believe I'm calling write() incorrectly in some way, but after a solid hour of googling and researching references and examples (all of which either use another overloaded write() or are using data with specifically defined sizes/structures), I haven't been able to determine what exactly I'm doing wrong here.

Can someone help me debug this compilation error?

Sam Miller
  • 23,808
  • 4
  • 67
  • 87
Josh1billion
  • 14,837
  • 8
  • 38
  • 48
  • This is probably irrelevant at this point, but I'd like to point out that `sizeof(data)` is equivalent to `sizeof(void *)`, which is most definitely not what you want here. You should pass the data's actual length as another parameter. `sizeof(fullData)` suffers from the same problem. – abel1502 Aug 10 '21 at 08:54

1 Answers1

16

documentation seems to be lacking

The highest voted question in is about documentation, start there :-)

Can someone help me debug this compilation error?

The write() free function expects a reference type as the first parameter. Not a pointer as you have in your example

bool sendMessage(tcp::socket* sock, uint16_t opcode, void* data)
{
    void* fullData = malloc(sizeof(uint16_t) + sizeof(data));
    memcpy(fullData, (void*)opcode, sizeof(opcode));
    memcpy(&fullData + sizeof(uint16_t), data, sizeof(data));
    boost::asio::write(*sock, boost::asio::buffer(fullData, sizeof(fullData)));
    //                 ^^^^ correct type now
    // by the way, at this point, is it safe to delete fullData to prevent memory leaks?
    return true;
}

at this point, is it safe to delete fullData to prevent memory leaks?

Yes, write() is a blocking call. It is done with your buffer when the call returns. I strongly suggest making this code exception safe however, look into using new and a boost::scoped_array if you wish to create your buffer with dynamic storage duration.

Community
  • 1
  • 1
Sam Miller
  • 23,808
  • 4
  • 67
  • 87
  • That worked great, thanks! :) And I did see the "highest voted question" many times in my googling, and I followed its advice, but not to much avail... the examples used different overloaded versions of write(), the class reference built upon many boost streams that I'm not familiar with, etc.. – Josh1billion Oct 16 '11 at 21:40