void DatagramSocket::send(const DatagramPacket& packet) throw(S1004LibException) {
    bool success= false;
    sockaddr_in recipient;

    recipient.sin_family= AF_INET;
    recipient.sin_port= htons(packet.getPort());
    vector<InetAddress> results= InetAddress::getByName(packet.getAddress());

    for(auto it= results.begin(); it != results.end(); it++) {
        int nBytes;
        inet_pton(recipient.sin_family, it->getHostAddress().c_str(), &(recipient.sin_addr));
        nBytes= sendto(udpSocket, packet.getData().c_str(), packet.getLength(), 0, 
            (struct sockaddr *) &recipient, sizeof(recipient));

        success= success || (nBytes >= 0);
    }
    if (!success) {
        stringstream msg(stringstream::out);

        msg << "Error sending packet to " << packet.getAddress() << ":" << packet.getPort();
        throw S1004LibException(msg.str());
    }

}
//==============================================================================
// PlainDatagramSocketImpl::receive
//
//==============================================================================
void PlainDatagramSocketImpl::receive(DatagramPacket& p)
{
	testSocketIsValid();

	sockaddr_in remoteAddr;
	cel_socklen_t addrLen;
	sockaddr* pRemoteAddr = reinterpret_cast<struct sockaddr*>(&remoteAddr);
	int recvLength;

	//
	// The following code is placed within a while() block to attempt to unify
	// the behaviour on multiple platforms.  If this datagram socket has been
	// used to send a dataram packet, an ICMP response may be received to
	// indicate that the send request was unsuccessful.  This behaviour is not
	// always helpful and is not guaranteed to occur (but seems to on Windows).
	// There is a far greater liklihood of this behaviour occurring on all platforms
	// when the socket has been connected to a particular host.  For this reason,
	// connect errors are ignored unless the socket has been connected.
	//
	while(true)
	{
		// simulate SO_TIMEOUT
		if(m_nTimeoutMS && !NetUtils::SelectSocket(m_rpSocketDescriptor.get(), m_nTimeoutMS,true,false))
		{
			static const String err(QC_T("receive timed out"));
			throw SocketTimeoutException(err);
		}

		int flags = 0;
		addrLen = sizeof(remoteAddr);
		recvLength = recvfrom(m_rpSocketDescriptor->getFD(),
		                      (char*) p.getData(),
		                      p.getLength(),
		                      flags,
		                      pRemoteAddr,
		                      &addrLen);

		if(recvLength < 0)
		{
			const int errorNum = NetUtils::GetLastSocketError();

			// Failure of recvfrom may be cause by the buffer length being smaller
			// than the message (in which case we silently ignore it, and set the
			// received length equal to the buffer length supplied), or due to
			// some other serious problem which will result in a SocketException
			//
			if(errorNum == QC_EMSGSIZE)
			{
				recvLength = p.getLength();
				break;
			}
			else if(!isConnected() && (errorNum == QC_ECONNRESET || errorNum == QC_ECONNABORTED || errorNum == QC_EHOSTUNREACH))
			{
				// See detailed comment above
				continue;
			}
			else
			{
				static const String err(QC_T("error calling recvfrom "));
				String errMsg = err + NetUtils::GetSocketErrorString(errorNum);
				throw SocketException(errMsg);
			}
		}
		else
		{
			break;
		}
	}
	
	//
	// Note: this test should migrate to the InetAddress class
	//
	if(addrLen != sizeof(sockaddr_in))
	{
		static const String err(QC_T("recvfrom() returned invalid address size"));
		throw SocketException(err);
	}

	//
	// Update the DatagramPacket with the address/length info
	//
	p.setPort(ntohs(remoteAddr.sin_port));
	p.setAddress(InetAddress::FromNetworkAddress(pRemoteAddr, addrLen).get());
	p.setLength(recvLength);

	if(Tracer::IsEnabled())
	{
		Tracer::TraceBytes(Tracer::Net, Tracer::Low, QC_T("Datagram rcvd:"), p.getData(), recvLength);
	}
}
//==============================================================================
// PlainDatagramSocketImpl::send
//
//==============================================================================
void PlainDatagramSocketImpl::send(const DatagramPacket& p)
{
	testSocketIsValid();

	int flags = 0;
	struct sockaddr* to=0;
	struct sockaddr_in sa;

	if(isConnected())
	{
		if(p.getAddress() && !(m_rpRemoteAddr->equals(*(p.getAddress()))))
		{
			throw IllegalArgumentException(QC_T("Address in datagram packet does not match connected address"));
		}
		if(p.getPort()!= -1 && p.getPort()!=m_remotePort)
		{
			throw IllegalArgumentException(QC_T("Port in datagram packet does not match connected port"));
		}
	}
	else
	{
		//
		// If the socket is not connected, then the passed datagram packet must contain
		// valid information.
		//
		if(!p.getAddress() || p.getPort()==-1)
		{
			throw IllegalArgumentException(QC_T("datagram packet does not contain required address/port information"));
		}
		//
		// Use the InetAddress and port contained in the packet to 
		// create and initialize a sockaddr_in structure.
		//
		::memset(&sa, 0, sizeof(sa));
		sa.sin_family = AF_INET;
		sa.sin_port = htons(p.getPort()); // convert port to network byte order 
		::memcpy(&sa.sin_addr, p.getAddress()->getAddress(), p.getAddress()->getAddressLength());
		to = reinterpret_cast<struct sockaddr*>(&sa);
	}

	if(Tracer::IsEnabled())
	{
		Tracer::TraceBytes(Tracer::Net, Tracer::Low, QC_T("Datagram send:"), p.getData(), p.getLength());
	}

	int rc = ::sendto(m_rpSocketDescriptor->getFD(),
	                  (const char*) p.getData(),
	                  p.getLength(),
	                  flags,
	                  to,
	                  to ? sizeof(struct sockaddr_in) : 0);

	if(rc<0)
	{
		static const String err(QC_T("error calling sendto "));
		String errMsg = err + NetUtils::GetSocketErrorString();
		throw SocketException(errMsg);
	}

	//
	// When an unbound datagram socket is used to send data, the system will allocate
	// it an address and ephemeral port.  Let's see what weve been given!
	//
	if(!isBound())
	{
	}
}