Search code examples
rubynetwork-programmingserver-side

Understanding bytes unpack


I found such code in: https://github.com/mojombo/proxymachine/

proxy do |data|
  return  if data.size < 9
  v, c, port, o1, o2, o3, o4, user = data.unpack("CCnC4a*")
  return { :close => "\0\x5b\0\0\0\0\0\0" }  if v != 4 or c != 1
  return  if ! idx = user.index("\0")
  { :remote => "#{[o1,o2,o3,o4]*'.'}:#{port}",
    :reply => "\0\x5a\0\0\0\0\0\0",
    :data => data[idx+9..-1] }
end

What does this code do? Especially these lines:

data.unpack("CCnC4a*")

return { :close => "\0\x5b\0\0\0\0\0\0" } if v != 4 or c != 1

:reply => "\0\x5a\0\0\0\0\0\0", :data => data[idx+9..-1] }

I am not asking for ruby idioms, but for the functional side.


Solution

  • Assuming data is a String, the unpack method is defined in String#unpack.

    v, c, port, o1, o2, o3, o4, user = data.unpack("CCnC4a*")
    

    This converts a String (throug reading the bytes, not interpreting the string as a text) into an array following these rules:

    • C: read 8-bit as an unsigned char
    • C: read 8-bit as an unsigned char
    • n: read 16-bit unsigned integer (in big-endian format)
    • C4: read 8-bit as an unsigned char (4 times)
    • a*: read all the remaining bytes as an arbitrary string

    So we get an array containing 8 entries (7 integers, one string). Each of those entries in the array is assigned to the variables v, c, port, o1, o2, o3, o4, user.

    return { :close => "\0\x5b\0\0\0\0\0\0" }  if v != 4 or c != 1
    

    When v is not 4 and c is not 1, return the hash { :close => "\0\x5b\0\0\0\0\0\0" }.

    A method returns the result of its last statement. The last statement of your method is

    { :remote => "#{[o1,o2,o3,o4]*'.'}:#{port}",
      :reply => "\0\x5a\0\0\0\0\0\0",
      :data => data[idx+9..-1] }
    

    It is a hash containing three keys (:remote, :reply, :data). In an earlier statement we assigned idx so that it contains the position of the first null-byte ("\0") in the data string.

    data[idx+9..-1] returns the part of the data string beginning at 9 bytes after the first null-byte until the end of the string.