Package tlslite :: Module messagesocket
[hide private]
[frames] | no frames]

Source Code for Module tlslite.messagesocket

  1  # vim: set fileencoding=utf8 
  2  # 
  3  # Copyright © 2015, Hubert Kario 
  4  # 
  5  # See the LICENSE file for legal information regarding use of this file. 
  6   
  7  """Wrapper of TLS RecordLayer providing message-level abstraction""" 
  8   
  9  from .recordlayer import RecordLayer 
 10  from .constants import ContentType 
 11  from .messages import RecordHeader3, Message 
 12  from .utils.codec import Parser 
 13   
14 -class MessageSocket(RecordLayer):
15 16 """TLS Record Layer socket that provides Message level abstraction 17 18 Because the record layer has a hard size limit on sent messages, they need 19 to be fragmented before sending. Similarly, a single record layer record 20 can include multiple handshake protocol messages (very common with 21 ServerHello, Certificate and ServerHelloDone), as such, the user of 22 RecordLayer needs to fragment those records into multiple messages. 23 Unfortunately, fragmentation of messages requires some degree of 24 knowledge about the messages passed and as such is outside scope of pure 25 record layer implementation. 26 27 This class tries to provide a useful abstraction for handling Handshake 28 protocol messages. 29 30 @type recordSize: int 31 @ivar recordSize: maximum size of records sent through socket. Messages 32 bigger than this size will be fragmented to smaller chunks. Setting it 33 to higher value than the default 2^14 will make the implementation 34 non RFC compliant and likely not interoperable with other peers. 35 36 @type defragmenter: L{Defragmenter} 37 @ivar defragmenter: defragmenter used for read records 38 39 @type unfragmentedDataTypes: tuple 40 @ivar unfragmentedDataTypes: data types which will be passed as-read, 41 TLS application_data by default 42 """ 43
44 - def __init__(self, sock, defragmenter):
45 """Apply TLS Record Layer abstraction to raw network socket. 46 47 @type sock: L{socket.socket} 48 @param sock: network socket to wrap 49 @type defragmenter: L{Defragmenter} 50 @param defragmenter: defragmenter to apply on the records read 51 """ 52 super(MessageSocket, self).__init__(sock) 53 54 self.defragmenter = defragmenter 55 self.unfragmentedDataTypes = tuple((ContentType.application_data, )) 56 self._lastRecordVersion = (0, 0) 57 58 self._sendBuffer = bytearray(0) 59 self._sendBufferType = None 60 61 self.recordSize = 2**14
62
63 - def recvMessage(self):
64 """ 65 Read next message in queue 66 67 will return a 0 or 1 if the read is blocking, a tuple of 68 L{RecordHeader3} and L{Parser} in case a message was received. 69 70 @rtype: generator 71 """ 72 while True: 73 while True: 74 ret = self.defragmenter.getMessage() 75 if ret is None: 76 break 77 header = RecordHeader3().create(self._lastRecordVersion, 78 ret[0], 79 0) 80 yield header, Parser(ret[1]) 81 82 for ret in self.recvRecord(): 83 if ret in (0, 1): 84 yield ret 85 else: 86 break 87 88 header, parser = ret 89 if header.type in self.unfragmentedDataTypes: 90 yield ret 91 # TODO probably needs a bit better handling... 92 if header.ssl2: 93 yield ret 94 95 self.defragmenter.addData(header.type, parser.bytes) 96 self._lastRecordVersion = header.version
97
98 - def recvMessageBlocking(self):
99 """Blocking variant of L{recvMessage}""" 100 for res in self.recvMessage(): 101 if res in (0, 1): 102 pass 103 else: 104 return res
105
106 - def flush(self):
107 """ 108 Empty the queue of messages to write 109 110 Will fragment the messages and write them in as little records as 111 possible. 112 113 @rtype: generator 114 """ 115 while len(self._sendBuffer) > 0: 116 recordPayload = self._sendBuffer[:self.recordSize] 117 self._sendBuffer = self._sendBuffer[self.recordSize:] 118 msg = Message(self._sendBufferType, recordPayload) 119 for res in self.sendRecord(msg): 120 yield res 121 122 assert len(self._sendBuffer) == 0 123 self._sendBufferType = None
124
125 - def flushBlocking(self):
126 """Blocking variant of L{flush}""" 127 for _ in self.flush(): 128 pass
129
130 - def queueMessage(self, msg):
131 """ 132 Queue message for sending 133 134 If the message is of same type as messages in queue, the message is 135 just added to queue. 136 137 If the message is of different type as messages in queue, the queue is 138 flushed and then the message is queued. 139 140 @rtype: generator 141 """ 142 if self._sendBufferType is None: 143 self._sendBufferType = msg.contentType 144 145 if msg.contentType == self._sendBufferType: 146 self._sendBuffer += msg.write() 147 return 148 149 for res in self.flush(): 150 yield res 151 152 assert self._sendBufferType is None 153 self._sendBufferType = msg.contentType 154 self._sendBuffer += msg.write()
155
156 - def queueMessageBlocking(self, msg):
157 """Blocking variant of L{queueMessage}""" 158 for _ in self.queueMessage(msg): 159 pass
160
161 - def sendMessage(self, msg):
162 """ 163 Fragment and send a message. 164 165 If a messages already of same type reside in queue, the message if 166 first added to it and then the queue is flushed. 167 168 If the message is of different type than the queue, the queue is 169 flushed, the message is added to queue and the queue is flushed again. 170 171 Use the sendRecord() message if you want to send a message outside 172 the queue, or a message of zero size. 173 174 @rtype: generator 175 """ 176 for res in self.queueMessage(msg): 177 yield res 178 179 for res in self.flush(): 180 yield res
181
182 - def sendMessageBlocking(self, msg):
183 """Blocking variant of L{sendMessage}""" 184 for _ in self.sendMessage(msg): 185 pass
186