TcpSocket.py 2.47 KB
"""
@author Georg Hopp

"""

import errno
import socket

import Transport
from Socket import Socket, CONTINUE

ACC_CONTINUE = CONTINUE + (
    errno.ENETDOWN,
    errno.EPROTO,
    errno.ENOPROTOOPT,
    errno.EHOSTDOWN,
    errno.ENONET,
    errno.EHOSTUNREACH,
    errno.EOPNOTSUPP
)

class TcpSocket(Socket):
    def __init__(self, host, port, con_ttl=30):
        super(TcpSocket, self).__init__(host, port, socket.SOCK_STREAM, con_ttl)
        self.remote = None

    def bind(self):
        super(TcpSocket, self).bind()
        self.socket.listen(128)
        self._listen = True

    def connect(self):
        with self._addrinfo():
            self.socket.settimeout(self._con_ttl)
            self.socket.connect(self._sa)
            self.socket.settimeout(None)
            self.socket.setblocking(0)

    def accept(self):
        try:
            con, remote = self.socket.accept()
        except socket.error as error:
            if error.errno not in ACC_CONTINUE:
                raise Transport.Error(Transport.Error.ERR_FAILED)
            return None

        try:
            host, port = con.getpeername()
        except Exception as error:
            # Here we should destinguish the addr_family...
            # Port is only available for INET and INET6 but not for UNIX.
            # Currently I don't support UNIX so i don't change it now.
            host = addr[0]
            port = addr[1]

        con.setblocking(0)
        newsock        = type(self)(host, port, self._con_ttl)
        newsock.socket = con
        newsock.remote = remote

        return newsock

    def recv(self, size):
        data = ''
        try:    
            data = self.socket.recv(size)
        except socket.error as error:
            if error.errno not in CONTINUE:
                raise Transport.Error(Transport.Error.ERR_FAILED)
            return None
                
        if not data:
            raise Transport.Error(Transport.Error.ERR_REMOTE_CLOSE)

        return (data, self.remote)

    def send(self, data, remote=None):
        send = 0
        try: 
            if self.socket:
                send = self.socket.send(data)
        except socket.error as error:
            if error.errno not in CONTINUE:
                if error.errno == errno.ECONNRESET:
                    raise Transport.Error(Transport.Error.ERR_REMOTE_CLOSE)
                else:
                    raise Transport.Error(Transport.Error.ERR_FAILED)

        return send

# vim: set ft=python et ts=4 sw=4 sts=4: