int DatagramSocket::read(DatagramPacket &pkt) { int numbytes; sockaddr_in addr; socklen_t addr_len=sizeof(addr); if ((numbytes=recvfrom(*((socket_t*)m_sock), (char *)pkt.getBuffer().getData(), pkt.getBuffer().getLength(), 0, (sockaddr *)&addr, &addr_len)) == -1) { Error_send("Unable to receive packet from UDP socket\n"); } pkt.setPort(addr.sin_port); pkt.setAddress(InetAddress(inet_ntoa(addr.sin_addr))); pkt.setLength(numbytes); return numbytes; }
//============================================================================== // 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); } }