Project 1 grades.


R. Clayton (rclayton@clayton.cs.monmouth.edu)
(no date)


Project 1's been graded; apologies for the delay. On the whole, the results
were disgusting. The most common error was not sending messages in the proper
format. There were two main causes of this problem, the first a bit tricky and
the other not so tricky. The tricky problem arose from a message structure of
the form

  struct turn_msg {
    char type;
    char cnt;
    int piles[max];
    };

This struct has an alignment problem; the compiler lays this out in storage as

      1 2 3 4 5 6 7 8
   +------+------+------+------+------+------+------+------+. . .
     type cnt pad pad -------- piles[0] ---------

Integers must be aligned on addresses congruent to zero modulo 4; if the
structure starts out on such an address (and it's required to by the standard),
then the compiler has to insert to pad bytes after cnt to make sure piles[0]
has the proper alignment. If you send this message as it is, you'll be sending
two extra bytes between cnt and the first number.

The second source of the problem was less tricky. Many people sent messages
using something like

  send(s, &turnmsg, sizeof(turn_msg));

Ignoring the padding problem for a moment, the problem with this code is that
it sends too many bytes. A message is supposed to contain only data bytes, but
the previous send() always sends the same number of bytes, independent of
whether they contain data or not. What is supposed to be sent is something to
the effect of

  send(s, &turnmsg, 2);
  send(s, turnmsg.piles, turnmsg.cnt*sizeof(int));

The insidious thing about this error is that if you make it on both sides, you
can't tell there's a problem. It's only when somebody else who didn't make the
error, or made a different error, tries to connect to one of your sides that
the problem appears.

There were a few other, smaller problems along these same lines, including the
assumption that max < 255.

Another problem that many people had was forgetting that tcp is a stream
protocol, and that a call such as

  e = read(s, &turnmsg, sizeof(turnmsg))

may legitimately read a partial message (that is, 0 < e < sizeof(turnmsg)).
This is right out of Snader, and some people dealt with it properly (one group
defined the proper read routine then never bothered to use it), but an
unfortunately large number of people didn't.

Similarly, some people forgot about differing host byte-orders and the need to
translate transmitted data to a canonical network-byte order. This is another
tough one to catch, particularly if you don't have two different machines
readily at hand, but it's also easy to avoid in the first place.

There were many other problems, but I chose to stick with, and test for, the
three described above.



This archive was generated by hypermail 2.0b3 on Sun May 06 2001 - 20:30:05 EDT