Skip to content

Commit

Permalink
Bugfix
Browse files Browse the repository at this point in the history
  • Loading branch information
luk3yx committed Aug 22, 2022
1 parent 1df8ee5 commit da58f17
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 17 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ Notes:
- This changelog may contain typographical errors, it is still a
work-in-progress.

## 1.8.4 - 2022-08-22

### Changed

- Fixed a socket-related oversight in v1.8.3.

## 1.8.3 - 2022-08-22

### Changed
Expand Down
17 changes: 9 additions & 8 deletions miniirc.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
import atexit, errno, threading, time, select, socket, ssl, sys, warnings

# The version string and tuple
ver = __version_info__ = (1,8,3)
version = 'miniirc IRC framework v1.8.3'
__version__ = '1.8.3'
ver = __version_info__ = (1,8,4)
version = 'miniirc IRC framework v1.8.4'
__version__ = '1.8.4'

# __all__ and _default_caps
__all__ = ['CmdHandler', 'Handler', 'IRC']
Expand Down Expand Up @@ -283,20 +283,21 @@ def quote(self, *msg, force=None, tags=None):
if tags:
msg = _dict_to_tags(tags) + msg

# Non-blocking sockets can't use sendall() reliably
msg += b'\r\n'
self._send_lock.acquire()
sent_bytes = 0
try: # Apparently try/finally is faster than "with".
while True:
while sent_bytes < len(msg):
try:
self.sock.sendall(msg)
break
except (BlockingIOError, ssl.SSLWantReadError):
sent_bytes += self.sock.send(msg[sent_bytes:])
except ssl.SSLWantReadError:
# Wait for the socket to become ready again
readable, _, _ = select.select(
(self.sock,), (), (self.sock,),
self.ping_timeout or self.ping_interval
)
except ssl.SSLWantWriteError:
except (BlockingIOError, ssl.SSLWantWriteError):
select.select((), (self.sock,), (self.sock,),
self.ping_timeout or self.ping_interval)
except (AttributeError, BrokenPipeError, socket.timeout):
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

setup(
name = 'miniirc',
version = '1.8.3',
version = '1.8.4',
py_modules = ['miniirc'],
author = 'luk3yx',
description = 'A lightweight IRC framework.',
Expand Down
39 changes: 31 additions & 8 deletions test_miniirc.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@ def wrapper(self, *args, **kwargs):
nonlocal err
try:
return func(self, *args, **kwargs)
except BlockingIOError:
raise
except Exception as e:
err = err or e
if MINIIRC_V2:
Expand Down Expand Up @@ -261,19 +263,31 @@ class fakesocket(socket.socket):
def __init__(self, __family, __type, *args):
assert __family in (socket.AF_INET, socket.AF_INET6)
assert __type == socket.SOCK_STREAM
self.__buf = b''

@catch_errors
def connect(self, __addr):
assert __addr[1] == 6667
self._recvq = queue.Queue()

@catch_errors
def send(self, data):
raise ValueError('socket.send() used in place of socket.sendall()')
def sendall(self, data):
raise ValueError('socket.sendall() used on non blocking socket')

@catch_errors
def sendall(self, data):
msg = data.decode('utf-8')
def send(self, data):
# Make sure that all data is sent
if len(data) > 5:
# Emulate the socket doing weird things
if random.randint(1, 3) == 1:
raise BlockingIOError

sent_bytes = random.randrange(len(data))
self.__buf += data[:sent_bytes]
return sent_bytes

msg = (self.__buf + data).decode('utf-8')
self.__buf = b''
assert msg.endswith('\r\n')
msg = msg[:-2]
assert msg in fixed_responses
Expand All @@ -283,7 +297,9 @@ def sendall(self, data):
self._recvq.put(line.encode('utf-8') +
random.choice((b'\r', b'\n', b'\r\n', b'\n\r')))
socket_event.set()
return len(data)

@catch_errors
def recv(self, chunk_size):
assert chunk_size == 8192
if err is not None or self._recvq is None:
Expand All @@ -310,13 +326,20 @@ def setblocking(self, blocking):

monkeypatch.setattr(socket, 'socket', fakesocket)

def fake_select(send, recv, err, timeout):
assert send == err
assert not recv
def fake_select(read, write, err, timeout):
assert read == err or write == err
assert len(err) == 1
assert timeout == 60

# When waiting for writing just return immediately
if write:
assert not read
return read, write, err

# Otherwise wait for the next socket event
socket_event.wait()
socket_event.clear()
return send, recv, err
return read, write, err

monkeypatch.setattr(select, 'select', fake_select)

Expand Down

0 comments on commit da58f17

Please sign in to comment.