// // read() // ssize_t InputStream::read(unsigned char* b, size_t size, size_t off, size_t len) throw(IOException, IllegalBlockingModeException, IndexOutOfBoundsException) { // Comprueba los limites del array if (off + len > size) { throw IndexOutOfBoundsException("Index out of bounds"); } // Delega la operacion en el canal, si este existe if (_channel) { SocketChannel* ch = dynamic_cast<SocketChannel*>(_channel); return ch->read(b + off, len); } // Bytes leidos ssize_t n = -1; // Lee del stream si no se ha alcanzado EOF /* [email protected] 14/7/2004 if (! eof()) { */ // Timeout in microseconds (by default, infinite timeout) struct timeval tval_timeout; struct timeval* timeoutptr = NULL; if (_timeout) { tval_timeout.tv_sec = ((long) _timeout) / 1000L; tval_timeout.tv_usec = 1000L * (((long) _timeout) % 1000L); timeoutptr = &tval_timeout; } // Comprueba si el stream esta listo para lectura fd_set rset; FD_ZERO(&rset); FD_SET((int) _fd, &rset); int error = select((int) _fd + 1, &rset, NULL, NULL, timeoutptr); if (error <= 0 || !FD_ISSET((int) _fd, &rset)) { // Corrige errno para indicar vencimiento del timeout errno = (error == 0) ? ETIMEDOUT : errno; } else { // Lee del stream n = ::read((int) _fd, (void*) (b + off), len); } // Comprobacion de errores if (n == -1) { if (errno == ETIMEDOUT) throw SocketTimeoutException("read() timeout"); else if (errno == EINTR) n = read(b, size, off, len); else throw IOException("read() error", errno); } /* [email protected]: 14/7/2004 } */ return n; }
//============================================================================== // 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); } }