Skip to content

Commit

Permalink
Passo 1 feito
Browse files Browse the repository at this point in the history
  • Loading branch information
YaboiAst committed Jun 30, 2023
1 parent ef87e44 commit fb0abca
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 1 deletion.
24 changes: 23 additions & 1 deletion tcp.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import asyncio
import random
import sys
from tcputils import *
##

class Servidor:
def __init__(self, rede, porta):
self.rede = rede
Expand Down Expand Up @@ -34,6 +36,10 @@ def _rdt_rcv(self, src_addr, dst_addr, segment):
# A flag SYN estar setada significa que é um cliente tentando estabelecer uma conexão nova
# TODO: talvez você precise passar mais coisas para o construtor de conexão
conexao = self.conexoes[id_conexao] = Conexao(self, id_conexao)
response = fix_checksum(make_header(dst_port, src_port, random.randint(0, 0xffff), seq_no+1, FLAGS_ACK | FLAGS_SYN), dst_addr, src_addr)
self.rede.enviar(response, src_addr)
conexao.expected_seq = seq_no + 1
#print("retornando", response)
# TODO: você precisa fazer o handshake aceitando a conexão. Escolha se você acha melhor
# fazer aqui mesmo ou dentro da classe Conexao.
if self.callback:
Expand All @@ -53,6 +59,7 @@ def __init__(self, servidor, id_conexao):
self.callback = None
self.timer = asyncio.get_event_loop().call_later(1, self._exemplo_timer) # um timer pode ser criado assim; esta linha é só um exemplo e pode ser removida
#self.timer.cancel() # é possível cancelar o timer chamando esse método; esta linha é só um exemplo e pode ser removida
self.expected_seq = 0

def _exemplo_timer(self):
# Esta função é só um exemplo e pode ser removida
Expand All @@ -62,8 +69,23 @@ def _rdt_rcv(self, seq_no, ack_no, flags, payload):
# TODO: trate aqui o recebimento de segmentos provenientes da camada de rede.
# Chame self.callback(self, dados) para passar dados para a camada de aplicação após
# garantir que eles não sejam duplicados e que tenham sido recebidos em ordem.
#
print(seq_no, self.expected_seq)
if seq_no != self.expected_seq:
#print(seq_no, ": expected ", self.expected_seq)
return

print('recebido payload: %r' % payload)

# ACK
src_addr, src_port, dst_addr, dst_port = self.id_conexao
response = fix_checksum(make_header(dst_port, src_port, ack_no + len(payload), seq_no, FLAGS_ACK), dst_addr, src_addr)
self.servidor.rede.enviar(response, dst_addr)

# Passa para a camada de aplicação
self.expected_seq = seq_no + len(payload)
self.callback(self, payload)

# Os métodos abaixo fazem parte da API

def registrar_recebedor(self, callback):
Expand Down
93 changes: 93 additions & 0 deletions tcputils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Você pode usar tudo que está definido neste arquivo na sua implementação de TCP,
# porém NÃO EDITE este arquivo. Se você editá-lo, ele será ignorado pelo robô de
# correção do Autolab, pois os testes dependem das definições aqui realizadas.

import struct

# Valores das flags que serão usadas na nossa implementação simplificada
FLAGS_FIN = 1<<0
FLAGS_SYN = 1<<1
FLAGS_RST = 1<<2
FLAGS_ACK = 1<<4

MSS = 1460 # Tamanho do payload de um segmento TCP (em bytes)


def make_header(src_port, dst_port, seq_no, ack_no, flags):
"""
Constrói um cabeçalho TCP simplificado.
Consulte o formato completo em https://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_segment_structure
"""
return struct.pack('!HHIIHHHH',
src_port, dst_port, seq_no, ack_no, (5 << 12) | flags,
8*MSS, 0, 0)


def read_header(segment):
"""
Lê um cabeçalho
"""
src_port, dst_port, seq_no, ack_no, \
flags, window_size, checksum, urg_ptr = \
struct.unpack('!HHIIHHHH', segment[:20])
return src_port, dst_port, seq_no, ack_no, \
flags, window_size, checksum, urg_ptr


def calc_checksum(segment, src_addr=None, dst_addr=None):
"""
Calcula o checksum complemento-de-um (formato do TCP e do UDP) para os
dados fornecidos.
É necessário passar os endereços IPv4 de origem e de destino, já que
apesar de não fazerem parte da camada de transporte, eles são incluídos
no pseudocabeçalho, que faz parte do cálculo do checksum.
Os endereços IPv4 devem ser passados como string (no formato x.y.z.w)
"""
if src_addr is None and dst_addr is None:
data = segment
else:
pseudohdr = str2addr(src_addr) + str2addr(dst_addr) + \
struct.pack('!HH', 0x0006, len(segment))
data = pseudohdr + segment

if len(data) % 2 == 1:
# se for ímpar, faz padding à direita
data += b'\x00'
checksum = 0
for i in range(0, len(data), 2):
x, = struct.unpack('!H', data[i:i+2])
checksum += x
while checksum > 0xffff:
checksum = (checksum & 0xffff) + 1
checksum = ~checksum
return checksum & 0xffff


def fix_checksum(segment, src_addr, dst_addr):
"""
Corrige o checksum de um segmento TCP.
"""
seg = bytearray(segment)
seg[16:18] = b'\x00\x00'
seg[16:18] = struct.pack('!H', calc_checksum(seg, src_addr, dst_addr))
return bytes(seg)


def addr2str(addr):
"""
Converte um endereço IPv4 binário para uma string (no formato x.y.z.w)
"""
return '%d.%d.%d.%d' % tuple(int(x) for x in addr)


def str2addr(addr):
"""
Converte uma string (no formato x.y.z.w) para um endereço IPv4 binário
"""
return bytes(int(x) for x in addr.split('.'))



0 comments on commit fb0abca

Please sign in to comment.