Opened 11 years ago

#6661 new Bugs

Different behavior on WIN and Linux

Reported by: cupper.jj@… Owned by: chris_kohlhoff
Milestone: To Be Determined Component: asio
Version: Boost 1.49.0 Severity: Problem
Keywords: udp, available, receive Cc:

Description

Hi, I've found a different behavior at use of some functions with UDP protocol.

Look at this code

	io_service ios;
	
	udp::endpoint to(address::from_string("127.0.0.1"), port);
	udp::socket sender(ios, udp::v4());
	udp::socket receiver(ios, udp::endpoint(udp::v4(), port));
	
	const char buf[] = "Some test data...";
	const size_t buf_len = sizeof(buf);
	
	char read_buf[buf_len];
	char half_read_buf[buf_len / 2];
	
	sender.send_to(buffer(buf, buf_len), to);
	try
	{
		udp::endpoint sender_point;
		receiver.receive_from(buffer(half_read_buf, sizeof(half_read_buf)),
								sender_point);
	}
	catch(exception& ex)
	{
		string str = ex.what();
		cerr << "Exception: "<< ex.what() << endl;
	}
	cout << string(half_read_buf, sizeof(half_read_buf)) << endl;
	
	sender.send_to(buffer(buf, buf_len), to);
	sender.send_to(buffer(buf, buf_len), to);
	
	cout << "Available: " << receiver.available() << endl;
	receiver.receive(buffer(read_buf, sizeof(read_buf)));
	
	cout << "Available: " << receiver.available() << endl;
	receiver.receive(buffer(read_buf, sizeof(read_buf)));
	
	cout << "Available: " << receiver.available() << endl;

Here we are reading half an datagramm and use socket::available() to look how much data into the socket. Execute this code on WIN32 and you get this output

Exception: receive_from: The message was too large for the specified buffer and (for unreliable protocols only) any trailing portion of the message that did not fit into the 
buffer has been discarded.
Some test
Available: 36
Available: 18
Available: 0

Execute it on Linux and you get

Some test
Available: 18
Available: 18
Available: 0

It looks strange.
Look into source

boost/asio/detail/impl/socket_ops.ipp
-------------------------------------
int recvfrom(socket_type s, buf* bufs, size_t count, int flags,
    socket_addr_type* addr, std::size_t* addrlen,
    boost::system::error_code& ec)
{
...
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
  int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count,
        &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec);
  *addrlen = (std::size_t)tmp_addrlen;
...
  if (result != 0)
    return socket_error_retval;
  ec = boost::system::error_code();
  return bytes_transferred;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
  msghdr msg = msghdr();
  init_msghdr_msg_name(msg.msg_name, addr);
  msg.msg_namelen = *addrlen;
  msg.msg_iov = bufs;
  msg.msg_iovlen = count;
  int result = error_wrapper(::recvmsg(s, &msg, flags), ec);
  *addrlen = msg.msg_namelen;
  if (result >= 0)
    ec = boost::system::error_code();
  return result;
}

For WIN32 uses functions family WSARecv(http://msdn.microsoft.com/en-us/library/windows/desktop/ms741686(v=vs.85).aspx) they return status of error. And one of which is

WSAEMSGSIZE 
The message was too large for the specified buffer and (for unreliable protocols only) any trailing portion of the message that did not fit into the buffer has been discarded.

For Linux uses functions family recv (http://linux.die.net/man/2/recv). They return the length of the message on successful completion or -1 and set status in errno if was error. But for them no the error if buffer length less that a received datagram.

But if we uses function recvfrom, it sets this error into struct msghdr in the msg_flags

MSG_TRUNC
indicates that the trailing portion of a datagram was discarded because the datagram was larger than the buffer supplied.

And also about function basic_datagram_socket::available. For WIN32 it returns length of all datagrams in the socket BUT for linux in returns length a one datagramm.

Change History (0)

Note: See TracTickets for help on using tickets.