4444import linecache
4545import logging
4646import os
47+ import operator
4748import pickle as py_pickle
4849import pstats
4950import signal
@@ -767,6 +768,54 @@ def find_class(self, module, func):
767768 _Unpickler = pickle .Unpickler
768769
769770
771+ class MessageError (Error ): pass
772+ class MessageMagicError (MessageError ): pass
773+ class MessageSizeError (MessageError ): pass
774+
775+
776+ class MessageHeader (tuple ):
777+ __slots__ = ()
778+ _struct = struct .Struct ('>hLLLLLL' )
779+ MAGIC = 0x4d49 # b'MI'
780+ SIZE = _struct .size
781+
782+ def __new__ (cls , magic , dst , src , auth , handle , reply_to , data_size ):
783+ args = (magic , dst , src , auth , handle , reply_to , data_size )
784+ return tuple .__new__ (cls , args )
785+
786+ magic = property (operator .itemgetter (0 ))
787+ dst = property (operator .itemgetter (1 ))
788+ src = property (operator .itemgetter (2 ))
789+ auth = property (operator .itemgetter (3 ))
790+ handle = property (operator .itemgetter (4 ))
791+ reply_to = property (operator .itemgetter (5 ))
792+ data_size = property (operator .itemgetter (6 ))
793+
794+ @classmethod
795+ def unpack (cls , buffer , max_message_size ):
796+ self = cls (* cls ._struct .unpack (buffer ))
797+ if self .magic != cls .MAGIC :
798+ raise MessageMagicError (
799+ 'Expected magic %x, got %x' % (cls .MAGIC , self .magic ),
800+ )
801+ if self .data_size > max_message_size :
802+ raise MessageSizeError (
803+ 'Maximum size exceeded (got %d, max %d)'
804+ % (self .data_size , max_message_size ),
805+ )
806+ return self
807+
808+ def pack (self ):
809+ return self ._struct .pack (* self )
810+
811+ def __repr__ (self ):
812+ return '%s.%s(magic=%d, dst=%d, src=%d, auth=%d, handle=%d, reply_to=%d, data_size=%d)' % (
813+ self .__class__ .__module__ , self .__class__ .__name__ ,
814+ self .magic , self .dst , self .src , self .auth , self .handle ,
815+ self .reply_to , self .data_size ,
816+ )
817+
818+
770819class Message (object ):
771820 """
772821 Messages are the fundamental unit of communication, comprising fields from
@@ -810,10 +859,6 @@ class Message(object):
810859 #: the :class:`mitogen.select.Select` interface. Defaults to :data:`None`.
811860 receiver = None
812861
813- HEADER_FMT = '>hLLLLLL'
814- HEADER_LEN = struct .calcsize (HEADER_FMT )
815- HEADER_MAGIC = 0x4d49 # 'MI'
816-
817862 def __init__ (self , ** kwargs ):
818863 """
819864 Construct a message from from the supplied `kwargs`. :attr:`src_id` and
@@ -825,12 +870,11 @@ def __init__(self, **kwargs):
825870 assert isinstance (self .data , BytesType ), 'Message data is not Bytes'
826871
827872 def pack (self ):
828- return (
829- struct .pack (self .HEADER_FMT , self .HEADER_MAGIC , self .dst_id ,
830- self .src_id , self .auth_id , self .handle ,
831- self .reply_to or 0 , len (self .data ))
832- + self .data
873+ hdr = MessageHeader (
874+ MessageHeader .MAGIC , self .dst_id , self .src_id , self .auth_id ,
875+ self .handle , self .reply_to or 0 , len (self .data ),
833876 )
877+ return hdr .pack () + self .data
834878
835879 def _unpickle_context (self , context_id , name ):
836880 return _unpickle_context (context_id , name , router = self .router )
@@ -2138,37 +2182,32 @@ def on_receive(self, broker, buf):
21382182 )
21392183
21402184 def _receive_one (self , broker ):
2141- if self ._input_buf_len < Message . HEADER_LEN :
2185+ if self ._input_buf_len < MessageHeader . SIZE :
21422186 return False
21432187
2144- msg = Message ()
2145- msg .router = self ._router
2146- (magic , msg .dst_id , msg .src_id , msg .auth_id ,
2147- msg .handle , msg .reply_to , msg_len ) = struct .unpack (
2148- Message .HEADER_FMT ,
2149- self ._input_buf [0 ][:Message .HEADER_LEN ],
2150- )
2151-
2152- if magic != Message .HEADER_MAGIC :
2188+ try :
2189+ hdr = MessageHeader .unpack (
2190+ self ._input_buf [0 ][:MessageHeader .SIZE ],
2191+ self ._router .max_message_size ,
2192+ )
2193+ except MessageMagicError :
21532194 LOG .error (self .corrupt_msg , self .stream .name , self ._input_buf [0 ][:2048 ])
21542195 self .stream .on_disconnect (broker )
21552196 return False
2156-
2157- if msg_len > self ._router .max_message_size :
2158- LOG .error ('%r: Maximum message size exceeded (got %d, max %d)' ,
2159- self , msg_len , self ._router .max_message_size )
2197+ except MessageSizeError as exc :
2198+ LOG .error ('%r: %s' , self , exc )
21602199 self .stream .on_disconnect (broker )
21612200 return False
21622201
2163- total_len = msg_len + Message . HEADER_LEN
2202+ total_len = MessageHeader . SIZE + hdr . data_size
21642203 if self ._input_buf_len < total_len :
21652204 _vv and IOLOG .debug (
21662205 '%r: Input too short (want %d, got %d)' ,
2167- self , msg_len , self ._input_buf_len - Message . HEADER_LEN
2206+ self , hdr . data_size , self ._input_buf_len - MessageHeader . SIZE
21682207 )
21692208 return False
21702209
2171- start = Message . HEADER_LEN
2210+ start = MessageHeader . SIZE
21722211 prev_start = start
21732212 remain = total_len
21742213 bits = []
@@ -2180,6 +2219,11 @@ def _receive_one(self, broker):
21802219 prev_start = start
21812220 start = 0
21822221
2222+ msg = Message (
2223+ dst_id = hdr .dst , src_id = hdr .src , auth_id = hdr .auth ,
2224+ handle = hdr .handle , reply_to = hdr .reply_to ,
2225+ )
2226+ msg .router = self ._router
21832227 msg .data = b ('' ).join (bits )
21842228 self ._input_buf .appendleft (buf [prev_start + len (bit ):])
21852229 self ._input_buf_len -= total_len
0 commit comments