2 # -*- coding: utf-8 -*-
4 # Copyright (c) 2018-2021 Niklas Ekström
16 logging.basicConfig(format = '%(levelname)s, %(asctime)s, %(name)s, line %(lineno)d: %(message)s')
17 logger = logging.getLogger(__name__)
18 logger.setLevel(logging.INFO)
20 CONFIG_FILE_PATH = 'a314/files_pi/a314fs.conf'
22 SHARED_DIRECTORY = 'data/a314shared'
23 METAFILE_EXTENSION = ':a314'
25 with open(CONFIG_FILE_PATH, encoding='utf-8') as f:
29 SHARED_DIRECTORY = dev['path']
33 MSG_DEREGISTER_REQ = 3
34 MSG_DEREGISTER_RES = 4
40 MSG_CONNECT_RESPONSE = 10
47 while len(header) < 9:
48 data = drv.recv(9 - len(header))
50 logger.error('Connection to a314d was closed, terminating.')
53 (plen, stream_id, ptype) = struct.unpack('=IIB', header)
55 while len(payload) < plen:
56 data = drv.recv(plen - len(payload))
58 logger.error('Connection to a314d was closed, terminating.')
61 return (stream_id, ptype, payload)
63 def send_register_req(name):
64 m = struct.pack('=IIB', len(name), 0, MSG_REGISTER_REQ) + name
67 def send_read_mem_req(address, length):
68 m = struct.pack('=IIBII', 8, 0, MSG_READ_MEM_REQ, address, length)
71 def read_mem(address, length):
72 send_read_mem_req(address, length)
73 stream_id, ptype, payload = wait_for_msg()
74 if ptype != MSG_READ_MEM_RES:
75 logger.error('Expected MSG_READ_MEM_RES but got %s. Shutting down.', ptype)
79 def send_write_mem_req(address, data):
80 m = struct.pack('=IIBI', 4 + len(data), 0, MSG_WRITE_MEM_REQ, address) + data
83 def write_mem(address, data):
84 send_write_mem_req(address, data)
85 stream_id, ptype, payload = wait_for_msg()
86 if ptype != MSG_WRITE_MEM_RES:
87 logger.error('Expected MSG_WRITE_MEM_RES but got %s. Shutting down.', ptype)
90 def send_connect_response(stream_id, result):
91 m = struct.pack('=IIBB', 1, stream_id, MSG_CONNECT_RESPONSE, result)
94 def send_data(stream_id, data):
95 m = struct.pack('=IIB', len(data), stream_id, MSG_DATA) + data
98 def send_eos(stream_id):
99 m = struct.pack('=IIB', 0, stream_id, MSG_EOS)
102 def send_reset(stream_id):
103 m = struct.pack('=IIB', 0, stream_id, MSG_RESET)
111 ACTION_CURRENT_VOLUME = 7
112 ACTION_LOCATE_OBJECT = 8
113 ACTION_RENAME_DISK = 9
114 ACTION_WRITE = ord('W')
115 ACTION_READ = ord('R')
116 ACTION_FREE_LOCK = 15
117 ACTION_DELETE_OBJECT = 16
118 ACTION_RENAME_OBJECT = 17
119 ACTION_MORE_CACHE = 18
121 ACTION_WAIT_CHAR = 20
122 ACTION_SET_PROTECT = 21
123 ACTION_CREATE_DIR = 22
124 ACTION_EXAMINE_OBJECT = 23
125 ACTION_EXAMINE_NEXT = 24
126 ACTION_DISK_INFO = 25
129 ACTION_SET_COMMENT = 28
133 ACTION_DISK_TYPE = 32
134 ACTION_DISK_CHANGE = 33
136 ACTION_SAME_LOCK = 40
137 ACTION_SCREEN_MODE = 994
138 ACTION_READ_RETURN = 1001
139 ACTION_WRITE_RETURN = 1002
140 ACTION_FINDUPDATE = 1004
141 ACTION_FINDINPUT = 1005
142 ACTION_FINDOUTPUT = 1006
145 ACTION_TRUNCATE = 1022
146 ACTION_WRITE_PROTECT = 1023
147 ACTION_EXAMINE_FH = 1034
148 ACTION_UNSUPPORTED = 65535
150 ERROR_NO_FREE_STORE = 103
151 ERROR_TASK_TABLE_FULL = 105
152 ERROR_LINE_TOO_LONG = 120
153 ERROR_FILE_NOT_OBJECT = 121
154 ERROR_INVALID_RESIDENT_LIBRARY = 122
155 ERROR_NO_DEFAULT_DIR = 201
156 ERROR_OBJECT_IN_USE = 202
157 ERROR_OBJECT_EXISTS = 203
158 ERROR_DIR_NOT_FOUND = 204
159 ERROR_OBJECT_NOT_FOUND = 205
160 ERROR_BAD_STREAM_NAME = 206
161 ERROR_OBJECT_TOO_LARGE = 207
162 ERROR_ACTION_NOT_KNOWN = 209
163 ERROR_INVALID_COMPONENT_NAME = 210
164 ERROR_INVALID_LOCK = 211
165 ERROR_OBJECT_WRONG_TYPE = 212
166 ERROR_DISK_NOT_VALIDATED = 213
167 ERROR_DISK_WRITE_PROTECTED = 214
168 ERROR_RENAME_ACROSS_DEVICES = 215
169 ERROR_DIRECTORY_NOT_EMPTY = 216
170 ERROR_TOO_MANY_LEVELS = 217
171 ERROR_DEVICE_NOT_MOUNTED = 218
172 ERROR_SEEK_ERROR = 219
173 ERROR_COMMENT_TOO_BIG = 220
174 ERROR_DISK_FULL = 221
175 ERROR_DELETE_PROTECTED = 222
176 ERROR_WRITE_PROTECTED = 223
177 ERROR_READ_PROTECTED = 224
178 ERROR_NOT_A_DOS_DISK = 225
180 ERROR_NO_MORE_ENTRIES = 232
189 MODE_OLDFILE = 1005 # Open existing file read/write positioned at beginning of file.
190 MODE_NEWFILE = 1006 # Open freshly created file (delete old file) read/write, exclusive lock.
191 MODE_READWRITE = 1004 # Open old file w/shared lock, creates file if doesn't exist.
193 OFFSET_BEGINNING = -1 # Relative to Begining Of File.
194 OFFSET_CURRENT = 0 # Relative to Current file position.
195 OFFSET_END = 1 # relative to End Of File.
199 ST_SOFTLINK = 3 # looks like dir, but may point to a file!
200 ST_LINKDIR = 4 # hard link to dir
201 ST_FILE = -3 # must be negative for FIB!
202 ST_LINKFILE = -4 # hard link to file
205 current_stream_id = 0
207 class ObjectLock(object):
208 def __init__(self, key, mode, path):
221 next_key = 1 if next_key == 0x7fffffff else (next_key + 1)
226 def find_path(key, name):
229 vol = name[:i].lower()
230 if vol == '' or vol == 'pi0' or vol == 'pidisk':
253 p = '.' if len(cp) == 0 else '/'.join(cp)
254 entries = os.listdir(p)
257 if comp.lower() == e.lower():
269 def read_metadata(path):
273 if not os.path.isfile(path + METAFILE_EXTENSION):
274 return (protection, comment)
277 f = open(path + METAFILE_EXTENSION, 'r')
281 protection = int(line[1:].strip())
285 comment = line[1:].strip()[:79]
287 except FileNotFoundError:
289 return (protection, comment)
291 def write_metadata(path, protection=None, comment=None):
292 p, c = read_metadata(path)
294 if protection == None:
299 if (p, c) == (protection, comment):
303 f = open(path + METAFILE_EXTENSION, 'w')
304 f.write('p' + str(protection) + '\n')
305 f.write('c' + comment + '\n')
307 except FileNotFoundError as e:
308 logger.warning('Failed to write metadata for file %s: %s', path, e)
312 def process_locate_object(key, mode, name):
313 logger.debug('ACTION_LOCATE_OBJECT, key: %s, mode: %s, name: %s', key, mode, name)
315 cp = find_path(key, name)
317 if cp is None or not (len(cp) == 0 or os.path.exists('/'.join(cp))):
318 return struct.pack('>HH', 0, ERROR_OBJECT_NOT_FOUND)
320 # TODO: Must check if there is already a lock for this path,
321 # and if so, if the locks are compatible.
324 locks[key] = ObjectLock(key, mode, cp)
325 return struct.pack('>HHI', 1, 0, key)
327 def process_free_lock(key):
328 logger.debug('ACTION_FREE_LOCK, key: %s', key)
331 return struct.pack('>HH', 1, 0)
333 def process_copy_dir(prev_key):
334 logger.debug('ACTION_COPY_DIR, prev_key: %s', prev_key)
337 locks[key] = ObjectLock(key, ol.mode, ol.path)
338 return struct.pack('>HHI', 1, 0, key)
340 def process_parent(prev_key):
341 logger.debug('ACTION_PARENT, prev_key: %s', prev_key)
343 if len(ol.path) == 0:
347 locks[key] = ObjectLock(key, SHARED_LOCK, ol.path[:-1])
348 return struct.pack('>HHI', 1, 0, key)
350 def mtime_to_dmt(mtime):
352 days = mtime // 86400
353 left = mtime - days * 86400
355 secs = left - mins * 60
357 days -= 2922 # Days between 1970-01-01 and 1978-01-01
358 days = max(0, days) # If days are before Amiga epoc
359 return (days, mins, ticks)
361 def process_examine_object(key):
362 logger.debug('ACTION_EXAMINE_OBJECT, key: %s', key)
365 if len(ol.path) == 0:
370 path = '/'.join(ol.path)
372 days, mins, ticks = mtime_to_dmt(os.path.getmtime(path))
373 protection, comment = read_metadata(path)
375 if os.path.isfile(path):
376 size = os.path.getsize(path)
381 ol.entry_it = os.scandir(path)
383 size = min(size, 2 ** 31 - 1)
384 fn = (chr(len(fn)) + fn).encode('latin-1', 'ignore')
385 comment = (chr(len(comment)) + comment).encode('latin-1', 'ignore')
386 return struct.pack('>HHHhIIIII', 1, 0, 666, type_, size, protection, days, mins, ticks) + fn + comment
388 def process_examine_next(key, disk_key):
389 logger.debug('ACTION_EXAMINE_NEXT, key: %s, disk_key: %s', key, disk_key)
392 if len(ol.path) == 0:
395 path = '/'.join(ol.path)
397 if not os.path.isdir(path):
398 return struct.pack('>HH', 0, ERROR_OBJECT_WRONG_TYPE)
402 entry = next(ol.entry_it, None)
403 while entry and entry.name.endswith(METAFILE_EXTENSION):
404 entry = next(ol.entry_it, None)
407 return struct.pack('>HH', 0, ERROR_NO_MORE_ENTRIES)
410 path = ('/'.join(ol.path + (fn,)))
412 days, mins, ticks = mtime_to_dmt(entry.stat().st_mtime)
413 protection, comment = read_metadata(path)
415 if os.path.isfile(path):
416 size = os.path.getsize(path)
422 size = min(size, 2 ** 31 - 1)
423 fn = (chr(len(fn)) + fn).encode('latin-1', 'ignore')
424 comment = (chr(len(comment)) + comment).encode('latin-1', 'ignore')
425 return struct.pack('>HHHhIIIII', 1, 0, disk_key, type_, size, protection, days, mins, ticks) + fn + comment
427 def process_examine_fh(arg1):
428 logger.debug('ACTION_EXAMINE_FH, arg1: %s', arg1)
430 fn = open_file_handles[arg1].f.name
431 path = os.path.realpath(fn)
432 days, mins, ticks = mtime_to_dmt(os.path.getmtime(path))
433 protection, comment = read_metadata(path)
435 if os.path.isfile(path):
436 size = os.path.getsize(path)
442 size = min(size, 2 ** 31 - 1)
443 fn = (chr(len(fn)) + fn).encode('latin-1', 'ignore')
444 comment = (chr(len(comment)) + comment).encode('latin-1', 'ignore')
445 return struct.pack('>HHHhIIIII', 1, 0, 666, type_, size, protection, days, mins, ticks) + fn + comment
450 open_file_handles = {}
455 next_fp = 1 if next_fp == 0x7fffffff else next_fp + 1
456 while fp in open_file_handles:
460 class OpenFileHandle(object):
461 def __init__(self, fp, f, p):
466 def process_findxxx(mode, key, name):
467 if mode == ACTION_FINDINPUT:
468 logger.debug('ACTION_FINDINPUT, key: %s, name: %s', key, name)
469 elif mode == ACTION_FINDOUTPUT:
470 logger.debug('ACTION_FINDOUTPUT, key: %s, name: %s', key, name)
471 elif mode == ACTION_FINDUPDATE:
472 logger.debug('ACTION_FINDUPDATE, key: %s, name: %s', key, name)
474 cp = find_path(key, name)
476 return struct.pack('>HH', 0, ERROR_OBJECT_NOT_FOUND)
479 if len(cp) == 0 or os.path.isdir(path):
480 return struct.pack('>HH', 0, ERROR_OBJECT_WRONG_TYPE)
482 # TODO: Must check if there already exists a non-compatible lock for this path.
484 # TODO: This must be handled better. Especially error reporting.
486 protection, _ = read_metadata(path)
488 if mode == MODE_OLDFILE:
489 f = open(path, 'r+b')
490 elif mode == MODE_READWRITE:
491 f = open(path, 'r+b')
493 protection = protection & 0b11101111
494 write_metadata(path, protection=protection)
495 elif mode == MODE_NEWFILE:
497 return struct.pack('>HH', 0, ERROR_DELETE_PROTECTED)
498 elif protection & 0x4:
499 return struct.pack('>HH', 0, ERROR_WRITE_PROTECTED)
500 f = open(path, 'w+b')
502 protection = protection & 0b11101111
503 write_metadata(path, protection=protection)
505 if mode == MODE_READWRITE:
507 f = open(path, 'w+b')
509 protection = protection & 0b11101111
510 write_metadata(path, protection=protection)
512 return struct.pack('>HH', 0, ERROR_OBJECT_NOT_FOUND)
514 return struct.pack('>HH', 0, ERROR_OBJECT_NOT_FOUND)
517 ofh = OpenFileHandle(fp, f, protection)
518 open_file_handles[fp] = ofh
520 return struct.pack('>HHI', 1, 0, fp)
522 def process_read(arg1, address, length):
523 logger.debug('ACTION_READ, arg1: %s, address: %s, length: %s', arg1, address, length)
524 protection = open_file_handles[arg1].p
526 return struct.pack('>HH', 0, ERROR_READ_PROTECTED)
527 f = open_file_handles[arg1].f
528 data = f.read(length)
530 write_mem(address, data)
531 return struct.pack('>HHI', 1, 0, len(data))
533 def process_write(arg1, address, length):
534 logger.debug('ACTION_WRITE, arg1: %s, address: %s, length: %s', arg1, address, length)
535 protection = open_file_handles[arg1].p
537 return struct.pack('>HH', 0, ERROR_WRITE_PROTECTED)
538 data = read_mem(address, length)
539 f = open_file_handles[arg1].f
544 return struct.pack('>HH', 0, ERROR_DISK_FULL)
545 return struct.pack('>HHI', 1, 0, length)
547 def process_seek(arg1, new_pos, mode):
548 logger.debug('ACTION_SEEK, arg1: %s, new_pos: %s, mode: %s', arg1, new_pos, mode)
550 f = open_file_handles[arg1].f
554 if mode == OFFSET_CURRENT:
556 elif mode == OFFSET_END:
559 f.seek(new_pos, from_what)
561 return struct.pack('>HHi', 1, 0, old_pos)
563 def process_end(arg1):
564 logger.debug('ACTION_END, arg1: %s', arg1)
566 if arg1 in open_file_handles:
567 f = open_file_handles.pop(arg1).f
570 return struct.pack('>HH', 1, 0)
572 def process_delete_object(key, name):
573 logger.debug('ACTION_DELETE_OBJECT, key: %s, name: %s', key, name)
575 cp = find_path(key, name)
576 if cp is None or len(cp) == 0:
577 return struct.pack('>HH', 0, ERROR_OBJECT_NOT_FOUND)
580 is_dir = os.path.isdir(path)
582 protection, _ = read_metadata(path)
584 return struct.pack('>HH', 0, ERROR_DELETE_PROTECTED)
591 if os.path.isfile(path + METAFILE_EXTENSION):
592 os.remove(path + METAFILE_EXTENSION)
595 return struct.pack('>HH', 0, ERROR_DIRECTORY_NOT_EMPTY)
597 return struct.pack('>HH', 0, ERROR_OBJECT_NOT_FOUND)
599 return struct.pack('>HH', 1, 0)
601 def process_rename_object(key, name, target_dir, new_name):
602 logger.debug('ACTION_RENAME_OBJECT, key: %s, name: %s, target_dir: %s, new_name: %s', key, name, target_dir, new_name)
604 cp1 = find_path(key, name)
605 if cp1 is None or len(cp1) == 0:
606 return struct.pack('>HH', 0, ERROR_OBJECT_NOT_FOUND)
608 from_path = '/'.join(cp1)
609 if not os.path.exists(from_path):
610 return struct.pack('>HH', 0, ERROR_OBJECT_NOT_FOUND)
612 cp2 = find_path(target_dir, new_name)
613 if cp2 is None or len(cp2) == 0:
614 return struct.pack('>HH', 0, ERROR_OBJECT_NOT_FOUND)
616 to_path = '/'.join(cp2)
618 if from_path == to_path:
619 return struct.pack('>HH', 1, 0)
621 if os.path.exists(to_path):
622 return struct.pack('>HH', 0, ERROR_OBJECT_EXISTS)
625 os.rename(from_path, to_path)
626 if os.path.isfile(from_path + METAFILE_EXTENSION):
627 os.rename(from_path + METAFILE_EXTENSION, to_path + METAFILE_EXTENSION)
629 return struct.pack('>HH', 0, ERROR_OBJECT_NOT_FOUND)
631 return struct.pack('>HH', 1, 0)
633 def process_create_dir(key, name):
634 logger.debug('ACTION_CREATE_DIR, key: %s, name: %s', key, name)
636 cp = find_path(key, name)
637 if cp is None or len(cp) == 0:
638 return struct.pack('>HH', 0, ERROR_OBJECT_NOT_FOUND)
644 return struct.pack('>HH', 0, ERROR_OBJECT_NOT_FOUND)
647 locks[key] = ObjectLock(key, SHARED_LOCK, cp)
648 return struct.pack('>HHI', 1, 0, key)
650 def process_set_protect(key, name, mask):
651 logger.debug('ACTION_SET_PROTECT, key: %s, name: %s, mask: %s', key, name, mask)
653 cp = find_path(key, name)
654 if cp is None or len(cp) == 0:
655 return struct.pack('>HH', 0, ERROR_OBJECT_NOT_FOUND)
658 if write_metadata(path, protection=mask):
659 return struct.pack('>HH', 1, 0)
661 return struct.pack('>HH', 0, ERROR_OBJECT_NOT_FOUND)
663 def process_set_comment(key, name, comment):
664 logger.debug('ACTION_SET_COMMENT, key: %s, name: %s, comment: %s', key, name, comment)
666 if len(comment) > 79:
667 return struct.pack('>HH', 0, ERROR_COMMENT_TOO_BIG)
669 cp = find_path(key, name)
670 if cp is None or len(cp) == 0:
671 return struct.pack('>HH', 0, ERROR_OBJECT_NOT_FOUND)
674 if write_metadata(path, comment=comment):
675 return struct.pack('>HH', 1, 0)
677 return struct.pack('>HH', 0, ERROR_OBJECT_NOT_FOUND)
679 def process_same_lock(key1, key2):
680 logger.debug('ACTION_SAME_LOCK, key1: %s key2: %s', key1, key2)
682 if not (key1 in locks and key2 in locks):
683 return struct.pack('>HH', 0, LOCK_DIFFERENT)
684 elif locks[key1].path == locks[key2].path:
685 return struct.pack('>HH', 1, LOCK_SAME)
687 return struct.pack('>HH', 0, LOCK_SAME_VOLUME)
689 def process_request(req):
690 #logger.debug('len(req): %s, req: %s', len(req), list(req))
692 (rtype,) = struct.unpack('>H', req[:2])
694 if rtype == ACTION_LOCATE_OBJECT:
695 key, mode, nlen = struct.unpack('>IHB', req[2:9])
696 name = req[9:9+nlen].decode('latin-1')
697 return process_locate_object(key, mode, name)
698 elif rtype == ACTION_FREE_LOCK:
699 (key,) = struct.unpack('>I', req[2:6])
700 return process_free_lock(key)
701 elif rtype == ACTION_COPY_DIR:
702 (key,) = struct.unpack('>I', req[2:6])
703 return process_copy_dir(key)
704 elif rtype == ACTION_PARENT:
705 (key,) = struct.unpack('>I', req[2:6])
706 return process_parent(key)
707 elif rtype == ACTION_EXAMINE_OBJECT:
708 (key,) = struct.unpack('>I', req[2:6])
709 return process_examine_object(key)
710 elif rtype == ACTION_EXAMINE_NEXT:
711 key, disk_key = struct.unpack('>IH', req[2:8])
712 return process_examine_next(key, disk_key)
713 elif rtype == ACTION_EXAMINE_FH:
714 (arg1,) = struct.unpack('>I', req[2:6])
715 return process_examine_fh(arg1)
716 elif rtype == ACTION_FINDINPUT or rtype == ACTION_FINDOUTPUT or rtype == ACTION_FINDUPDATE:
717 key, nlen = struct.unpack('>IB', req[2:7])
718 name = req[7:7+nlen].decode('latin-1')
719 return process_findxxx(rtype, key, name)
720 elif rtype == ACTION_READ:
721 arg1, address, length = struct.unpack('>III', req[2:14])
722 return process_read(arg1, address, length)
723 elif rtype == ACTION_WRITE:
724 arg1, address, length = struct.unpack('>III', req[2:14])
725 return process_write(arg1, address, length)
726 elif rtype == ACTION_SEEK:
727 arg1, new_pos, mode = struct.unpack('>Iii', req[2:14])
728 return process_seek(arg1, new_pos, mode)
729 elif rtype == ACTION_END:
730 (arg1,) = struct.unpack('>I', req[2:6])
731 return process_end(arg1)
732 elif rtype == ACTION_DELETE_OBJECT:
733 key, nlen = struct.unpack('>IB', req[2:7])
734 name = req[7:7+nlen].decode('latin-1')
735 return process_delete_object(key, name)
736 elif rtype == ACTION_RENAME_OBJECT:
737 key, target_dir, nlen, nnlen = struct.unpack('>IIBB', req[2:12])
738 name = req[12:12+nlen].decode('latin-1')
739 new_name = req[12+nlen:12+nlen+nnlen].decode('latin-1')
740 return process_rename_object(key, name, target_dir, new_name)
741 elif rtype == ACTION_CREATE_DIR:
742 key, nlen = struct.unpack('>IB', req[2:7])
743 name = req[7:7+nlen].decode('latin-1')
744 return process_create_dir(key, name)
745 elif rtype == ACTION_SET_PROTECT:
746 key, mask, nlen = struct.unpack('>IIB', req[2:11])
747 name = req[11:11+nlen].decode('latin-1')
748 return process_set_protect(key, name, mask)
749 elif rtype == ACTION_SET_COMMENT:
750 key, nlen, clen = struct.unpack('>IBB', req[2:8])
751 name = req[8:8+nlen].decode('latin-1')
752 comment = req[8+nlen:8+nlen+clen].decode('latin-1')
753 return process_set_comment(key, name, comment)
754 elif rtype == ACTION_SAME_LOCK:
755 key1, key2 = struct.unpack('>II', req[2:10])
756 return process_same_lock(key1, key2)
757 elif rtype == ACTION_UNSUPPORTED:
758 (dp_Type,) = struct.unpack('>H', req[2:4])
759 logger.warning('Unsupported action %d (Amiga/a314fs)', dp_Type)
760 return struct.pack('>HH', 0, ERROR_ACTION_NOT_KNOWN)
762 logger.warning('Unsupported action %d (a314d/a314fs)', rtype)
763 return struct.pack('>HH', 0, ERROR_ACTION_NOT_KNOWN)
768 idx = sys.argv.index('-ondemand')
773 fd = int(sys.argv[idx + 1])
774 drv = socket.socket(fileno=fd)
776 drv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
777 drv.connect(('localhost', 7110))
779 send_register_req(b'a314fs')
780 stream_id, ptype, payload = wait_for_msg()
782 logger.error('Unable to register service a314fs, shutting down')
787 os.chdir(SHARED_DIRECTORY)
788 logger.info('a314fs is running, shared directory: %s', SHARED_DIRECTORY)
791 stream_id, ptype, payload = wait_for_msg()
793 if ptype == MSG_CONNECT:
794 if payload == b'a314fs':
795 if current_stream_id is not None:
796 send_reset(current_stream_id)
797 current_stream_id = stream_id
798 send_connect_response(stream_id, 0)
800 send_connect_response(stream_id, 3)
801 elif ptype == MSG_DATA:
802 address, length = struct.unpack('>II', payload)
803 #logger.debug('address: %s, length: %s', address, length)
804 req = read_mem(address + 2, length - 2)
805 res = process_request(req)
806 write_mem(address + 2, res)
807 #write_mem(address, b'\xff\xff')
808 send_data(stream_id, b'\xff\xff')
809 elif ptype == MSG_EOS:
810 if stream_id == current_stream_id:
811 logger.debug('Got EOS, stream closed')
813 current_stream_id = None
814 elif ptype == MSG_RESET:
815 if stream_id == current_stream_id:
816 logger.debug('Got RESET, stream closed')
817 current_stream_id = None