You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
130 lines
3.3 KiB
130 lines
3.3 KiB
"""
|
|
@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:
|