]> code.delx.au - pymsnt/blob - src/tlib/msnp2p.py
Reimport and tags (0.10.1)
[pymsnt] / src / tlib / msnp2p.py
1 # Copyright 2005 James Bunton <james@delx.cjb.net>
2 # Licensed for distribution under the GPL version 2, check COPYING for details
3
4 import struct
5 import random
6 import sha
7
8 import utils
9
10 MSNP2P_DEBUG = False
11
12 class MSNOBJ:
13 def __init__(self):
14 self.creator = ""
15 self.imageData = ""
16 self.size = ""
17 self.type = 0
18 self.location = ""
19 self.friendly = ""
20 self.sha1d = ""
21 self.text = ""
22
23 def setData(self, creator, imageData):
24 self.creator = creator
25 self.imageData = imageData
26 self.size = len(imageData)
27 self.type = 3
28 self.location = "TMP" + str(random.randint(1000,9999))
29 self.friendly = "AAA="
30 self.sha1d = utils.b64enc(sha.sha(imageData).digest())
31 self.makeText()
32
33 def setNull(self):
34 self.creator = ""
35 self.imageData = ""
36 self.size = 0
37 self.type = 0
38 self.location = ""
39 self.friendly = ""
40 self.sha1d = ""
41 self.text = ""
42
43 def makeText(self):
44 h = []
45 h.append("Creator")
46 h.append(self.creator)
47 h.append("Size")
48 h.append(str(self.size))
49 h.append("Type")
50 h.append(str(self.type))
51 h.append("Location")
52 h.append(self.location)
53 h.append("Friendly")
54 h.append(self.friendly)
55 h.append("SHA1D")
56 h.append(self.sha1d)
57 sha1c = utils.b64enc(sha.sha("".join(h)).digest())
58 self.text = '<msnobj Creator="%s" Size="%s" Type="%s" Location="%s" Friendly="%s" SHA1D="%s" SHA1C="%s"/>' % (self.creator, str(self.size), str(self.type), self.location, self.friendly, self.sha1d, sha1c)
59
60 def parse(self, s):
61 e = utils.parseText(s)
62 self.creator = e.getAttribute("Creator")
63 self.size = int(e.getAttribute("Size"))
64 self.type = int(e.getAttribute("Type"))
65 self.location = e.getAttribute("Location")
66 self.friendly = e.getAttribute("Friendly")
67 self.sha1d = e.getAttribute("SHA1D")
68 self.text = s
69
70
71
72 class BinaryFields:
73 ACK = 0x02
74 WAIT = 0x04
75 ERR = 0x08
76 DATA = 0x20
77 BYEGOT = 0x40
78 BYESENT = 0x80
79 DATAFT = 0x1000030
80
81 def __init__(self, fields=None):
82 if(not fields):
83 fields = [0] * 10
84 self.fields = fields
85
86 def __getitem__(self, key):
87 return self.fields[key]
88
89 def __setitem__(self, key, value):
90 self.fields[key] = value
91
92 def unpackFields(self, packet):
93 self.fields = struct.unpack("<LLQQLLLLQ", packet[0:48])
94 self.fields += struct.unpack(">L", packet[len(packet)-4:])
95 if MSNP2P_DEBUG:
96 print "Unpacked fields:",
97 for i in self.fields:
98 print hex(i),
99 print
100
101 def packHeaders(self):
102 f = tuple(self.fields)
103 if MSNP2P_DEBUG:
104 print "Packed fields:",
105 for i in self.fields:
106 print hex(i),
107 print
108 return struct.pack("<LLQQLLLLQ", f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8])
109
110 def packFooter(self):
111 return struct.pack(">L", self.fields[9])
112
113
114 class MSNSLPMessage:
115 def __init__(self):
116 self.method = ""
117 self.status = ""
118 self.to = ""
119 self.fro = ""
120 self.cseq = 0
121 self.sessionGuid = ""
122 self.sessionID = None
123 self.euf_guid = ""
124 self.data = "\r\n" + chr(0)
125
126 def create(self, method=None, status=None, to=None, fro=None, cseq=0, sessionGuid=None, data=None):
127 self.method = method
128 self.status = status
129 self.to = to
130 self.fro = fro
131 self.cseq = cseq
132 self.sessionGuid = sessionGuid
133 if(data): self.data = data
134
135 def setData(self, sessionID=None, appID=None, guid=None, context=None):
136 s = []
137 if(guid): s.append("EUF-GUID: %s\r\n" % guid)
138 if(sessionID): s.append("SessionID: %s\r\n" % sessionID)
139 if(appID): s.append("AppID: %s\r\n" % appID)
140 if(context): s.append("Context: %s\r\n\r\n" % context)
141 s.append(chr(0))
142
143 self.data = "".join(s)
144
145 def parse(self, s):
146 s = s[48:len(s)-4:]
147 if s.find("MSNSLP/1.0") < 0: return
148
149 lines = s.split("\r\n")
150
151 # Get the MSNSLP method or status
152 msnslp = lines[0].split(" ")
153 if MSNP2P_DEBUG: print "Parsing MSNSLPMessage", s, len(s)
154 if(msnslp[0] in ("INVITE", "BYE")):
155 self.method = msnslp[0].strip()
156 else:
157 self.status = msnslp[1].strip()
158
159 lines.remove(lines[0])
160
161 for line in lines:
162 line = line.split(":")
163 if(len(line) > 1):
164 if(len(line) > 2 and line[0] == "To"):
165 self.to = line[2][:line[2].find('>')]
166 elif(len(line) > 2 and line[0] == "From"):
167 self.fro = line[2][:line[2].find('>')]
168 elif(line[0] == "Call-ID"):
169 self.sessionGuid = line[1].strip()
170 elif(line[0] == "CSeq"):
171 self.cseq = int(line[1].strip())
172 elif(line[0] == "SessionID"):
173 self.sessionID = int(line[1].strip())
174 elif(line[0] == "EUF-GUID"):
175 self.euf_guid = line[1].strip()
176
177 def __str__(self):
178 s = []
179 if(self.method):
180 s.append("%s MSNMSGR:%s MSNSLP/1.0\r\n" % (self.method, self.to))
181 else:
182 s.append("MSNSLP/1.0 %s\r\n" % self.status)
183 s.append("To: <msnmsgr:%s>\r\n" % self.to)
184 s.append("From: <msnmsgr:%s>\r\n" % self.fro)
185 s.append("Via: MSNSLP/1.0/TLP ;branch=%s\r\n" % utils.random_guid())
186 s.append("CSeq: %s \r\n" % str(self.cseq))
187 s.append("Call-ID: %s\r\n" % self.sessionGuid)
188 s.append("Max-Forwards: 0\r\n")
189 if(self.method == "BYE"):
190 s.append("Content-Type: application/x-msnmsgr-sessionclosebody\r\n")
191 else:
192 s.append("Content-Type: application/x-msnmsgr-sessionreqbody\r\n")
193 s.append("Content-Length: %s\r\n\r\n" % len(self.data))
194 s.append(self.data)
195 return "".join(s)
196
197
198 class BaseID:
199 def __init__(self, baseID=None, sender=False):
200 if(baseID):
201 self.baseID = baseID
202 else:
203 self.baseID = random.randint(4, 2**30)
204 self.sender = sender
205 if(self.sender):
206 self.pos = -1
207 else:
208 self.pos = 0
209
210 def get(self):
211 if self.pos == -1:
212 return self.baseID
213 else:
214 return self.baseID + self.pos - 3
215
216 def next(self):
217 self.pos += 1
218 if self.pos == 3 and self.sender:
219 self.pos += 1
220 return self.get()
221
222 class FileData:
223 def __init__(self, size):
224 self.data = chr(0) * size
225 self.totalSize = size
226 self.gotSize = 0
227
228 def put(self, offset, data):
229 self.data = self.data[0:offset] + data + self.data[offset+len(data):]
230 self.gotSize += len(data)
231
232 def finished(self):
233 return self.gotSize >= self.totalSize
234
235
236 class MSNP2P_Avatar:
237 TRANSFER_COUNT = 0
238 ERROR_COUNT = 0
239
240 EUF_GUID = "{A4268EEC-FEC5-49E5-95C3-F126696BDBF6}"
241 ERROR = -1
242
243 def __init__(self):
244 raise "NotImplemented"
245
246 def getImage(self):
247 return False
248
249 def isFinished(self):
250 if self.state >= self.FINISHED:
251 MSNP2P_Avatar.TRANSFER_COUNT += 1
252 return True
253 elif self.state < 0:
254 MSNP2P_Avatar.ERROR_COUNT += 1
255 return True
256 else:
257 return False
258
259 def setError(self, text):
260 if MSNP2P_DEBUG:
261 print "ERROR in avatar transfer: ", self, text, "in state:", self.state
262 self.state = self.ERROR
263
264 def warn(self, text):
265 if MSNP2P_DEBUG:
266 print "Warning in avatar transfer: ", self, text, "in state:", self.state
267
268
269 class MSNP2P_Avatar_Send(MSNP2P_Avatar):
270 # Avatar_Send states
271 WAIT_REQUEST = 0
272 SEND_REQACK = 1
273 SEND_200OK = 2
274 WAIT_200OK_ACK = 3
275 SEND_DATAPREP = 4
276 WAIT_DATAPREP_ACK = 5
277 SEND_DATA = 6
278 WAIT_BYE = 7
279 SEND_BYE_ACK = 8
280 FINISHED = 9
281
282 def __init__(self, to, fro, msnobj):
283 self.to = to
284 self.fro = fro
285 self.msnobj = msnobj
286 self.fileOffset = 0 # The amount already sent
287 self.sessionID = 0
288 self.baseID = BaseID(sender=True)
289 self.state = self.WAIT_REQUEST
290 self.lastFields = BinaryFields()
291 self.lastSentFields = BinaryFields()
292
293 def processPacket(self, packet):
294 if MSNP2P_DEBUG:
295 print "processPacket", self.to, self.fro, self.state
296 if(self.state == self.WAIT_REQUEST):
297 message = MSNSLPMessage()
298 message.parse(packet)
299 if(message.method != "INVITE"):
300 self.setError("method" + message.method)
301 return
302 if(message.cseq != 0):
303 self.setError("cseq" + str(message.cseq))
304 return
305 if(message.euf_guid != self.EUF_GUID):
306 self.setError("guid" + message.euf_guid)
307 return
308
309 binaryFields = BinaryFields()
310 binaryFields.unpackFields(packet)
311
312 self.sguid = message.sessionGuid
313 self.sessionID = message.sessionID
314
315 self.lastFields = binaryFields
316 self.state = self.SEND_REQACK
317 return
318
319 if(self.state == self.WAIT_200OK_ACK):
320 binaryFields = BinaryFields()
321 binaryFields.unpackFields(packet)
322
323 if(binaryFields[6] != self.lastSentFields[1]):
324 self.warn("field6," + str(binaryFields[6]) + "," + str(self.lastSentFields[1]))
325 return
326 if(binaryFields[3] != self.lastSentFields[3]):
327 self.setError("field3," + str(binaryFields[3]) + "," + str(self.lastSentFields[3]))
328 return
329 if(binaryFields[8] != self.lastSentFields[3]):
330 self.setError("field8," + str(binaryFields[8]) + "," + str(self.lastSentFields[3]))
331 return
332 if(binaryFields[5] != BinaryFields.ACK):
333 self.setError("field5," + str(binaryFields[5]))
334 return
335
336 self.lastFields = binaryFields
337 self.state = self.SEND_DATAPREP
338 return
339
340 if(self.state == self.WAIT_DATAPREP_ACK):
341 binaryFields = BinaryFields()
342 binaryFields.unpackFields(packet)
343
344 if(binaryFields[0] != self.sessionID):
345 self.warn("field0," + str(binaryFields[0]) + "," + str(self.sessionID))
346 return
347 if(binaryFields[3] != self.lastSentFields[3]):
348 self.setError("field3," + str(binaryFields[3]) + "," + str(self.lastSentFields[3]))
349 return
350 if(binaryFields[8] != self.lastSentFields[3]):
351 self.setError("field8," + str(binaryFields[8]) + "," + str(self.lastSentFields[3]))
352 return
353 if(binaryFields[5] != BinaryFields.ACK):
354 self.setError("field5," + str(binaryFields[5]))
355 return
356 if(binaryFields[6] != self.lastSentFields[1]):
357 self.setError("field6," + str(binaryFields[6]) + "," + str(self.lastSentFields[1]))
358 return
359 if(binaryFields[7] != self.lastSentFields[6]):
360 self.setError("field7," + str(binaryFields[7]) + "," + str(self.lastSentFields[6]))
361 return
362
363 self.lastFields = binaryFields
364 self.baseID.next()
365 self.state = self.SEND_DATA
366 return
367
368 if(self.state == self.WAIT_BYE):
369 binaryFields = BinaryFields()
370 binaryFields.unpackFields(packet)
371
372 # BYE message
373 message = MSNSLPMessage()
374 message.parse(packet)
375 if(message.sessionGuid != self.sguid):
376 self.warn("sessionGuid" + message.sessionGuid)
377 return
378 if(message.method != "BYE"):
379 self.setError("method " + message.method)
380 return
381 if(message.cseq != 0):
382 self.setError("cseq" + str(message.cseq))
383 return
384
385 self.lastFields = binaryFields
386 self.state = self.SEND_BYE_ACK # I don't really care about receiving the data ack
387 return
388
389
390 def getNextPacket(self):
391 if MSNP2P_DEBUG:
392 print "getNextPacket (Avatar_Send)", self.to, self.fro, self.state
393 if(self.state == self.SEND_REQACK):
394 binaryFields = BinaryFields()
395 binaryFields[1] = self.baseID.get()
396 binaryFields[3] = self.lastFields[3]
397 binaryFields[5] = BinaryFields.ACK
398 binaryFields[6] = self.lastFields[1]
399 binaryFields[7] = self.lastFields[6]
400 binaryFields[8] = self.lastFields[3]
401
402 packet = binaryFields.packHeaders() + binaryFields.packFooter()
403
404 self.state = self.SEND_200OK
405 self.lastSentFields = binaryFields
406 return packet
407
408 if(self.state == self.SEND_200OK):
409 msg = MSNSLPMessage()
410 msg.create(status="200 OK", to=self.to, fro=self.fro, cseq=1, sessionGuid=self.sguid)
411 msg.setData(sessionID=self.sessionID)
412 msgStr = str(msg)
413
414 binaryFields = BinaryFields()
415 binaryFields[1] = self.baseID.next()
416 binaryFields[3] = len(msgStr)
417 binaryFields[4] = len(msgStr)
418 binaryFields[6] = random.randint(0, 2**30)
419
420 packet = binaryFields.packHeaders() + msgStr + binaryFields.packFooter()
421
422 self.state = self.WAIT_200OK_ACK
423 self.lastSentFields = binaryFields
424 return packet
425
426 if(self.state == self.SEND_DATAPREP):
427 binaryFields = BinaryFields()
428 binaryFields[0] = self.sessionID
429 binaryFields[1] = self.baseID.next()
430 binaryFields[3] = 4
431 binaryFields[4] = 4
432 binaryFields[6] = random.randint(0, 2**30)
433 binaryFields[9] = 1
434
435 packet = binaryFields.packHeaders() + chr(0) * 4 + binaryFields.packFooter()
436
437 self.state = self.WAIT_DATAPREP_ACK
438 self.lastSentFields = binaryFields
439 return packet
440
441 if(self.state == self.SEND_DATA):
442 binaryFields = BinaryFields()
443 binaryFields[0] = self.sessionID
444 binaryFields[1] = self.baseID.get()
445 binaryFields[2] = self.fileOffset
446 binaryFields[3] = len(self.msnobj.imageData)
447 binaryFields[5] = BinaryFields.DATA
448 binaryFields[6] = random.randint(0, 2**30)
449 binaryFields[9] = 1
450
451 # Work out what part of the file we're sending
452 length = len(self.msnobj.imageData) - self.fileOffset
453 if(length > 1202):
454 # Max amount per message is 1202
455 length = 1202
456 else:
457 # Last packet!
458 self.state = self.WAIT_BYE
459 self.lastSentFields = binaryFields
460 binaryFields[4] = length
461 chunk = self.msnobj.imageData[self.fileOffset : self.fileOffset + length]
462 self.fileOffset += length
463
464 packet = binaryFields.packHeaders() + chunk + binaryFields.packFooter()
465 return packet
466
467 if(self.state == self.SEND_BYE_ACK):
468 binaryFields = BinaryFields()
469 binaryFields[1] = self.baseID.next()
470 binaryFields[3] = self.lastFields[3]
471 binaryFields[5] = BinaryFields.BYEGOT
472 binaryFields[6] = self.lastFields[1]
473 binaryFields[7] = self.lastFields[6]
474 binaryFields[8] = self.lastFields[3]
475
476 packet = binaryFields.packHeaders() + binaryFields.packFooter()
477
478 self.state = self.FINISHED
479 self.lastSentFields = binaryFields
480 return packet
481
482
483
484
485 class MSNP2P_Avatar_Receive(MSNP2P_Avatar):
486 # Avatar_Receive states
487 SEND_REQUEST = 0 # Send the request
488 WAIT_REQACK_200OK = 1 # Wait for REQACK and 200OK message
489 # Skip one value so we know both of the above have been done
490 SEND_200OK_ACK = 3 # Received both of the above
491 WAIT_DATAPREP = 4 # Wait for DATAPREP
492 SEND_DATAPREP_ACK = 5 # Send ACK to above
493 WAIT_DATA = 6 # Wait for all data messages and send DATA_ACK
494 SEND_DATA_ACK = 7 # Then send BYE
495 SEND_BYE = 8
496 FINISHED = 9
497
498 def __init__(self, to, fro, msnobj):
499 self.to = to
500 self.fro = fro
501 self.msnobj = msnobj
502 self.sessionID = random.randint(0, 2**30)
503 self.sguid = utils.random_guid()
504 self.baseID = BaseID()
505 self.state = self.SEND_REQUEST
506 self.lastFields = BinaryFields()
507 self.lastSentFields = BinaryFields()
508 self.fileData = None
509
510 def getImage(self):
511 if(self.state >= self.SEND_BYE):
512 return self.fileData.data
513
514 def processPacket(self, packet):
515 if MSNP2P_DEBUG:
516 print "processPacket", self.to, self.fro, self.state
517 if(self.state == self.WAIT_REQACK_200OK or self.state == self.WAIT_REQACK_200OK + 1):
518 binaryFields = BinaryFields()
519 binaryFields.unpackFields(packet)
520
521 if(binaryFields[5] == BinaryFields.ACK):
522 # REQUESTACK!
523 if(binaryFields[6] != self.lastSentFields[1]):
524 self.warn("field6," + str(binaryFields[6]) + "," + str(self.lastSentFields[1]))
525 return
526 if(binaryFields[3] != self.lastSentFields[3]):
527 self.setError("field3," + str(binaryFields[3]) + "," + str(self.lastSentFields[3]))
528 return
529 if(binaryFields[7] != self.lastSentFields[6]):
530 self.setError("field7," + str(binaryFields[7]) + "," + str(self.lastSentFields[6]))
531 return
532 if(binaryFields[8] != self.lastSentFields[3]):
533 self.setError("field8," + str(binaryFields[8]) + "," + str(self.lastSentFields[3]))
534 return
535
536 self.state += 1
537 return
538
539 elif(binaryFields[5] == 0):
540 # 200OK
541 message = MSNSLPMessage()
542 message.parse(packet)
543 if(message.sessionID != self.sessionID):
544 self.warn("sessionID" + str(message.sessionID) + "," + str(self.sessionID))
545 return
546 if(message.status != "200"):
547 self.setError("status" + message.status)
548 return
549 if(message.cseq != 1):
550 self.setError("cseq" + str(message.cseq))
551 return
552 if(message.sessionGuid != self.sguid):
553 self.setError("sessionGuid" + message.sessionGuid + "," + self.sguid)
554 return
555
556 self.lastFields = binaryFields
557 self.state += 1
558 return
559
560 else:
561 self.warn("Packet discarded," + str(binaryFields[5]))
562
563 if(self.state == self.WAIT_DATAPREP):
564 binaryFields = BinaryFields()
565 binaryFields.unpackFields(packet)
566
567 if(binaryFields[0] != self.sessionID):
568 self.warn("field0," + str(binaryFields[0]) + "," + str(self.sessionID))
569 return
570 if(binaryFields[3] != 4):
571 self.setError("field3," + str(binaryFields[3]))
572 return
573 if(binaryFields[4] != 4):
574 self.setError("field4," + str(binaryFields[4]))
575 return
576 if(binaryFields[9] != 1):
577 self.warn("field9," + str(binaryFields[9]))
578 # return
579
580 self.lastFields = binaryFields
581 self.state = self.SEND_DATAPREP_ACK
582 return
583
584 if(self.state == self.WAIT_DATA):
585 binaryFields = BinaryFields()
586 binaryFields.unpackFields(packet)
587 if(binaryFields[0] != self.sessionID):
588 self.warn("field0," + str(binaryFields[0]) + "," + str(self.sessionID))
589 return
590 if(binaryFields[5] != BinaryFields.DATA):
591 self.setError("field5," + str(binaryFields[5]))
592 return
593 if(binaryFields[9] != 1):
594 self.warn("field9," + str(binaryFields[9]))
595 # return
596 offset = binaryFields[2]
597 total = binaryFields[3]
598 length = binaryFields[4]
599 if(not self.fileData):
600 self.fileData = FileData(binaryFields[3])
601
602 data = packet[48:len(packet)-4]
603 self.fileData.put(offset, packet[48:len(packet)-4])
604
605 if self.fileData.finished():
606 self.state = self.SEND_DATA_ACK
607
608 self.lastFields = binaryFields
609
610 return
611
612 def getNextPacket(self):
613 if MSNP2P_DEBUG:
614 print "getNextPacket (Avatar_Receive)", self.to, self.fro, self.state
615 if(self.state == self.SEND_REQUEST):
616 msg = MSNSLPMessage()
617 msg.create(method="INVITE", to=self.to, fro=self.fro, cseq=0, sessionGuid=self.sguid)
618 msg.setData(sessionID=self.sessionID, appID="1", guid=self.EUF_GUID, context=utils.b64enc(self.msnobj.text + chr(0)))
619 msgStr = str(msg)
620
621 binaryFields = BinaryFields()
622 binaryFields[1] = self.baseID.get()
623 binaryFields[6] = random.randint(0, 2**30)
624 binaryFields[3] = len(msgStr)
625 binaryFields[4] = len(msgStr)
626
627 packet = binaryFields.packHeaders() + msgStr + binaryFields.packFooter()
628
629 self.state = self.WAIT_REQACK_200OK
630 self.lastSentFields = binaryFields
631 return packet
632
633 if(self.state == self.SEND_200OK_ACK):
634 binaryFields = BinaryFields()
635 binaryFields[1] = self.baseID.next()
636 binaryFields[3] = self.lastFields[3]
637 binaryFields[8] = self.lastFields[3]
638 binaryFields[5] = BinaryFields.ACK
639 binaryFields[6] = self.lastFields[1]
640 binaryFields[7] = self.lastFields[6]
641
642 packet = binaryFields.packHeaders() + binaryFields.packFooter()
643
644 self.state = self.WAIT_DATAPREP
645 self.lastSentFields = binaryFields
646 return packet
647
648 if(self.state == self.SEND_DATAPREP_ACK):
649 binaryFields = BinaryFields()
650 binaryFields[0] = self.sessionID
651 binaryFields[1] = self.baseID.next()
652 binaryFields[3] = 4
653 binaryFields[8] = 4
654 binaryFields[5] = BinaryFields.ACK
655 binaryFields[6] = self.lastFields[1]
656 binaryFields[7] = self.lastFields[6]
657
658 packet = binaryFields.packHeaders() + binaryFields.packFooter()
659
660 self.state = self.WAIT_DATA
661 self.lastSentFields = binaryFields
662 return packet
663
664 if(self.state == self.SEND_DATA_ACK):
665 # FIXME Check hash!
666 binaryFields = BinaryFields()
667 binaryFields[0] = self.sessionID
668 binaryFields[1] = self.baseID.next()
669 binaryFields[3] = self.lastFields[3]
670 binaryFields[8] = self.lastFields[3]
671 binaryFields[5] = BinaryFields.ACK
672 binaryFields[6] = self.lastFields[1]
673 binaryFields[7] = self.lastFields[6]
674
675 packet = binaryFields.packHeaders() + binaryFields.packFooter()
676
677 self.state = self.SEND_BYE
678 self.lastSentFields = binaryFields
679 return packet
680
681 if(self.state == self.SEND_BYE):
682 msg = MSNSLPMessage()
683 msg.create(method="BYE", to=self.to, fro=self.fro, cseq=0, sessionGuid=self.sguid)
684 msgStr = str(msg)
685
686 binaryFields = BinaryFields()
687 binaryFields[1] = self.baseID.next()
688 binaryFields[3] = len(msgStr)
689 binaryFields[4] = len(msgStr)
690 binaryFields[5] = BinaryFields.BYESENT
691 binaryFields[6] = random.randint(0, 2**30)
692
693 packet = binaryFields.packHeaders() + msgStr + binaryFields.packFooter()
694
695 self.state = self.FINISHED
696 self.lastSentFields = binaryFields
697 return packet
698
699
700