Update 03.09.2019: The vpatches reground to sept_fixes are at:
curl 'http://bvt-trace.net/vpatches/active_disconnect_r3.kv.vpatch' > active_disconnect_r3.kv.vpatch curl 'http://bvt-trace.net/vpatches/active_disconnect_r3.kv.vpatch.bvt.sig' > active_disconnect_r3.kv.vpatch.bvt.sig
This patch modifies the behavior of logotron IRC bot to close the socket on error and initialize it anew when connecting to a new server. It also has some additional changes:
- I disabled Nagle's algorithm on a socket, as it has no business being enabled on low-bandwidth low-rate IRC links.
- I replaced 'Listen socket' with 'Receive socket' in the error messages: 'listen' is a term of art for sockets accepting connections, so it looked confusing to me - there is no listening in BSD sockets sense of this word anywhere in the bot.
- I also removed SO_KEEPALIVE socket option which got into hastily prepared initial version of vpatch. TCP keepalive messages are first sent after two hours of idleness on the socket - long after ~250 seconds of IRC idleness timeout expire.
def init_socket():
global sock
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Disable Nagle's algorithm for transmit operations
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
# Disable Nagle's algorithm for receive operation, Linux-only
try:
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_QUICKACK, 1)
except Exception as e:
logging.warning(e)
connected = False
def deinit_socket():
global connected
global sock
sock.close()
connected = False
@@ -171,7 +188,7 @@
sock.send(message.encode("utf-8"))
except (socket.timeout, socket.error) as e:
logging.warning("Socket could not send! Disconnecting.")
- connected = False
+ deinit_socket()
return False
except Exception as e:
logging.exception(e)
@@ -219,6 +236,10 @@
def irc():
global connected
global time_last_conn
+ global sock
+
+ # Initialize a socket
+ init_socket()
# Connect to one among the specified servers, in given priority :
while not connected:
@@ -246,20 +267,20 @@
try:
data = sock.recv(Buf_Size)
except socket.timeout as e:
- logging.debug("Listen timed out")
+ logging.debug("Receive timed out")
continue
except socket.error as e:
- logging.warning("Listen socket error, disconnecting.")
- connected = False
+ logging.warning("Receive socket error, disconnecting.")
+ deinit_socket()
continue
except Exception as e:
logging.exception(e)
- connected = False
+ deinit_socket()
continue
else:
if len(data) == 0:
- logging.warning("Listen socket closed, disconnecting.")
- connected = False
+ logging.warning("Receive socket closed, disconnecting.")
+ deinit_socket()
continue
try:
try:
It was tested only a little using strace's error injection:
$ strace -f -einject=sendto,recvfrom,connect:error=ECONNRESET:when=10+7 -p PID_OF_bot.py
Patches available here:
curl 'http://bvt-trace.net/vpatches/active_disconnect.kv.vpatch' > active_disconnect.kv.vpatch curl 'http://bvt-trace.net/vpatches/active_disconnect.kv.vpatch.bvt.sig' > active_disconnect.kv.vpatch.bvt.sig