예제 #1
0
def sendData(sock, data):
    """
    Send some data over a socket.
    Some systems have problems with ``sendall()`` when the socket is in non-blocking mode.
    For instance, Mac OS X seems to be happy to throw EAGAIN errors too often.
    This function falls back to using a regular send loop if needed.
    """
    if sock.gettimeout() is None:
        # socket is in blocking mode, we can use sendall normally.
        try:
            sock.sendall(data)
            return
        except socket.timeout:
            raise TimeoutError("sending: timeout")
        except socket.error as x:
            raise ConnectionClosedError("sending: connection lost: " + str(x))
    else:
        # Socket is in non-blocking mode, use regular send loop.
        retrydelay = 0.0
        while data:
            try:
                sent = sock.send(data)
                data = data[sent:]
            except socket.timeout:
                raise TimeoutError("sending: timeout")
            except socket.error as x:
                err = getattr(x, "errno", x.args[0])
                if err not in ERRNO_RETRIES:
                    raise ConnectionClosedError("sending: connection lost: " +
                                                str(x))
                time.sleep(
                    0.00001 +
                    retrydelay)  # a slight delay to wait before retrying
                retrydelay = __nextRetrydelay(retrydelay)
예제 #2
0
def receiveData(sock, size):
    """Retrieve a given number of bytes from a socket.
    It is expected the socket is able to supply that number of bytes.
    If it isn't, an exception is raised (you will not get a zero length result
    or a result that is smaller than what you asked for). The partial data that
    has been received however is stored in the 'partialData' attribute of
    the exception object."""
    try:
        retrydelay = 0.0
        msglen = 0
        chunks = []
        if config.USE_MSG_WAITALL and not hasattr(sock, "getpeercert"):
            # waitall is very convenient and if a socket error occurs,
            # we can assume the receive has failed. No need for a loop,
            # unless it is a retryable error.
            # Some systems have an erratic MSG_WAITALL and sometimes still return
            # less bytes than asked. In that case, we drop down into the normal
            # receive loop to finish the task.
            # Also note that on SSL sockets, you cannot use MSG_WAITALL (or any other flag)
            while True:
                try:
                    data = sock.recv(size, socket.MSG_WAITALL)
                    if len(data) == size:
                        return data
                    # less data than asked, drop down into normal receive loop to finish
                    msglen = len(data)
                    chunks = [data]
                    break
                except socket.timeout:
                    raise TimeoutError("receiving: timeout")
                except socket.error as x:
                    err = getattr(x, "errno", x.args[0])
                    if err not in ERRNO_RETRIES:
                        raise ConnectionClosedError(
                            "receiving: connection lost: " + str(x))
                    time.sleep(
                        0.00001 +
                        retrydelay)  # a slight delay to wait before retrying
                    retrydelay = __nextRetrydelay(retrydelay)
        # old fashioned recv loop, we gather chunks until the message is complete
        while True:
            try:
                while msglen < size:
                    # 60k buffer limit avoids problems on certain OSes like VMS, Windows
                    chunk = sock.recv(min(60000, size - msglen))
                    if not chunk:
                        break
                    chunks.append(chunk)
                    msglen += len(chunk)
                data = b"".join(chunks)
                del chunks
                if len(data) != size:
                    err = ConnectionClosedError("receiving: not enough data")
                    err.partialData = data  # store the message that was received until now
                    raise err
                return data  # yay, complete
            except socket.timeout:
                raise TimeoutError("receiving: timeout")
            except socket.error:
                x = sys.exc_info()[1]
                err = getattr(x, "errno", x.args[0])
                if err not in ERRNO_RETRIES:
                    raise ConnectionClosedError(
                        "receiving: connection lost: " + str(x))
                time.sleep(
                    0.00001 +
                    retrydelay)  # a slight delay to wait before retrying
                retrydelay = __nextRetrydelay(retrydelay)
    except socket.timeout:
        raise TimeoutError("receiving: timeout")