Skip to content

Commit

Permalink
Merge pull request #160 from Chrezm/4.3.4-post2-dev
Browse files Browse the repository at this point in the history
4.3.4-post2
  • Loading branch information
Chrezm authored Aug 31, 2022
2 parents be9d14a + 03e69bd commit 3716222
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 30 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -796,3 +796,7 @@

### 220821b (4.3.4-post1)
* Fixed area list reloads crashing

### 220830a (4.3.4-post2)
* Fixed clients sending legitimate split packets being abnormally disconnected
* Fixed character list reloads crashing when someone is in server select
8 changes: 5 additions & 3 deletions server/area_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,7 @@ def get_chars_unusable(self, allow_restricted: bool = False,
if more_unavail_chars is None:
more_unavail_chars = set()

unavailable = {x.char_id for x in self.clients if x.char_id is not None
and x.char_id >= 0}
unavailable = {x.char_id for x in self.clients if x.has_character()}
unavailable |= more_unavail_chars
restricted = {self.server.char_list.index(name) for name in self.restricted_chars}

Expand Down Expand Up @@ -406,9 +405,12 @@ def is_char_available(self, char_id: int, allow_restricted: bool = False,
is not found to be among the area's unusable characters.
"""

if char_id < 0:
return True

unused = char_id in self.get_chars_unusable(allow_restricted=allow_restricted,
more_unavail_chars=more_unavail_chars)
return char_id == -1 or not unused
return not unused

def add_to_dicelog(self, client: ClientManager.Client, msg: str):
"""
Expand Down
2 changes: 1 addition & 1 deletion server/client_changearea.py
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ def notify_others(self, area: AreaManager.Area, old_dname: str,
# Assuming this is not a spectator...
# If autopassing, send OOC messages

if not ignore_autopass and not client.char_id < 0:
if not ignore_autopass and client.has_character():
self.notify_others_moving(client, old_area,
'{} has left to the {}.'.format(old_dname, area.name),
'You hear footsteps going out of the room.')
Expand Down
24 changes: 14 additions & 10 deletions server/client_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,12 @@ def showname_else_char_showname(self) -> str:
return self.showname
return self.char_showname

def has_character(self, char_id: int = None) -> bool:
if char_id is None:
char_id = self.char_id

return char_id is not None and char_id >= 0

def change_character(self, char_id: int, force: bool = False,
target_area: AreaManager.Area = None,
announce_zwatch: bool = True):
Expand Down Expand Up @@ -812,7 +818,8 @@ def change_character(self, char_id: int, force: bool = False,
# Code after this comment assumes the character change will be successful
self.ever_chose_character = True

if old_char_id < 0 and char_id >= 0: # No longer spectator?
if not self.has_character() and self.has_character(char_id=char_id):
# No longer spectator?
# Now bound by AFK rules
self.server.tasker.create_task(self, ['as_afk_kick', self.area.afk_delay,
self.area.afk_sendto])
Expand All @@ -826,7 +833,8 @@ def change_character(self, char_id: int, force: bool = False,
f'and you are not logged in.')
self.unfollow_user()

elif old_char_id >= 0 and char_id < 0: # Now a spectator?
elif self.has_character() and not self.has_character(char_id=char_id):
# Now a spectator?
# No longer bound to AFK rules
try:
self.server.tasker.remove_task(self, ['as_afk_kick'])
Expand Down Expand Up @@ -958,7 +966,7 @@ def notify_change_area(self, area: AreaManager.Area, old_char: str,
just_me=just_me)

def check_lurk(self):
if self.area.lurk_length > 0 and not self.is_staff() and self.char_id >= 0:
if self.area.lurk_length > 0 and not self.is_staff() and self.has_character():
self.server.tasker.create_task(self, ['as_lurk', self.area.lurk_length])
else: # Otherwise, end any existing lurk, if there is one
try:
Expand Down Expand Up @@ -1600,8 +1608,7 @@ def refresh_char_list(self):
for x in unusable_ids:
char_list[x] = -1

# If not spectator
if self.char_id is not None and self.char_id >= 0:
if self.has_character():
char_list[self.char_id] = 0 # Self is always available
self.send_command_dict('CharsCheck', {
'chars_status_ao2_list': char_list,
Expand All @@ -1610,7 +1617,7 @@ def refresh_char_list(self):
def refresh_visible_char_list(self):
char_list = [0] * len(self.server.char_list)
unusable_ids = {c.char_id for c in self.get_visible_clients(self.area)
if c.char_id >= 0}
if c.has_character()}
if not self.is_staff():
unusable_ids |= {self.server.char_list.index(name)
for name in self.area.restricted_chars}
Expand All @@ -1619,7 +1626,7 @@ def refresh_visible_char_list(self):
char_list[x] = -1

# Self is always available
if self.char_id is not None and self.char_id >= 0:
if self.has_character():
char_list[self.char_id] = 0
self.send_command_dict('CharsCheck', {
'chars_status_ao2_list': char_list,
Expand Down Expand Up @@ -1889,9 +1896,6 @@ def get_char_name(self, char_id: int = None) -> str:
return self.server.server_select_name
return self.server.char_list[char_id]

def has_character(self) -> bool:
return self.char_id not in [-1, None]

def get_showname_history(self) -> str:
info = '== Showname history of client {} =='.format(self.id)

Expand Down
8 changes: 4 additions & 4 deletions server/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -2570,8 +2570,8 @@ def ooc_cmd_follow(client: ClientManager.Client, arg: str):
Constants.assert_command(client, arg, is_staff=True, parameters='=1')
except ClientError.UnauthorizedError:
Constants.assert_command(client, arg, parameters='=1')
if not client.char_id < 0:
raise ClientError('You must be authorized to follow without being in spectator mode.')
if client.has_character():
raise ClientError('You must be authorized to follow while having a character.')

if client.party:
raise PartyError('You cannot follow someone while in a party.')
Expand Down Expand Up @@ -9297,8 +9297,8 @@ def ooc_cmd_unfollow(client: ClientManager.Client, arg: str):
Constants.assert_command(client, arg, is_staff=True, parameters='=0')
except ClientError.UnauthorizedError:
Constants.assert_command(client, arg, parameters='=0')
if not client.char_id < 0:
raise ClientError('You must be authorized to unfollow without being in spectator mode.')
if client.has_character():
raise ClientError('You must be authorized to unfollow while having a character.')

client.unfollow_user()

Expand Down
25 changes: 18 additions & 7 deletions server/network/ao_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def connection_lost(self, exc):
self.server.remove_client(self.client)
self.ping_timeout.cancel()

def _get_messages(self):
def _get_messages(self) -> str:
""" Parses out full messages from the buffer.
:return: yields messages
Expand All @@ -115,13 +115,20 @@ def _get_messages(self):
self.buffer = spl[1]
yield spl[0]

def _shortened_buffer(self) -> str:
short_buffer = self.buffer
if len(short_buffer) >= 512:
short_buffer = short_buffer[:500] + '...' + short_buffer[-12:]

return f'{short_buffer} ({len(self.buffer)} bytes)'

def _process_message(self, msg):
if len(msg) < 2:
# This immediatelly kills any client that does not even try to follow the proper
# client protocol
msg = self.buffer if len(self.buffer) < 512 else self.buffer[:512] + '...'
logger.log_server(f'Terminated {self.client.get_ipreal()} (packet too short): '
f'sent {msg} ({len(self.buffer)} bytes)')
f'sent {self._shortened_buffer()}.')
self.client.disconnect()
return False

Expand Down Expand Up @@ -175,9 +182,8 @@ def data_received(self, data):
self.buffer = self.buffer.translate({ord(c): None for c in '\0'})

if len(self.buffer) > 8192:
msg = self.buffer if len(self.buffer) < 512 else self.buffer[:512] + '...'
logger.log_server(f'Terminated {self.client.get_ipreal()} (packet too long): '
f'sent {msg} ({len(self.buffer)} bytes)')
f'sent {self._shortened_buffer()}.')
self.client.disconnect()
return

Expand All @@ -187,14 +193,19 @@ def data_received(self, data):
if not self._process_message(msg):
return

if not found_message:
if found_message:
return

# Check if valid packet split by evil router on client side
buffer_command = self.buffer.split('#')[0]
if buffer_command not in self._net_cmd_dispatcher:
# This immediatelly kills any client that does not even try to follow the proper
# client protocol
msg = self.buffer if len(self.buffer) < 512 else self.buffer[:512] + '...'
logger.log_server(f'Terminated {self.client.get_ipreal()} (packet syntax '
f'unrecognized): sent {msg} ({len(self.buffer)} bytes)')
f'unrecognized): sent {self._shortened_buffer()}.')
self.client.disconnect()


def _validate_net_cmd(self, args, *types, needs_auth=True):
""" Makes sure the net command's arguments match expectations.
Expand Down
4 changes: 2 additions & 2 deletions server/tasker.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ async def as_afk_kick(self, client: ClientManager.Client, args: List):
raise ServerError(info)
if client.area.id == afk_sendto: # Don't try and kick back to same area
return
if client.char_id < 0: # Assumes spectators are exempted from AFK kicks
if not client.has_character(): # Assumes spectators are exempted from AFK kicks
return
if client.is_staff(): # Assumes staff are exempted from AFK kicks
return
Expand Down Expand Up @@ -728,6 +728,6 @@ async def as_phantom_peek(self, client: ClientManager.Client, args: List):
return
if client.is_staff():
return
if client.char_id is None or client.char_id < 0:
if not client.has_character():
return
client.send_ooc('You feel as though you are being peeked on.')
6 changes: 3 additions & 3 deletions server/tsuserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ def __init__(self, protocol: AOProtocol = None,
self.release = 4
self.major_version = 3
self.minor_version = 4
self.segment_version = 'post1'
self.internal_version = '220821b'
self.segment_version = 'post2'
self.internal_version = '220830a'
version_string = self.get_version_string()
self.software = 'TsuserverDR {}'.format(version_string)
self.version = 'TsuserverDR {} ({})'.format(version_string, self.internal_version)
Expand Down Expand Up @@ -408,7 +408,7 @@ def load_characters(self) -> List[str]:
target_char_id = -1
old_char_name = client.get_char_name()

if client.char_id < 0:
if not client.has_character():
# Do nothing for spectators
pass
elif old_char_name not in new_chars:
Expand Down

0 comments on commit 3716222

Please sign in to comment.