receive_from - An invalid argument was supplied - boost

I've tried using the example code for a synchronous UDP client from the boost documentation ( http://www.boost.org/doc/libs/1_58_0/doc/html/boost_asio/tutorial/tutdaytime4/src.html ), I've only removed the 'sending' part of the example:
#include <iostream>
#include <boost/array.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::udp;
int main(int argc, char* argv[])
{
try
{
boost::asio::io_service io_service;
udp::socket socket(io_service);
socket.open(udp::v4());
boost::array<char, 128> recv_buf;
udp::endpoint sender_endpoint;
size_t len = socket.receive_from(
boost::asio::buffer(recv_buf), sender_endpoint); // Causes the exception "An invalid argument was supplied".
std::cout.write(recv_buf.data(), len);
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
I haven't made any other changes to the example code, and I don't see anything wrong with it, so why is it creating the exception? I have no firewall active which could be blocking anything.

You never bound your socket to an endpoint. You need to create a boost::asio::ip::udp::endpoint and bind your socket to it. This endpoint represents the ip address and the port that you will be receiving packets on.
See the docs here:
http://www.boost.org/doc/libs/1_58_0/doc/html/boost_asio/reference/basic_datagram_socket/bind.html

Related

Boost using async_write sends strange data

I'm trying to develop a simple chat program using Boost. I came accross strange situation. I use netcat to listen at specific port while I run the program that's sending a simple text. Connection is established but the text is messed up. Actually instead of whole line I sometimes get one random characters or two. Im putting the code down below:
#include "lib/client.h"
#include <boost/asio.hpp>
#include <boost/asio/io_service.hpp>
#include <iostream>
#include <thread>
#include <string>
int main(int argc, char* argv[]){
if(argc != 3){
std::cout << "Wrong use. After specifying executable, add host and port\n";
return 0;
}
boost::asio::io_service io_service;
boost::asio::ip::tcp::resolver resolver(io_service);
auto endpoint = resolver.resolve({argv[1],argv[2]});
Client c(io_service, endpoint);
std::thread t([&io_service](){ io_service.run();});
std::string text = "Welcome host!";
c.add_msg_to_deque(text);
t.join();
c.close();
return 0;
}
And here are client methods:
#include "../lib/client.h"
#include <boost/asio.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/array.hpp>
#include <deque>
#include <iostream>
#include <string>
void Client::connect(boost::asio::ip::tcp::resolver::iterator endpoint){
boost::asio::async_connect(socket, endpoint,
[this](boost::system::error_code ec, boost::asio::ip::tcp::resolver::iterator)
{
if (!ec)
{
}
});
}
void Client::close()
{
ios.post([this]() { socket.close(); });
}
void Client::add_msg_to_deque(const std::string& msg){
ios.post([this,msg](){
write_msg_deque.push_back(msg);
send_msg();
});
}
void Client::send_msg(){
boost::array<char,128> buf;
std::string temp_string = write_msg_deque.front();
std::copy(temp_string.begin(),temp_string.end(),buf.begin());
boost::asio::async_write(socket, boost::asio::buffer(buf,temp_string.size()),[this](boost::system::error_code ec, std::size_t){
if(!ec){
write_msg_deque.pop_front();
if(!write_msg_deque.empty())
send_msg();
}
else{
socket.close();
}
});
}
You are using async_write with local data it is bad idea. async_write returns immediately. After calling async_write your method send_msg terminates, so local data (buf array) is destroyed before your message is sent. You can use a synchronous version of IO functions to send data or keep buf as member of your class to provide data exists until data is sent successfully.

Getting wrong output from boost lock free spsc queue

I am trying to implement lock free queue of user defined data type using boost library, but I am getting wrong result.
Please help me out where I am doing wrong.
#include <boost/lockfree/spsc_queue.hpp>
#include <thread>
#include <iostream>
#include <string.h>
#include <time.h>
class Queue
{
private:
unsigned char *m_data;
int m_len;
public:
Queue(unsigned char *data,int len);
Queue(const Queue &obj);
~Queue();
Queue & operator =(const Queue &obj);
unsigned char *getdata()
{
return m_data;
}
int getint()
{
return m_len;
}
};
Queue::Queue(unsigned char* data, int len)
{
m_len=len;
m_data=new unsigned char[m_len];
memcpy(m_data,data,m_len);
}
Queue::Queue(const Queue& obj)
{
m_len= obj.m_len;
m_data=new unsigned char[m_len];
memcpy(m_data,(unsigned char *)obj.m_data,m_len);
}
Queue::~Queue()
{
delete[] m_data;
m_len=0;
}
Queue & Queue::operator =(const Queue &obj)
{
if(this != &obj)
{
m_len=obj.m_len;
m_data=new unsigned char[m_len];
memcpy(m_data,(unsigned char *)obj.m_data,m_len);
}
return *this;
}
boost::lockfree::spsc_queue<Queue*> q(10);
void produce()
{
int i=0;
unsigned char* data=(unsigned char *)malloc(10);
memset(data,1,9);
Queue obj(data,10);
Queue *pqueue=&obj;
printf("%d\n",pqueue->getint());
q.push(pqueue);
}
void consume()
{
Queue *obj;
q.pop(&obj);
printf("%d\n",obj->getint());
}
int main(int argc, char** argv) {
// std::thread t1{produce};
// std::thread t2{consume};
//
// t1.join();
// t2.join();
produce();
consume();
return 0;
}
As per boost::lockfree::queue requirements I created following in class.
Copy Constructor
Assignment Operator
Destructor
Please let me know if anything other requires.
Thanks.
You're using malloc in C++.
You die.
You have 2 lives left.
Seriously, don't do that. Especially since using it with delete[] is clear cut Undefined Behaviour.
Sadly you lose another life here:
Queue obj(data,10);
Queue *pqueue=&obj;
q.push(pqueue);
You store a pointer to a local. More Undefined Behaviour
You have 1 life left.
Last life at
q.pop(&obj);
You pop using an iterator. It will be treated as an output iterator.
You get a return that indicates the number of elements popped, and items
will be written to &obj[0], &obj[1], &obj[2], etc.
Guess what? Undefined Behaviour.
See also: Boost spsc queue segfault
You died.
You're already dead. But you forsake your afterlife with
printf("%d\n",obj->getint());
Since pop might not have popped anything (the queue may have been empty), this in itself is Undefined Behaviour.
The funny part is, you talk about all these constructor requirements but you store pointers in the lockfree queue...?! Just write it:
typedef std::vector<unsigned char> Data;
class Queue {
private:
Data m_data;
public:
Queue(Data data) : m_data(std::move(data)) {}
Queue() : m_data() {}
unsigned char const *getdata() const { return m_data.data(); }
size_t getint() const { return m_data.size(); }
};
boost::lockfree::spsc_queue<Queue> q(10);
Live On Coliru
Notes:
you need to make the consumer check the return code of pop. The push might not have happened, and lock free queues don't block.
you don't need that contraption. Just pass vectors all the way:
C++ Code
Live On Coliru
#include <boost/lockfree/spsc_queue.hpp>
#include <thread>
#include <iostream>
#include <vector>
typedef std::vector<unsigned char> Queue;
boost::lockfree::spsc_queue<Queue> q(10);
void produce() {
Queue obj(10, 1);
std::cout << __FUNCTION__ << " - " << obj.size() << "\n";
q.push(std::move(obj));
}
void consume() {
Queue obj;
while (!q.pop(obj)) { }
std::cout << __FUNCTION__ << " - " << obj.size() << "\n";
}
int main() {
std::thread t1 {produce};
std::thread t2 {consume};
t1.join();
t2.join();
}

Reading data with boost asio on client

I am learning boost asio and have mistake. I have written simple client ( I can send data from it but when I read data I cant even compile it) I used protocol buffer to serialize data . So file #include "test.pb.h" is probuffer class
My code client :
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/thread/thread.hpp>
#include <cstdlib>
#include <iostream>
#include <string>
#include <thread>
#include "test.pb.h"
using boost::asio::ip::tcp;
int main(int argc, char** argv)
{
try
{
// connect to the server:
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
std::string const server_address = "localhost";
std::string const server_port = "10000";
tcp::resolver::query query(server_address, server_port);
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::socket socket(io_service);
boost::asio::connect(socket, endpoint_iterator);
//while ( true)
{
Person p = Person();
p.set_id(22);
p.set_name("Jack vorobey");
// std::cout << p.id();
// std::cout << p.name();
std::string data; // this will hold serialized data
bool ok = p.SerializeToString(&data);
assert(ok);
// std::cout << data.size() << std::endl;
boost::asio::write(socket, boost::asio::buffer(data))
boost::asio::read(socket, boost::asio::buffer(data));;
// break; // Connection closed cleanly by peer.
// std::cout << data.size() << std::endl; // shows a reduction in amount of
remaining data
// boost::asio::read(socket, boost::asio::buffer(data) /*,
}
boost::asio::transfer_exactly(65536) */);
}
catch (std::exception& e)
{
//std::cerr << e.what(luuu) << std::endl;
}
std::cout << "\nClosing";
std::string dummy;
}
The code of my mistake I dont understand :
error C2679: binary '=' : no operator found which takes a right-hand operand of type 'const boost::asio::const_buffer' (or there is no acceptable conversion)
1> c:\local\boost_1_55_0\boost\asio\buffer.hpp(136): could be 'boost::asio::mutable_buffer &boost::asio::mutable_buffer::operator =(const boost::asio::mutable_buffer &)'
1> while trying to match the argument list '(boost::asio::mutable_buffer, const boost::asio::const_buffer)'
This is because template<typename Elem, typename Traits, typename Allocator> const_buffers_1 buffer(const std::basic_string<Elem, Traits, Allocator> &) returns an instance of const_buffers_1 (which is a model of ConstBufferSequence concept). Certainly, you cannot read data into a constant buffer.
Do not read data into a std::string, because it's not intended for that (note that its c_str() and data() member functions return const char*). Instead, allocate another buffer or use asio::streambuf.
You can use a streambuf, or specify the (preallocated!) size:
#include <boost/asio.hpp>
#include <string>
using boost::asio::ip::tcp;
int main()
{
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
tcp::socket socket(io_service);
boost::asio::connect(socket, resolver.resolve(tcp::resolver::query("localhost", "10000")));
std::string request("request");
boost::asio::write(socket, boost::asio::buffer(request));
#if 0
std::string response;
response.resize(32);
boost::asio::read(socket, boost::asio::buffer(&response[0], response.size()));
#else
boost::asio::streambuf response;
boost::asio::read(socket, response);
#endif
}

ZeroMQ PUB/SUB example won't work from EC2 to private IP

I am a noob to zeromq and I'm trying to use it to message from an Ubuntu 12.04 micro instance on AWS to my home PC. Here is the Subscriber code which I run on my home pc under msvc++:
#include "stdafx.h"
#include <string>
#include <iostream>
#include "zmq.hpp"
static std::string s_recv (zmq::socket_t &socket) {
zmq::message_t message;
socket.recv(&message);
return std::string(static_cast<char*>(message.data()), message.size()-1);
}
int main () {
zmq::context_t context (1);
zmq::socket_t subscriber (context, ZMQ_SUB);
std::cout << "Connecting to port 5556..." << std::endl;
subscriber.connect("tcp://ec2-23-22-38-77.compute-1.amazonaws.com:5556");
const char *filter ="Sending ";
subscriber.setsockopt(ZMQ_SUBSCRIBE, filter ,strlen(filter));
int update_nbr=0;
for (update_nbr=0; update_nbr<100; update_nbr++){
zmq::message_t update;
std::string msg_s=s_recv(subscriber);
std::cout<<"Received something..."<<msg_s<<std::endl;
}
return 0;
}
and here is the publisher code I am running on the AWS instance, compiled by g++
#include <string>
#include <iostream>
#include "zmq.hpp"
static std::string s_recv (zmq::socket_t &socket) {
zmq::message_t message;
socket.recv(&message);
return std::string(static_cast<char*>(message.data()), message.size()-1);
}
int main () {
// Prepare our context and socket
zmq::context_t context (1);
zmq::socket_t publisher (context, ZMQ_PUB);
std::cout << "Binding to port 5556..." << std::endl;
publisher.bind("tcp://*:5556");
int cnt =0;
while(1){
char buffer[30];
int msgn=0;
msgn=snprintf(buffer, 30, "Sending number %d", cnt);
std::cout<<buffer<<std::endl;
zmq::message_t message(30);
memcpy((void*) message.data(), buffer,30);
publisher.send(message);
sleep(1);
cnt++;
}
return 0;
}
Both computers have version ZeroMQ 3.2.3 installed.
When I run both locally on the AWS instance (replacing the tcp address as "tcp://localhost:5556") it works fine and same when both are on my home-pc however nothing happens when I run them on different IP addresses.
Am I using the wrong address for the amazon instance? Is it formatted wrongly? I can't help but feel there is just something really basic that I'm doing wrong because this is all pretty new to me. If you need any more info let me know. Any help greatly appreciated, thanks.

Why doesn't this boost asio code work correctly?

This boost udp server doesn't function as expected.
It is identical to the blocking UDP echo server EXCEPT for a minor change.
I'm using a different socket to return the response, i.e. sock2.
Now this code works perfectly if the client is on the same machine as the server.
But the moment I run this on a different machine, the response is not received.
However, if I change the sending socket to be sock rather than sock2 it does work
across machines.
Any idea why that would be? wireshark is not showing any errors at all. Client uses random source port, but then calls recv_from on the same random port. Server sends response back to that same port number that the client then listens on.
#include <cstdlib>
#include <iostream>
#include <boost/asio.hpp>
using boost::asio::ip::udp;
enum { max_length = 1024 };
void server(boost::asio::io_service& io_service, short port)
{
udp::socket sock(io_service, udp::endpoint(udp::v4(), port));
udp::socket sock2(io_service, udp::endpoint(udp::v4(), 0));
for (;;)
{
char data[max_length];
udp::endpoint sender_endpoint;
size_t length = sock.receive_from(
boost::asio::buffer(data, max_length), sender_endpoint);
printf("Got data, sending response to %s:%d\n", sender_endpoint.address().to_string().c_str(), sender_endpoint.port());
sock2.send_to(boost::asio::buffer(data, length), sender_endpoint);
}
}
int main(int argc, char* argv[])
{
try
{
if (argc != 2)
{
std::cerr << "Usage: blocking_udp_echo_server <port>\n";
return 1;
}
boost::asio::io_service io_service;
using namespace std; // For atoi.
server(io_service, atoi(argv[1]));
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
Answering my own question again!
Check there is no firewall software running on the other machine!. It turns out that the windows machine running in the VM was running a windows firewall.
I didn't immediately suspect this because when I send the UDP response on the original socket using the port number passed into the server, it worked.
I guess the windows firewall is maintaining some state.

Resources