Subject: Clarifications regarding assn 3 (This message is being sent to all CPSC 360 students) In msg.012, in trying to correct the programs of a number of people who were sending a constant number of bytes in the udping program regardless of what the value of the -s parameter was, I said: > Any sendto() or write() call that uses any sizeof() as > a length parameter is fatally flawed!! That statement was ABSOLUTELY correct as it applied to the udping program but should NOT be taken as a hard and fast rule for all time. But following paragraph of this message SHOULD BE CONSIDERED SO. The third parameter passed to the write() or sendto() function must ALWAYS be the ACTUAL NUMBER OF BYTES you want to travel down the wire to the other end. Therefore: write( , , MAX_PACKET_SIZE); is a fatally flawed way to write an RPS header (control packet of 12 bytes) but write( , , sizeof(rps_hdr_t)); is OK (if and ONLY if all you want to send is a header). ----------------- I have already received two or three requests for debugging help that indicate that my debug lecture was misunderstood, ignored, rejected, or some combination thereof. Since receiving them, I have come to believe that I have not yet been successful in conveying the level of attention to detail that is required. So I'll try again: (0) until you THINK you understand what some code is supposed to be doing DON"T WASTE TIME trying to write it. (your understanding and the code may turn out to be wrong -- thats OK) (1) Until you understand how to "test" some code (figure out in your own head a strategy for determining whether it is doing what you want it to do or not) DON"T WASTE YOUR TIME trying to write it. (2) If YOU don't understand what your existing dprintf()s are telling DON"T WRITE EVEN ONE MORE LINE until you do! (3) If your dprintfs() are producing ill formatted stuff with missing values that NOBODY can understand, DON"T dupe yourself into thinking "I'll clean up this debugging mess after its all working".. What sense does that make?? (4) Your debug code CAN BE BROKEN and producing values that make no sense thus causing you to have to "fix" stuff when the real code was OK along :-( (Think Lucas electrics and Smith's instruments) The proper response is NOT TO ASSUME dprintf() is broken and thus ignore the messages. The solution is to RESOLVE THE INCONSISTENCY of expectation and observed result. -------------------------- Header building A student noted that I had mentioned a useful routine called rps_make_header() but not described how to write it. Here is a hint: The header is defined as a structure. A structure consist of elements and one the elements is "flags". The "flags" element should be set to the value of the third parameter --- (example: RPS_CONN_PEND), For now the seq, ack, and win parameters should ALL be 0. The "len" element should not be modified. The magic and sig parameters must be set appropriately. When I started messing with headers I built in this order (1) a test driver that called them both. (2) rps_make_header() and stepped through it with gdb and then (3) rps_dump_header When done with that exercise, I moved those routines to trust-but-verify status, used BOTH in rps_connect() and only after VERIFYING that the results STILL looked fine in rps_connect() did I try to send stuff. ------------------------------------ Incremental development "But Dr. Westall its easy for you to test incementally because you know gdb --- what about us who are unWILLING to learn (I REFUSE to believe that ANY of you are unable to learn how to use gdb.. but you have a right to be unwilling)" Incremental testing even without gdb is straightforward! gdb is of little use when we get to the real system anyway. Here is my personal code for rps_connect() Try 1: int rps_connect( rps_sock_t *rpsock, char *name, /* host name or NULL */ int port) /* local port */ { struct hostent *id = 0; int i; int rc; rps_hdr_t hdr; double delay = 1.0; dprintf("rps_connect: structure at %p \n", rpsock); dprintf("rps_connect: host %s \n", name); dprintf("rps_connect: port %d \n", port); exit(0); } Compile execute read debug log. If it works: Try 2: int rps_connect( rps_sock_t *rpsock, char *name, /* host name or NULL */ int port) /* local port */ { struct hostent *id = 0; int i; int rc; rps_hdr_t hdr; double delay = 1.0; dprintf("rps_connect: structure at %p \n", rpsock); dprintf("rps_connect: host %s \n", name); dprintf("rps_connect: port %d \n", port); /* Connect the underlying UDP socket to the remote address */ if (name == 0) { fprintf(stderr, "Remote host name not supplied \n"); return(-1); } /* Connect underlying UDP socket to remote address */ make_sockaddr(&rpsock->local, id, port); connect_socket(rpsock->sock, &rpsock->local); exit(0); } The make_sockaddr() and connect_socket() functions should say what they are doing. If it still looks like it works.. Try 3: /**/ /* Connect an rps_sock to a remote host/port */ /* Unlike UDP connect this DOES initiate the rps */ /* connection protocol */ int rps_connect( rps_sock_t *rpsock, char *name, /* host name or NULL */ int port) /* local port */ { struct hostent *id = 0; int i; int rc; rps_hdr_t hdr; double delay = 1.0; dprintf("rps_connect: structure at %p \n", rpsock); dprintf("rps_connect: host %s \n", name); dprintf("rps_connect: port %d \n", port); /* Connect the underlying UDP socket to the remote address */ if (name == 0) { fprintf(stderr, "Remote host name not supplied \n"); return(-1); } /* Connect underlying UDP socket to remote address */ make_sockaddr(&rpsock->local, id, port); connect_socket(rpsock->sock, &rpsock->local); /* Construct and rps_hdr_t containing the connection */ /* request */ memset(&hdr, 0, sizeof(hdr)); rps_make_header(rpsock, &hdr, RPH_CONNECT); rps_dump_header(rpsock, "rps_connect", &hdr); /* Set the socket state to RPS_CONN_PEND */ rpsock->state = RPS_CONN_PEND; dprintf("rps_connect: new state %d \n", rpsock->state); exit(0); } Actually getting a bit greedy here but how hard can it be to set rpsock->state... If it still looks like it works. Try 4: /**/ /* Connect an rps_sock to a remote host/port */ /* Unlike UDP connect this DOES initiate the rps */ /* connection protocol */ int rps_connect( rps_sock_t *rpsock, char *name, /* host name or NULL */ int port) /* local port */ { struct hostent *id = 0; int i; int rc; rps_hdr_t hdr; double delay = 1.0; dprintf("rps_connect: structure at %p \n", rpsock); dprintf("rps_connect: host %s \n", name); dprintf("rps_connect: port %d \n", port); /* Connect the underlying UDP socket to the remote address */ if (name == 0) { fprintf(stderr, "Remote host name not supplied \n"); return(-1); } /* Connect underlying UDP socket to remote address */ make_sockaddr(&rpsock->local, id, port); connect_socket(rpsock->sock, &rpsock->local); /* Construct and rps_hdr_t containing the connection */ /* request */ memset(&hdr, 0, sizeof(hdr)); rps_make_header(rpsock, &hdr, RPH_CONNECT); rps_dump_header(rpsock, "rps_connect", &hdr); /* Set the socket state to RPS_CONN_PEND */ rpsock->state = RPS_CONN_PEND; dprintf("rps_connect: new state %d \n", rpsock->state); exit(0); for (i = 0; i < MAX_CONNECT_ATTEMPTS; i++) { double tod; struct timespec ts; rc = write(rpsock->sock, &hdr, sizeof(hdr)); dprintf("rps_connect: wrote %d \n", rc); if (rc < 0) perror("rps_connect"); exit(1); ---- timeout stuff left as an exercise --- } } ---------------------------------------------