This page is READ-ONLY. It is generated from the old site.
All timestamps are relative to 2013 (when this page is generated).
If you are looking for TeX support, please go to VietTUG.org

Perl: pack and unpack (example)

Amazing :D
Added by ruby 8 months ago  »  Votes: 2/2

{{{allow ruby, icy}}}

Original code by Timkay

1 $addr = pack(CnC, 127, $<, 1);
2 print "solo: bind ", join(".", unpack(C4, $addr)), ":$port\n" if $verbose;
3 $^F = 10;    # unset close-on-exec
4 socket(SOLO, PF_INET, SOCK_STREAM, getprotobyname('tcp')) or die "socket: $!";
5 bind(SOLO, sockaddr_in($port, $addr)) or $silent? exit: die "solo($port): $!\n";

Pack specifications

  1. C: An unsigned char (octet) value
  2. n: An unsigned short (16-bit) in "network" (big-endian) order
  3. N: An unsigned long (32-bit) in "network" (big-endian) order

We will take a deep lock how the code works

  1. Line 1: $add = pack(CnC, 127, $
    1. Here $ is the real user id of the process. Let's take $. The binary forms of these three values are
    2. 127 in binary form = 1111111 (aka [127].pack("C").unpack("B*"). This is also equivalent to 127.to_s(2) in Ruby.
    3. 217000: This is a big number. The binary form is 110100111110101000 (this is 217000.to_s(2) or [217000].pack("N").unpack("B*"). As 217000 is 32 bit number, we need to use N. In the code, the author uses an n for packing. This means that he will get only last 16 bits of the binary form of the long number, that's [217000].pack("N").unpack("B*") or the number 20392 (or 0100111110101000 in binary form).
    4. 1: it's simple.
    5. In short, the code means: get 8-bits from the number 127, get 16-bits from the real user id of the process, and get 8-bits from the number 1. In total we have 32-bits which is enough to create an IP-v4 address.
  2. Line 2:: to see the address in real form, we need to unpack it. As each number in an IP-v4 address is an unsigned char number, the author uses unpack(C4, $addr). The equivalent Ruby code is [127,217000,1].pack("CnC").unpack("C4"), and this yields [127, 79, 168, 1] aka the IP-v4 address 127.79.168.1.

Comments

Added by ruby 8 months ago

So the author's code doesn't work as he means

Port 3801 in the example is an arbitrary TCP port number that isn't used elsewhere. (solo works by binding to 127.x.y.126:port. If the chosen port is not free, then a previous instance must still be running, and the job is aborted.) Make sure to use a different port number for each job, or they will prevent each other from running. If you aren't running as root, the port number should be above 1023. The maximum allowed port number is 65535.

The loopback IP address 127.x.y.126 is used, where xy is the uid. This way, different users will never use the same ports even if they use the same port numbers.