-
-
Save chintanparikh/d1274988ef436a411eac to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/Users/chintanparikh/.rvm/rubies/ruby-2.1.0/lib/ruby/2.1.0/timeout.rb:38:in `throw': uncaught throw #<Timeout::ExitException: Timeout::ExitException> (ArgumentError) | |
from /Users/chintanparikh/.rvm/rubies/ruby-2.1.0/lib/ruby/2.1.0/timeout.rb:38:in `exception' | |
from /Users/chintanparikh/Crap/project-3/rtp_socket.rb:203:in `send' | |
from /Users/chintanparikh/Crap/project-3/rtp_socket.rb:203:in `block in send_packet' | |
from /Users/chintanparikh/.rvm/rubies/ruby-2.1.0/lib/ruby/2.1.0/timeout.rb:82:in `block in timeout' | |
from /Users/chintanparikh/.rvm/rubies/ruby-2.1.0/lib/ruby/2.1.0/timeout.rb:70:in `catch' | |
from /Users/chintanparikh/.rvm/rubies/ruby-2.1.0/lib/ruby/2.1.0/timeout.rb:70:in `timeout' | |
from /Users/chintanparikh/Crap/project-3/rtp_socket.rb:202:in `send_packet' | |
from /Users/chintanparikh/Crap/project-3/rtp_socket.rb:150:in `block in send' | |
from /Users/chintanparikh/Crap/project-3/rtp_socket.rb:148:in `each' | |
from /Users/chintanparikh/Crap/project-3/rtp_socket.rb:148:in `send' | |
from client.rb:8:in `<main>' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'timeout' | |
require 'debugger' | |
class RTPSocket | |
def initialize ip_address, port, emu_ip, emu_port | |
@source_port = port | |
@source_ip = ip_address | |
@dest_port = nil | |
@dest_ip = nil | |
@emu_ip = emu_ip | |
@emu_port = emu_port | |
@connected = false | |
@terminated = false | |
@window = 1024 | |
@timeout = 5 | |
@rtt = 1 | |
@mss = 1024 | |
@buffer_size = @mss + 1024 | |
@seq_num = 0 | |
@send_seq_number = 0 | |
@expected_seq_number = 0 | |
@ack_number = 0 | |
@udp_socket = UDPSocket.new | |
@udp_socket.bind(@source_ip, @source_port) | |
end | |
# Server socket will connect to an IP Address and Port if a SYN packet is received: | |
# Validate checksum. If SYN, extract sequence number, IP, port and checksum | |
# Randomly generate initial sequence number | |
# Send SYNACK back with ACK = sequence_num + 1. Also send servers initial seq num. Increment seq num | |
def connect ip, port | |
port = @source_port.to_i + 1 | |
ip = @source_ip | |
@dest_ip = ip | |
@dest_port = port | |
@seq_num = Random.rand(1..(2**32)) | |
synack = nil | |
while synack.nil? | |
send_syn_packet @seq_num | |
synack = receive_packet | |
end | |
@ack_num = synack.seq_num + 1 | |
puts "Received SYNACK with seq_num #{synack.seq_num}, ack num #{synack.ack_num}" | |
send_ack_packet synack | |
puts "Sent final ACK packet. Connection established" | |
end | |
def disconnect | |
return unless @connected | |
if !@terminated | |
trm_packet = make_trm_packet | |
puts "Sending TRM packet" | |
send_packet trm_packet | |
puts "Received TRMACK" | |
@terminated = true | |
receive() | |
elsif @terminated # we have already terminated and just received a TRM packet from the other side | |
begin | |
packet = receive_packet | |
rescue | |
unless packet | |
send_ack_packet(packet) | |
receive() | |
end | |
end | |
end | |
@udp_socket.close | |
@connected = false | |
end | |
def listen | |
puts "Listening for a client to connect" | |
if @connected | |
puts "Already connected to a client" | |
return -1 | |
end | |
step = 0 | |
loop do | |
begin | |
packet = receive_packet | |
if step == 1 and packet.nil? | |
send_syn_ack_packet @seq_num, @ack_num | |
puts "Sent SYNACK packet" | |
end | |
if packet and packet.SYN.to_b and (step == 0 or step == 1) | |
puts "Received SYN Packet with sequence number #{packet.seq_num}" | |
@dest_ip = packet.dest_ip | |
@dest_port = packet.dest_port | |
@ack_num = packet.seq_num + 1 | |
@seq_num = Random.rand(1..(2**32)) | |
send_syn_ack_packet @seq_num, @ack_num | |
step = 1 | |
puts "Sent SYNACK packet" | |
elsif packet and packet.ACK.to_b and (step == 1 or step == 2) | |
puts "Got final packet for listen step with ack_num #{packet.ack_num}" | |
break | |
elsif packet and packet.data and step == 2 | |
break | |
end | |
rescue | |
end | |
end | |
puts "Connected to client" | |
@connected = true | |
end | |
def packetize data | |
packets = [] | |
byte_pointer = 0 | |
while byte_pointer + @mss < data.length | |
bytes_to_send = data[byte_pointer..byte_pointer + @mss] | |
packet = make_packet(bytes_to_send) | |
packets.push(packet) | |
byte_pointer += @mss | |
end | |
last_bytes = data[byte_pointer..-1] | |
packet = make_packet(last_bytes) | |
packets.push(packet) | |
packets | |
end | |
def send data | |
packets = packetize data | |
packets.each do |packet| | |
ack = nil | |
send_packet packet | |
end | |
packet = make_packet nil | |
send_packet packet | |
end | |
def receive | |
data_bytes = '' | |
disconnect = false | |
loop do | |
begin | |
packet = receive_packet | |
puts "Received packet - #{packet.data}" | |
rescue Timeout::Error | |
continue | |
end | |
if packet.TRM.to_b | |
disconnect = true | |
send_ack_packet packet | |
break | |
elsif packet.data == '' and not packet.ACK.to_b | |
puts "Received entire message" | |
send_ack_packet packet | |
break | |
elsif not packet.ACK.to_b | |
data_bytes += packet.data | |
# send_ack_packet packet | |
end | |
end | |
puts "Received entire message" | |
if disconnect | |
disconnect() | |
return nil | |
end | |
return data_bytes | |
end | |
def send_packet packet | |
puts "Sending packet with sequence number #{packet.seq_num}" | |
ack_packet = nil | |
packet_string = packet.to_s | |
@seq_num += packet_string.bytesize | |
while ack_packet == nil | |
begin | |
Timeout.timeout(@timeout) do | |
@udp_socket.send(packet_string, 0, @emu_ip, @emu_port) | |
puts "Sent packet" | |
recv_packet = receive_packet | |
puts "Received packet with ack number #{recv_packet.ack_num}" if recv_packet | |
if recv_packet and recv_packet.ACK and recv_packet.ack_num == packet.seq_num + 1 | |
ack_packet = recv_packet | |
return ack_packet | |
end | |
end | |
rescue Timeout::Error | |
rescue Timeout::ExitException | |
end | |
end | |
end | |
def receive_packet | |
begin | |
Timeout.timeout(@timeout) do | |
packet_string, addr = @udp_socket.recvfrom(@buffer_size) | |
packet = Packet.from_string(packet_string) | |
puts "Returning packet" | |
return packet | |
# unless packet.corrupted? | |
# unless packet.is_duplicate?(@expected_seq_number) | |
# return packet | |
# else | |
# puts "Received duplicate packet" | |
# end | |
# else | |
# puts "Corrupted packets" | |
# end | |
end | |
rescue Timeout::Error | |
return nil | |
rescue Timeout::ExitException | |
return nil | |
end | |
end | |
def make_packet data | |
packet = Packet.new | |
packet.data = data | |
packet.source_ip = @source_ip | |
packet.source_port = @source_port | |
packet.dest_ip = @dest_ip | |
packet.dest_port = @dest_port | |
packet.seq_num = @seq_num | |
packet.SYN = false | |
packet.ACK = false | |
packet.TRM = false | |
packet.recalculate_checksum! | |
return packet | |
end | |
def make_syn_packet seq_num | |
packet = make_packet nil | |
packet.SYN = true | |
packet.seq_num = seq_num | |
packet.recalculate_checksum! | |
return packet | |
end | |
def make_trm_packet | |
packet = make_packet nil | |
packet.TRM = true | |
packet.recalculate_checksum! | |
end | |
def make_ack_packet packet_to_ack | |
packet = make_packet nil | |
packet.ACK = true | |
packet.ack_num = packet_to_ack.seq_num + 1 | |
packet.recalculate_checksum! | |
return packet | |
end | |
def send_syn_packet seq_num | |
syn = make_syn_packet(seq_num) | |
packet_string = syn.to_s | |
puts "Sending SYN packet with seq num #{syn.seq_num}" | |
@seq_num = seq_num + syn.to_s.bytesize | |
@udp_socket.send(packet_string, 0, @emu_ip, @emu_port) | |
end | |
def send_ack_packet packet_to_ack | |
ack = make_ack_packet(packet_to_ack) | |
packet_string = ack.to_s | |
puts "Sending ACK packet with ack num #{ack.ack_num}" | |
@udp_socket.send(packet_string, 0, @emu_ip, @emu_port) | |
end | |
def send_syn_ack_packet seq_num, ack_num | |
packet = make_packet nil | |
packet.SYN = 1 | |
packet.ACK = 1 | |
packet.seq_num = seq_num | |
packet.ack_num = ack_num | |
packet.recalculate_checksum! | |
@seq_num = seq_num + packet.to_s.bytesize | |
puts "Sending SYNACK packet with seq num #{seq_num} ack num #{ack_num}" | |
@udp_socket.send(packet.to_s, 0, @emu_ip, @emu_port) | |
end | |
end | |
class Packet | |
HEADER_SIZE = 24 | |
attr_accessor :source_ip, :dest_ip, :source_port, :dest_port, :seq_num, :ack_num, :SYN, :ACK, :TRM, :checksum, :data | |
def initialize | |
@source_ip = nil | |
@source_port = nil | |
@dest_ip = nil | |
@dest_port = nil | |
@seq_num = 0 | |
@ack_num = 0 | |
@SYN = false | |
@ACK = false | |
@TRM = false | |
@checksum = nil | |
@data = nil | |
end | |
def to_a | |
flags = 0 | |
flags |= @SYN.to_i << 2 | |
flags |= @ACK.to_i << 1 | |
flags |= @TRM.to_i << 0 | |
[@source_ip.split('.').map{|e| e.to_i}, @dest_ip.split('.').map{|e| e.to_i}, @source_port.to_i, @dest_port.to_i, @seq_num, @ack_num, flags, @checksum, @data].flatten | |
end | |
def to_s | |
to_a.pack('CCCCCCCCSSLLSSa*') | |
end | |
def self.from_string packet_string | |
pack = Packet.new | |
packet_array = packet_string.unpack('CCCCCCCCSSLLSSa*') | |
pack.source_ip = packet_array[0..3].join('.') | |
pack.dest_ip = packet_array[4..7].join('.') | |
pack.source_port = packet_array[8] | |
pack.dest_port = packet_array[9] | |
pack.seq_num = packet_array[10] | |
pack.ack_num = packet_array[11] | |
flags = packet_array[12] | |
pack.SYN = flags & 100 | |
pack.ACK = flags & 10 | |
pack.TRM = flags & 1 | |
pack.checksum = packet_array[13] | |
pack.data = packet_array[14] | |
return pack | |
end | |
def recalculate_checksum! | |
@checksum = checksum(self) | |
end | |
# needs to return a 16 bit number | |
def checksum packet | |
return 1 | |
end | |
def corrupted? | |
return false | |
end | |
def is_duplicate? num | |
return false | |
end | |
end | |
class TrueClass | |
def to_i | |
1 | |
end | |
end | |
class FalseClass | |
def to_i | |
0 | |
end | |
end | |
class Integer | |
def to_b | |
!self.zero? | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment