Exemplo n.º 1
0
//
// 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;
}
Exemplo n.º 2
0
//==============================================================================
// 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);
	}
}