Skip to content

Commit 3716222

Browse files
authored
Merge pull request #160 from Chrezm/4.3.4-post2-dev
4.3.4-post2
2 parents be9d14a + 03e69bd commit 3716222

File tree

8 files changed

+51
-30
lines changed

8 files changed

+51
-30
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,3 +796,7 @@
796796

797797
### 220821b (4.3.4-post1)
798798
* Fixed area list reloads crashing
799+
800+
### 220830a (4.3.4-post2)
801+
* Fixed clients sending legitimate split packets being abnormally disconnected
802+
* Fixed character list reloads crashing when someone is in server select

server/area_manager.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -340,8 +340,7 @@ def get_chars_unusable(self, allow_restricted: bool = False,
340340
if more_unavail_chars is None:
341341
more_unavail_chars = set()
342342

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

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

408+
if char_id < 0:
409+
return True
410+
409411
unused = char_id in self.get_chars_unusable(allow_restricted=allow_restricted,
410412
more_unavail_chars=more_unavail_chars)
411-
return char_id == -1 or not unused
413+
return not unused
412414

413415
def add_to_dicelog(self, client: ClientManager.Client, msg: str):
414416
"""

server/client_changearea.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ def notify_others(self, area: AreaManager.Area, old_dname: str,
461461
# Assuming this is not a spectator...
462462
# If autopassing, send OOC messages
463463

464-
if not ignore_autopass and not client.char_id < 0:
464+
if not ignore_autopass and client.has_character():
465465
self.notify_others_moving(client, old_area,
466466
'{} has left to the {}.'.format(old_dname, area.name),
467467
'You hear footsteps going out of the room.')

server/client_manager.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,12 @@ def showname_else_char_showname(self) -> str:
776776
return self.showname
777777
return self.char_showname
778778

779+
def has_character(self, char_id: int = None) -> bool:
780+
if char_id is None:
781+
char_id = self.char_id
782+
783+
return char_id is not None and char_id >= 0
784+
779785
def change_character(self, char_id: int, force: bool = False,
780786
target_area: AreaManager.Area = None,
781787
announce_zwatch: bool = True):
@@ -812,7 +818,8 @@ def change_character(self, char_id: int, force: bool = False,
812818
# Code after this comment assumes the character change will be successful
813819
self.ever_chose_character = True
814820

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

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

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

1603-
# If not spectator
1604-
if self.char_id is not None and self.char_id >= 0:
1611+
if self.has_character():
16051612
char_list[self.char_id] = 0 # Self is always available
16061613
self.send_command_dict('CharsCheck', {
16071614
'chars_status_ao2_list': char_list,
@@ -1610,7 +1617,7 @@ def refresh_char_list(self):
16101617
def refresh_visible_char_list(self):
16111618
char_list = [0] * len(self.server.char_list)
16121619
unusable_ids = {c.char_id for c in self.get_visible_clients(self.area)
1613-
if c.char_id >= 0}
1620+
if c.has_character()}
16141621
if not self.is_staff():
16151622
unusable_ids |= {self.server.char_list.index(name)
16161623
for name in self.area.restricted_chars}
@@ -1619,7 +1626,7 @@ def refresh_visible_char_list(self):
16191626
char_list[x] = -1
16201627

16211628
# Self is always available
1622-
if self.char_id is not None and self.char_id >= 0:
1629+
if self.has_character():
16231630
char_list[self.char_id] = 0
16241631
self.send_command_dict('CharsCheck', {
16251632
'chars_status_ao2_list': char_list,
@@ -1889,9 +1896,6 @@ def get_char_name(self, char_id: int = None) -> str:
18891896
return self.server.server_select_name
18901897
return self.server.char_list[char_id]
18911898

1892-
def has_character(self) -> bool:
1893-
return self.char_id not in [-1, None]
1894-
18951899
def get_showname_history(self) -> str:
18961900
info = '== Showname history of client {} =='.format(self.id)
18971901

server/commands.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2570,8 +2570,8 @@ def ooc_cmd_follow(client: ClientManager.Client, arg: str):
25702570
Constants.assert_command(client, arg, is_staff=True, parameters='=1')
25712571
except ClientError.UnauthorizedError:
25722572
Constants.assert_command(client, arg, parameters='=1')
2573-
if not client.char_id < 0:
2574-
raise ClientError('You must be authorized to follow without being in spectator mode.')
2573+
if client.has_character():
2574+
raise ClientError('You must be authorized to follow while having a character.')
25752575

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

93039303
client.unfollow_user()
93049304

server/network/ao_protocol.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def connection_lost(self, exc):
105105
self.server.remove_client(self.client)
106106
self.ping_timeout.cancel()
107107

108-
def _get_messages(self):
108+
def _get_messages(self) -> str:
109109
""" Parses out full messages from the buffer.
110110
111111
:return: yields messages
@@ -115,13 +115,20 @@ def _get_messages(self):
115115
self.buffer = spl[1]
116116
yield spl[0]
117117

118+
def _shortened_buffer(self) -> str:
119+
short_buffer = self.buffer
120+
if len(short_buffer) >= 512:
121+
short_buffer = short_buffer[:500] + '...' + short_buffer[-12:]
122+
123+
return f'{short_buffer} ({len(self.buffer)} bytes)'
124+
118125
def _process_message(self, msg):
119126
if len(msg) < 2:
120127
# This immediatelly kills any client that does not even try to follow the proper
121128
# client protocol
122129
msg = self.buffer if len(self.buffer) < 512 else self.buffer[:512] + '...'
123130
logger.log_server(f'Terminated {self.client.get_ipreal()} (packet too short): '
124-
f'sent {msg} ({len(self.buffer)} bytes)')
131+
f'sent {self._shortened_buffer()}.')
125132
self.client.disconnect()
126133
return False
127134

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

177184
if len(self.buffer) > 8192:
178-
msg = self.buffer if len(self.buffer) < 512 else self.buffer[:512] + '...'
179185
logger.log_server(f'Terminated {self.client.get_ipreal()} (packet too long): '
180-
f'sent {msg} ({len(self.buffer)} bytes)')
186+
f'sent {self._shortened_buffer()}.')
181187
self.client.disconnect()
182188
return
183189

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

190-
if not found_message:
196+
if found_message:
197+
return
198+
199+
# Check if valid packet split by evil router on client side
200+
buffer_command = self.buffer.split('#')[0]
201+
if buffer_command not in self._net_cmd_dispatcher:
191202
# This immediatelly kills any client that does not even try to follow the proper
192203
# client protocol
193-
msg = self.buffer if len(self.buffer) < 512 else self.buffer[:512] + '...'
194204
logger.log_server(f'Terminated {self.client.get_ipreal()} (packet syntax '
195-
f'unrecognized): sent {msg} ({len(self.buffer)} bytes)')
205+
f'unrecognized): sent {self._shortened_buffer()}.')
196206
self.client.disconnect()
197207

208+
198209
def _validate_net_cmd(self, args, *types, needs_auth=True):
199210
""" Makes sure the net command's arguments match expectations.
200211

server/tasker.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ async def as_afk_kick(self, client: ClientManager.Client, args: List):
223223
raise ServerError(info)
224224
if client.area.id == afk_sendto: # Don't try and kick back to same area
225225
return
226-
if client.char_id < 0: # Assumes spectators are exempted from AFK kicks
226+
if not client.has_character(): # Assumes spectators are exempted from AFK kicks
227227
return
228228
if client.is_staff(): # Assumes staff are exempted from AFK kicks
229229
return
@@ -728,6 +728,6 @@ async def as_phantom_peek(self, client: ClientManager.Client, args: List):
728728
return
729729
if client.is_staff():
730730
return
731-
if client.char_id is None or client.char_id < 0:
731+
if not client.has_character():
732732
return
733733
client.send_ooc('You feel as though you are being peeked on.')

server/tsuserver.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ def __init__(self, protocol: AOProtocol = None,
6969
self.release = 4
7070
self.major_version = 3
7171
self.minor_version = 4
72-
self.segment_version = 'post1'
73-
self.internal_version = '220821b'
72+
self.segment_version = 'post2'
73+
self.internal_version = '220830a'
7474
version_string = self.get_version_string()
7575
self.software = 'TsuserverDR {}'.format(version_string)
7676
self.version = 'TsuserverDR {} ({})'.format(version_string, self.internal_version)
@@ -408,7 +408,7 @@ def load_characters(self) -> List[str]:
408408
target_char_id = -1
409409
old_char_name = client.get_char_name()
410410

411-
if client.char_id < 0:
411+
if not client.has_character():
412412
# Do nothing for spectators
413413
pass
414414
elif old_char_name not in new_chars:

0 commit comments

Comments
 (0)