class QuartzTorrent::PeerWireMessageSerializer

Public Class Methods

new() click to toggle source
# File lib/quartz_torrent/peermsgserialization.rb, line 12
def initialize
  # extendedMessageIdToClass is the mapping of extended message ids that the peer has sent to extensions.
  @extendedMessageIdToClass = [ExtendedHandshake]
  @logger = LogManager.getLogger("peermsg_serializer")
end

Public Instance Methods

serializeTo(msg, io) click to toggle source
# File lib/quartz_torrent/peermsgserialization.rb, line 41
def serializeTo(msg, io)
  if msg.is_a?(Extended)
    # Set the extended message id
    extendedMsgId = @extendedMessageIdToClass.index msg.class
    raise "Unsupported extended peer message #{msg.class}" if ! extendedMsgId
    msg.extendedMessageId = extendedMsgId
  end
  msg.serializeTo(io)
end
unserializeFrom(io) click to toggle source
# File lib/quartz_torrent/peermsgserialization.rb, line 18
def unserializeFrom(io)
  packedLength = io.read(4)
  raise EOFError.new if packedLength.length == 0

  length = packedLength.unpack("N")[0]
  @logger.debug "unserializeFrom: read that length of message is #{length}"
  raise "Received peer message with length #{length}. All messages must have length >= 0" if length < 0
  return KeepAlive.new if length == 0
  
  id = io.read(1).unpack("C")[0]
  @logger.debug "unserializeFrom: read message id #{id}"
  payload = io.read(length-1)

  #raise "Unsupported peer message id #{id}" if id >= self.classForMessage.length
  clazz = classForMessage(id, payload)
  raise "Unsupported peer message id #{id}" if ! clazz

  result = clazz.new
  result.unserialize(payload)
  updateExtendedMessageIdsFromHandshake(result)
  result
end

Private Instance Methods

classForMessage(id, payload) click to toggle source

Determine the class associated with the message type passed.

# File lib/quartz_torrent/peermsgserialization.rb, line 53
def classForMessage(id, payload)
  if @@classForMessage.nil?
    @@classForMessage = [Choke, Unchoke, Interested, Uninterested, Have, BitfieldMessage, Request, Piece, Cancel]
    @@classForMessage[20] = Extended
  end

  if @@classForExtendedMessage.nil?
    @@classForExtendedMessage = []
    @@classForExtendedMessage[Extension::MetadataExtensionId] = ExtendedMetaInfo
  end
  
  result = @@classForMessage[id]
  
  if result == Extended && payload
    # Extended messages have further subtypes.
    extendedMsgId = payload.unpack("C")[0]
    if extendedMsgId == 0
      result = ExtendedHandshake
    else
      # In this case the extended message number is the one we told our peers to use, not the one the peer told us.
      result = @@classForExtendedMessage[extendedMsgId]
      raise "Unsupported extended peer message id '#{extendedMsgId}'" if ! result 
    end

  end

  result
end
updateExtendedMessageIdsFromHandshake(msg) click to toggle source
# File lib/quartz_torrent/peermsgserialization.rb, line 82
def updateExtendedMessageIdsFromHandshake(msg)
  if msg.is_a?(ExtendedHandshake)
    if msg.dict && msg.dict["m"]
      msg.dict["m"].each do |extName, extId|
        # Update the list here.
        clazz = Extension.peerMsgClassForExtensionName(extName)
        if clazz  
          @logger.debug "Peer supports extension #{extName} using id '#{extId}'."
          @extendedMessageIdToClass[extId] = clazz
        else
          @logger.debug "Peer supports extension #{extName} using id '#{extId}', but I don't know what class to use for that extension."
        end
      end
    else
      @logger.warn "Peer sent extended handshake without the 'm' key."
    end
  end
end