void DatagramSocket::receive(DatagramPacket& packet) throw(S1004LibException) { sockaddr_in sender; int nBytes; socklen_t senderLength= sizeof(sender); char buffer[1025]; string data; do { nBytes= recvfrom(udpSocket, buffer, sizeof(buffer)-1, 0, (struct sockaddr *) &sender, &senderLength); if (nBytes < 0) { throw S1004LibException("Error receiving packet"); } buffer[nBytes]= '\0'; data+= buffer; } while (data.size() < packet.getLength() && nBytes == sizeof(buffer)-1); packet.setData(data).setAddress(inet_ntoa(sender.sin_addr)).setPort(ntohs(sender.sin_port)); }
int DatagramSocket::write(const DatagramPacket &pkt) { int numbytes; sockaddr_in addr; socklen_t addr_len=sizeof(addr); memset(&addr, 0, addr_len); addr.sin_family=AF_INET; addr.sin_port=htons(pkt.getPort()); addr.sin_addr=*((in_addr*)pkt.getAddress().getPtr()); if ((numbytes=sendto(*((socket_t*)m_sock), (char *)pkt.getBuffer().getData(), pkt.getLength(), 0, (sockaddr *)&addr, addr_len)) == -1) { Error_send("Unable to send packet from UDP socket\n"); } return numbytes; }
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()) { } }