Hacks to make behaviour observationally equivalent with oxenstored

Here is the sdiff of two transcripts from xstest [1] showing oxenstored on the left and this version on the right.

  0 S:  0(0) READ "\000".                                         0 S:  0(0) READ "\000".
  0 R:  0(0) ERROR "EINVAL\000".                                  0 R:  0(0) ERROR "EINVAL\000".
  1 S:  0(1) WRITE "\000".                                        1 S:  0(1) WRITE "\000".
  1 R:  0(1) ERROR "EINVAL\000".                                  1 R:  0(1) ERROR "EINVAL\000".
  2 S:  0(2) GET_DOMAIN_PATH "\000".                              2 S:  0(2) GET_DOMAIN_PATH "\000".
  2 R:  0(2) GET_DOMAIN_PATH "/local/domain/0\000".               2 R:  0(2) GET_DOMAIN_PATH "/local/domain/0\000".
  3 S:  0(3) DIRECTORY "\000".                                    3 S:  0(3) DIRECTORY "\000".
  3 R:  0(3) ERROR "EINVAL\000".                                  3 R:  0(3) ERROR "EINVAL\000".
  4 S:  0(4) MKDIR "\000".                                        4 S:  0(4) MKDIR "\000".
  4 R:  0(4) ERROR "EINVAL\000".                                  4 R:  0(4) ERROR "EINVAL\000".
  5 S:  0(5) GET_PERMS "\000".                                    5 S:  0(5) GET_PERMS "\000".
  5 R:  0(5) ERROR "EINVAL\000".                                  5 R:  0(5) ERROR "EINVAL\000".
  6 S:  0(6) SET_PERMS "\000".                                    6 S:  0(6) SET_PERMS "\000".
  6 R:  0(6) ERROR "EINVAL\000".                                  6 R:  0(6) ERROR "EINVAL\000".
  7 S:  0(7) WRITE "/test\000xxx\000yyy\000\000zzz".              7 S:  0(7) WRITE "/test\000xxx\000yyy\000\000zzz".
  7 R:  0(7) WRITE "OK\000".                                      7 R:  0(7) WRITE "OK\000".
  8 S:  0(8) READ "/test".                                        8 S:  0(8) READ "/test".
  8 R:  0(8) ERROR "EINVAL\000".                              |   8 R:  0(8) READ "xxx\000yyy\000\000zzz".
  9 S:  0(9) READ "/test\000".                                    9 S:  0(9) READ "/test\000".
  9 R:  0(9) READ "xxx\000yyy\000\000zzz".                        9 R:  0(9) READ "xxx\000yyy\000\000zzz".
  a S:  0(10) READ "/test\000some\000otherargs".                  a S:  0(10) READ "/test\000some\000otherargs".
  a R:  0(10) ERROR "EINVAL\000".                                 a R:  0(10) ERROR "EINVAL\000".
  b S:  0(11) DIRECTORY "/test\000spurious\000abc".               b S:  0(11) DIRECTORY "/test\000spurious\000abc".
  b R:  0(11) ERROR "EINVAL\000".                                 b R:  0(11) ERROR "EINVAL\000".
  c S:  0(12) DIRECTORY "/test\000spurious".                      c S:  0(12) DIRECTORY "/test\000spurious".
  c R:  0(12) ERROR "EINVAL\000".                                 c R:  0(12) ERROR "EINVAL\000".
  d S:  0(13) GET_PERMS "/test\000someotherargs".                 d S:  0(13) GET_PERMS "/test\000someotherargs".
  d R:  0(13) ERROR "EINVAL\000".                                 d R:  0(13) ERROR "EINVAL\000".
  e S:  0(14) GET_PERMS "/test\000someotherargs\000others".       e S:  0(14) GET_PERMS "/test\000someotherargs\000others".
  e R:  0(14) ERROR "EINVAL\000".                                 e R:  0(14) ERROR "EINVAL\000".
  f S:  0(15) WRITE "/test\000".                                  f S:  0(15) WRITE "/test\000".
  f R:  0(15) WRITE "OK\000".                                     f R:  0(15) WRITE "OK\000".
 10 S:  0(16) WRITE "/test\000abc".                              10 S:  0(16) WRITE "/test\000abc".
 10 R:  0(16) WRITE "OK\000".                                    10 R:  0(16) WRITE "OK\000".
 11 S:  0(17) READ "/test".                                      11 S:  0(17) READ "/test".
 11 R:  0(17) ERROR "EINVAL\000".                             |  11 R:  0(17) READ "abc".
 12 S:  0(18) READ "/test\000".                                  12 S:  0(18) READ "/test\000".
 12 R:  0(18) READ "abc".                                        12 R:  0(18) READ "abc".
 13 S:  0(19) READ "/test\000\000".                              13 S:  0(19) READ "/test\000\000".
 13 R:  0(19) ERROR "EINVAL\000".                                13 R:  0(19) ERROR "EINVAL\000".
 14 S:  0(20) WRITE "/test".                                     14 S:  0(20) WRITE "/test".
 14 R:  0(20) ERROR "EINVAL\000".                             |  14 R:  0(20) WRITE "OK\000".
 15 S:  0(21) READ "/test".                                      15 S:  0(21) READ "/test".
 15 R:  0(21) ERROR "EINVAL\000".                             |  15 R:  0(21) READ "".
 16 S:  0(22) READ "/test\000".                                  16 S:  0(22) READ "/test\000".
 16 R:  0(22) READ "abc".                                     |  16 R:  0(22) READ "".
 17 S:  0(23) READ "/test\000\000".                              17 S:  0(23) READ "/test\000\000".
 17 R:  0(23) ERROR "EINVAL\000".                                17 R:  0(23) ERROR "EINVAL\000".
 18 S:  0(24) WRITE "\000/".                                     18 S:  0(24) WRITE "\000/".
 18 R:  0(24) ERROR "EINVAL\000".                                18 R:  0(24) ERROR "EINVAL\000".
 19 S:  0(25) DIRECTORY "/test".                                 19 S:  0(25) DIRECTORY "/test".
 19 R:  0(25) ERROR "EINVAL\000".                             |  19 R:  0(25) DIRECTORY "abc\000def\000xyz\000".
 1a S:  0(26) DIRECTORY "/test\000".                             1a S:  0(26) DIRECTORY "/test\000".
 1a R:  0(26) DIRECTORY "".                                   |  1a R:  0(26) DIRECTORY "abc\000def\000xyz\000".
 1b S:  0(27) DIRECTORY "/test\000\000".                         1b S:  0(27) DIRECTORY "/test\000\000".
 1b R:  0(27) ERROR "EINVAL\000".                                1b R:  0(27) ERROR "EINVAL\000".
 1c S:  0(28) RM "/test".                                        1c S:  0(28) RM "/test".
 1c R:  0(28) ERROR "EINVAL\000".                             |  1c R:  0(28) RM "OK\000".
 1d S:  0(29) DIRECTORY "/test".                                 1d S:  0(29) DIRECTORY "/test".
 1d R:  0(29) ERROR "EINVAL\000".                             |  1d R:  0(29) ERROR "ENOENT\000".
 1e S:  0(30) DIRECTORY "/test\000".                             1e S:  0(30) DIRECTORY "/test\000".
 1e R:  0(30) DIRECTORY "".                                   |  1e R:  0(30) ERROR "ENOENT\000".
 1f S:  0(31) DIRECTORY "/test\000\000".                         1f S:  0(31) DIRECTORY "/test\000\000".
 1f R:  0(31) ERROR "EINVAL\000".                                1f R:  0(31) ERROR "EINVAL\000".
 20 S:  0(32) WRITE "/test/abc\000x1".                           20 S:  0(32) WRITE "/test/abc\000x1".
 20 R:  0(32) WRITE "OK\000".                                    20 R:  0(32) WRITE "OK\000".
 21 S:  0(33) WRITE "/test/def\000x2".                           21 S:  0(33) WRITE "/test/def\000x2".
 21 R:  0(33) WRITE "OK\000".                                    21 R:  0(33) WRITE "OK\000".
 22 S:  0(34) WRITE "/test/xyz\000x3".                           22 S:  0(34) WRITE "/test/xyz\000x3".
 22 R:  0(34) WRITE "OK\000".                                    22 R:  0(34) WRITE "OK\000".
 23 S:  0(35) WRITE "/test/xyz\000x4".                           23 S:  0(35) WRITE "/test/xyz\000x4".
 23 R:  0(35) WRITE "OK\000".                                    23 R:  0(35) WRITE "OK\000".
 24 S:  0(36) DIRECTORY "/test".                                 24 S:  0(36) DIRECTORY "/test".
 24 R:  0(36) ERROR "EINVAL\000".                             |  24 R:  0(36) DIRECTORY "abc\000def\000xyz\000".
 25 S:  0(37) DIRECTORY "/test\000".                             25 S:  0(37) DIRECTORY "/test\000".
 25 R:  0(37) DIRECTORY "abc\000def\000xyz\000".                 25 R:  0(37) DIRECTORY "abc\000def\000xyz\000".
 26 S:  0(38) DIRECTORY "/test\000spurious\000".                 26 S:  0(38) DIRECTORY "/test\000spurious\000".
 26 R:  0(38) ERROR "EINVAL\000".                                26 R:  0(38) ERROR "EINVAL\000".
 27 S:  0(39) GET_PERMS "/test".                                 27 S:  0(39) GET_PERMS "/test".
 27 R:  0(39) ERROR "EINVAL\000".                             |  27 R:  0(39) GET_PERMS "n0\000".
 28 S:  0(40) GET_PERMS "/test\000".                             28 S:  0(40) GET_PERMS "/test\000".
 28 R:  0(40) GET_PERMS "n0\000".                                28 R:  0(40) GET_PERMS "n0\000".
 29 S:  0(41) GET_PERMS "/test\000spurious\000".                 29 S:  0(41) GET_PERMS "/test\000spurious\000".
 29 R:  0(41) ERROR "EINVAL\000".                                29 R:  0(41) ERROR "EINVAL\000".
 2a S:  0(42) SET_PERMS "/test".                                 2a S:  0(42) SET_PERMS "/test".
 2a R:  0(42) ERROR "EINVAL\000".                                2a R:  0(42) ERROR "EINVAL\000".
 2b S:  0(43) GET_PERMS "/test\000".                             2b S:  0(43) GET_PERMS "/test\000".
 2b R:  0(43) GET_PERMS "n0\000".                                2b R:  0(43) GET_PERMS "n0\000".
 2c S:  0(44) SET_PERMS "/test\000".                             2c S:  0(44) SET_PERMS "/test\000".
 2c R:  0(44) ERROR "EINVAL\000".                                2c R:  0(44) ERROR "EINVAL\000".
 2d S:  0(45) GET_PERMS "/test\000".                             2d S:  0(45) GET_PERMS "/test\000".
 2d R:  0(45) GET_PERMS "n0\000".                                2d R:  0(45) GET_PERMS "n0\000".
 2e S:  0(46) SET_PERMS "/test\000\000".                         2e S:  0(46) SET_PERMS "/test\000\000".
 2e R:  0(46) ERROR "EINVAL\000".                                2e R:  0(46) ERROR "EINVAL\000".
 2f S:  0(47) GET_PERMS "/test\000".                             2f S:  0(47) GET_PERMS "/test\000".
 2f R:  0(47) GET_PERMS "n0\000".                                2f R:  0(47) GET_PERMS "n0\000".
 30 S:  0(48) SET_PERMS "/test\000n0\000".                       30 S:  0(48) SET_PERMS "/test\000n0\000".
 30 R:  0(48) SET_PERMS "OK\000".                                30 R:  0(48) SET_PERMS "OK\000".
 31 S:  0(49) GET_PERMS "/test\000".                             31 S:  0(49) GET_PERMS "/test\000".
 31 R:  0(49) GET_PERMS "n0\000".                                31 R:  0(49) GET_PERMS "n0\000".
 32 S:  0(50) SET_PERMS "/test\000n0".                           32 S:  0(50) SET_PERMS "/test\000n0".
 32 R:  0(50) ERROR "EINVAL\000".                             |  32 R:  0(50) SET_PERMS "OK\000".
 33 S:  0(51) GET_PERMS "/test\000".                             33 S:  0(51) GET_PERMS "/test\000".
 33 R:  0(51) GET_PERMS "n0\000".                                33 R:  0(51) GET_PERMS "n0\000".
 34 S:  0(52) SET_PERMS "/test\000n0\000r1".                     34 S:  0(52) SET_PERMS "/test\000n0\000r1".
 34 R:  0(52) SET_PERMS "OK\000".                                34 R:  0(52) SET_PERMS "OK\000".
 35 S:  0(53) GET_PERMS "/test\000".                             35 S:  0(53) GET_PERMS "/test\000".
 35 R:  0(53) GET_PERMS "n0\000".                             |  35 R:  0(53) GET_PERMS "n0\000r1\000".
 36 S:  0(54) SET_PERMS "/test\000n0\000r1\000".                 36 S:  0(54) SET_PERMS "/test\000n0\000r1\000".
 36 R:  0(54) SET_PERMS "OK\000".                                36 R:  0(54) SET_PERMS "OK\000".
 37 S:  0(55) GET_PERMS "/test\000".                             37 S:  0(55) GET_PERMS "/test\000".
 37 R:  0(55) GET_PERMS "n0\000r1\000".                          37 R:  0(55) GET_PERMS "n0\000r1\000".
 38 S:  0(56) SET_PERMS "/test\000n0r2\000spurious".             38 S:  0(56) SET_PERMS "/test\000n0r2\000spurious".
 38 R:  0(56) ERROR "EINVAL\000".                                38 R:  0(56) ERROR "EINVAL\000".
 39 S:  0(57) GET_PERMS "/test\000".                             39 S:  0(57) GET_PERMS "/test\000".
 39 R:  0(57) GET_PERMS "n0\000r1\000".                          39 R:  0(57) GET_PERMS "n0\000r1\000".
 3a S:  0(58) GET_DOMAIN_PATH "3\000".                           3a S:  0(58) GET_DOMAIN_PATH "3\000".
 3a R:  0(58) GET_DOMAIN_PATH "/local/domain/3\000".             3a R:  0(58) GET_DOMAIN_PATH "/local/domain/3\000".
 3b S:  0(59) GET_DOMAIN_PATH "10\000".                          3b S:  0(59) GET_DOMAIN_PATH "10\000".
 3b R:  0(59) GET_DOMAIN_PATH "/local/domain/10\000".            3b R:  0(59) GET_DOMAIN_PATH "/local/domain/10\000".
 3c S:  0(60) GET_DOMAIN_PATH "13 \000".                         3c S:  0(60) GET_DOMAIN_PATH "13 \000".
 3c R:  0(60) GET_DOMAIN_PATH "/local/domain/13\000".            3c R:  0(60) GET_DOMAIN_PATH "/local/domain/13\000".
 3d S:  0(61) GET_DOMAIN_PATH " 17\000".                         3d S:  0(61) GET_DOMAIN_PATH " 17\000".
 3d R:  0(61) GET_DOMAIN_PATH "/local/domain/17\000".            3d R:  0(61) GET_DOMAIN_PATH "/local/domain/17\000".
 3e S:  0(62) GET_DOMAIN_PATH "45\000spurious".                  3e S:  0(62) GET_DOMAIN_PATH "45\000spurious".
 3e R:  0(62) ERROR "EINVAL\000".                                3e R:  0(62) ERROR "EINVAL\000".
 3f S:  0(63) GET_DOMAIN_PATH "45\000really\000".                3f S:  0(63) GET_DOMAIN_PATH "45\000really\000".
 3f R:  0(63) ERROR "EINVAL\000".                                3f R:  0(63) ERROR "EINVAL\000".
 40 S:  0(64) TRANSACTION_START "\000".                          40 S:  0(64) TRANSACTION_START "\000".
 40 R:  0(64) TRANSACTION_START "1\000".                         40 R:  0(64) TRANSACTION_START "1\000".
 41 S:  1(65) TRANSACTION_END "\000".                            41 S:  1(65) TRANSACTION_END "\000".
 41 R:  1(65) ERROR "EINVAL\000".                                41 R:  1(65) ERROR "EINVAL\000".
 42 S:  0(66) TRANSACTION_START "\000".                          42 S:  0(66) TRANSACTION_START "\000".
 42 R:  0(66) TRANSACTION_START "2\000".                         42 R:  0(66) TRANSACTION_START "2\000".
 43 S:  2(67) TRANSACTION_END "2\000".                           43 S:  2(67) TRANSACTION_END "2\000".
 43 R:  2(67) ERROR "EINVAL\000".                                43 R:  2(67) ERROR "EINVAL\000".
 44 S:  0(68) TRANSACTION_START "\000\000".                      44 S:  0(68) TRANSACTION_START "\000\000".
 44 R:  0(68) TRANSACTION_START "3\000".                         44 R:  0(68) TRANSACTION_START "3\000".
 45 S:  3(69) TRANSACTION_END "0\000\000".                       45 S:  3(69) TRANSACTION_END "0\000\000".
 45 R:  3(69) ERROR "EINVAL\000".                                45 R:  3(69) ERROR "EINVAL\000".

The differences are all to do with the behaviour when strings in requests are NUL-terminated or not.

This patch makes the behaviour of this xenstore match oxenstored, but it is a bunch of hacks and is probably not a reasonable solution nor a complete solution, and it has not been tested in anger.

[1] https://github.com/xen-org/xen-api/blob/master/ocaml/xstest/xstest.ml
test: make debug printing optional (use -debug)

Signed-off-by: David Scott <dave.scott@eu.citrix.com>
make test: run the new 'binary' protocol test

Signed-off-by: David Scott <dave.scott@eu.citrix.com>