-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathslip.py
105 lines (92 loc) · 4.2 KB
/
slip.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
class CamadaEnlace:
ignore_checksum = False
def __init__(self, linhas_seriais):
"""
Inicia uma camada de enlace com um ou mais enlaces, cada um conectado
a uma linha serial distinta. O argumento linhas_seriais é um dicionário
no formato {ip_outra_ponta: linha_serial}. O ip_outra_ponta é o IP do
host ou roteador que se encontra na outra ponta do enlace, escrito como
uma string no formato 'x.y.z.w'. A linha_serial é um objeto da classe
PTY (vide camadafisica.py) ou de outra classe que implemente os métodos
registrar_recebedor e enviar.
"""
self.enlaces = {}
self.callback = None
# Constrói um Enlace para cada linha serial
for ip_outra_ponta, linha_serial in linhas_seriais.items():
enlace = Enlace(linha_serial)
self.enlaces[ip_outra_ponta] = enlace
enlace.registrar_recebedor(self._callback)
def registrar_recebedor(self, callback):
"""
Registra uma função para ser chamada quando dados vierem da camada de enlace
"""
self.callback = callback
def enviar(self, datagrama, next_hop):
"""
Envia datagrama para next_hop, onde next_hop é um endereço IPv4
fornecido como string (no formato x.y.z.w). A camada de enlace se
responsabilizará por encontrar em qual enlace se encontra o next_hop.
"""
# Encontra o Enlace capaz de alcançar next_hop e envia por ele
self.enlaces[next_hop].enviar(datagrama)
def _callback(self, datagrama):
if self.callback:
self.callback(datagrama)
class Enlace:
def __init__(self, linha_serial):
self.linha_serial = linha_serial
self.linha_serial.registrar_recebedor(self.__raw_recv)
self.residuos = b''
def registrar_recebedor(self, callback):
self.callback = callback
def enviar(self, datagrama):
# TODO: Preencha aqui com o código para enviar o datagrama pela linha
# serial, fazendo corretamente a delimitação de quadros e o escape de
# sequências especiais, de acordo com o protocolo CamadaEnlace (RFC 1055).
pass
#bytes de escape para 0xc0 e 0xdb
datagrama_original = datagrama
datagrama = b''
for byte in datagrama_original:
if byte == 0xc0:
datagrama += b'\xdb\xdc'
elif byte == 0xdb:
datagrama += b'\xdb\xdd'
else:
datagrama += bytes([byte])
#byte especial para saber onde o quadro começa e termina
datagrama = b'\xc0' + datagrama + b'\xc0'
self.linha_serial.enviar(datagrama)
def __raw_recv(self, dados):
# TODO: Preencha aqui com o código para receber dados da linha serial.
# Trate corretamente as sequências de escape. Quando ler um quadro
# completo, repasse o datagrama contido nesse quadro para a camada
# superior chamando self.callback. Cuidado pois o argumento dados pode
# vir quebrado de várias formas diferentes - por exemplo, podem vir
# apenas pedaços de um quadro, ou um pedaço de quadro seguido de um
# pedaço de outro, ou vários quadros de uma vez só.
pass
#juntando os dados residuais
dados = self.residuos + dados
self.residuos = b''
#separando os quadros
datagramas = dados.split(b'\xc0')
if dados[-1] != b'\xc0':
self.residuos = datagramas[-1]
datagramas = datagramas[:-1]
#separando os bytes de escape
for datagrama in datagramas:
datagrama = datagrama.replace(b'\xdb\xdc', b'\xc0')
datagrama = datagrama.replace(b'\xdb\xdd', b'\xdb')
if datagrama != b'':
try:
self.callback(datagrama)
except:
# ignora a exceção, mas mostra na tela
import traceback
traceback.print_exc()
finally:
# faça aqui a limpeza necessária para garantir que não vão sobrar
# pedaços do datagrama em nenhum buffer mantido por você
dados = b''