Socket.py 3.33 KB
"""
@author Georg Hopp

"""

import socket
import errno
import sys

import Transport

from contextlib import contextmanager

CONTINUE = (errno.EAGAIN, errno.EWOULDBLOCK)
if 'win32' == sys.platform:
        CONTINUE = CONTINUE + (errno.WSAEWOULDBLOCK)

class Socket(object):
    def __init__(self, host, port, socket_type, con_ttl=30):
        self.socket       = None
        self._host        = host
        self._port        = port
        self._con_ttl     = con_ttl
        self._socket_type = socket_type
        self._listen      = False
        self._fin_state = 0

    def isListen(self):
        return self._listen

    def isFin(self):
        # TODO important, create something sane here.
        return 0 != self._fin_state

    def readReady(self):
        return 0 == self._fin_state & 1

    def writeReady(self):
        return 0 == self._fin_state & 2

    def getHandle(self):
        return self.socket

    def getHost(self):
        return self._host

    def getPort(self):
        return self._port

    def getAddr(self):
        return (self._host, self._port)

    @contextmanager
    def _addrinfo(self, flags=0):
        for res in socket.getaddrinfo(
                self._host, self._port,
                socket.AF_UNSPEC, self._socket_type,
                0, flags):
            af, socktype, proto, canonname, self._sa = res

            try:
                if not self.socket:
                    self.socket = socket.socket(af, socktype, proto)
            except socket.error as error:
                current_exception = error
                self.socket = None
                continue

            try:
                yield socktype
            except socket.error as error:
                current_exception = error
                self.socket.close()
                self.socket = None
                continue
            break

        if not self.socket:
            raise Transport.Error(Transport.Error.ERR_FAILED)

    def bind(self):
        with self._addrinfo(socket.AI_PASSIVE):
            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.socket.bind(self._sa)
            self.socket.setblocking(0)

    def open(self):
        with self._addrinfo(socket.AI_PASSIVE):
            self.socket.setblocking(0)

    def shutdownRead(self):
        try:
            if 0 == self._fin_state & 1:
                self.socket.shutdown(socket.SHUT_RD)
                self._fin_state |= 1
        except socket.error as error:
            self._fin_state |= 3
        return self._fin_state

    def shutdownWrite(self):
        try:
            if 0 == self._fin_state & 2:
                self.socket.shutdown(socket.SHUT_WR)
                self._fin_state |= 2
        except socket.error as error:
            self._fin_state |= 3
        return self._fin_state

    def shutdown(self):
        try:
            if 0 == self._fin_state:
                self.socket.shutdown(socket.SHUT_RDWR)
            else:
                self.shutdownRead()
                self.shutdownWrite()
        except socket.error as error:
            pass
        self._fin_state |= 3
        return self._fin_state

    def close(self):
        try:
            self.shutdown()
            self.socket.close()
        except socket.error as error:
            pass

        self.socket = None

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