PROGRAM A FAQ (FREQUENTLY ASKED QUESTIONS) ------------------------------------------ Last Updated: Wed, 625 PM, Feb. 17, 1999 INDEX ----- Q1) I could not connect to xserve. Is it up? Q2) When I tried to read man pages in /home/cec/class/cs533/projects/proj1/man1, I got error messages about not being able to find the file. Can you tell what might be the problem? Q3) My client sent 1 message. The server made a connection and received a message, but it said that I got a 0-byte message. When I tried again, I got a message about "connection refused." What does that mean? Q4) Could you please explain how the probabilities (p1, p2. p3, p4) work? I am just so confused about their uses in this program. So if I set the p1 and p3 equal to 0.5, is is true that the xserve will have 50% dropping the packet. But if it's true, how the xserve response to that. It doesn't make sense to me. Q5) What is the following code fragment suppose to do in the Client Skeleton? if ((he = gethostbyname(...)) == NULL) { if ((host_ip = inet_addr(...)) == 0xffffffff) { ... error ... } } Q6) Why is there an 'xread()' but no 'xwrite()' in lib533.a? Q7) Your Client Skeleton has an argument 'struct sockaddr_in *sn'. It doesn't seem to be used for anything. Q8) What is PF_INET? Q9) My program is running but sometimes it seems to be reeeeeally slow. How can that be? Q10) Could you tell me how to link my source file wiht lib533.a in the directory you gave us. Q11) I just lost all of my files. What can I do to recover them? Q12) Where is the variable "s" in the 'socket()' call in SetupClient() coming from? Where is it declared? How is it passed back to main? Q13) What is the purpose of this assignment? Q14) When I am sending an ACK back to the client, do I need to send a packet header? Q15) Does an ACK packet have to have a zero-length body? Q16) Does our program have to work with packet dropping and packet reordering or can we assume that none of these things will occur? Q17) How do we define an 'ACK'? With a string "ACK", or "ack"? With an an integer 1 for success, -1 for none? Q18) Since Part 2 includes Part 1, can we turn in just one piece of code? Q19) My client seems to get out of sync with xserv. When I omit xserv from the path, everything seems to be ok. When I insert xserv, I can't seem to get past the first and sometimes first packet. Any ideas? Q20) Should the client and server port fields in the packet header (i.e., 'dp' and 'sp') be the same? Q21) When writing a header packet to xserve from the client, write(int fd, char * buff, int n) would expect the packet header to be a character string. My question: what conversion or cast would be appropriate for a variable to type packet_hdr so that I could use write() to correctly pass it to xserve? Q22) What is the packet size used for; i.e., the 200? Is it the size for every packet, that is both header and data, or just data? Q23) What is the meaning of the error flag and loss probability command line arguments. What are their relations to p1, p2, p3 and p4? Q24) I am running into some trouble with the xserv. The client successfully got connected with xserv, that is, the connection protocol completed. But in the data transmission phase, the data length read out by the server was always 0. When I skipped the xserv and transmitted directly between the server and the client, this problem disappeared. Any ideas? Q25) Why does the following code end up setting 'plen' to 4 instead of 10? char *buff; int plen; buff = "0123456789"; plen = sizeof(buff); QUESTIONS/ANSWERS ----------------- Q1) Uuuh, you are a bit early. I'll try to get it up by tomorrow (Tue, 1/26). Q2) When I tried to read man pages in /home/cec/class/cs533/projects/proj1/man1, I got the following error messages (attached). Can you tell what might be the problem? A2) Try (from a cec machine) one of the following: Method 1: man -M ~cs533/projects/proj1/man xread man -M ~cs533/projects/proj1/man conn ... etc ... Method 2: nroff -man ~cs533/projects/proj1/man/man1/xread.1 | less nroff -man ~cs533/projects/proj1/man/man1/conn.1 | less Method 3: # add to .cshrc.mine the following line and 'source .cshrc.mine' setenv MANPATH ~cs533/projects/proj1/man:$MANPATH # then you don't need the long path names man xread man conn or their equivalent. Also, some but not all files have a plain text version. For those files, cd ~cs533/projects/proj1/man/man1 more *.txt Q3) My client sent 1 message. The server made a connection and received a message, but it said that I got a 0-byte message. When I tried again, I got a message about "connection refused." What does that mean? A3) It looks like 2 problems. First, 'xserv' expects the client to send it data in the form: header, body, header, body, .... This is AFTER your client goes through the connection protocol specified in the assignment. If you just send messages without a header (see /include/packet.h), the server will get a 0-byte message. Second, I don't think 'xserv' is running yet. You may have (by chance) connected to a test version of 'xserv'. Yijie will send out email when 'xserv' is running. Q4) Could you please explain how the probabilities (p1, p2. p3, p4) work? I just so confused about their uses in this program. So if I set the p1 and p3 equal to 0.5, is is true that the xserve will have 50% dropping the packet. But if it's true, how the xserve response to that. It doesn't make sense to me. A4) If you set p1=0.2 and p3=0.7, 20% of the packets going from client to server (p1) will be dropped and 70% of the ones going from server to client (p3) will be dropped. This is done without notice and you wouldn't know it unless you counted the packets or put an identifier (e.g., sequence number) on each packet. 'xserv' conceptually expects to see packets in the form ; i.e., send the header, then send the body. Also, packets come in two forms: FLAG_DATA (data) and FLAG_DACK (acknowledgement) (See .../include/packet.h). 'xserv' will drop a packet with the above probabilities. For example, consider p1. It is a Bernoulli process with success probability of p1; i.e., 'xserv' flips a coin with success probability p1 and failure probability 1-p1. If the coin comes up "success", it silently discards the whole packet (header and body); otherwise, it sends (relays) it to your server with probability 1-p1. Q5) What is the following code fragment suppose to do in the Client Skeleton? if ((he = gethostbyname(...)) == NULL) { if ((host_ip = inet_addr(...)) == 0xffffffff) { ... error ... } } A5) Originally, 'gethostbyname()' did not handle dot notation IP addresses. So, gethostbyname("128.252.153.16") would return NULL. Evidently, around 1996, it was enhanced to handle both a host name and an IP address in dot notation; i.e., the following will do what the above code use to do: if ((he = gethostbyname(...)) == NULL) { ... error ... } But if you are running on a system with an older OS (e.g., pre-Solaris), the older semantics may be in effect. Q6) Why is there an 'xread()' but no 'xwrite()' in lib533.a? A6) 'xread()' handles the fact that 'read()' may read less bytes than called for; i.e., 'xread()' will keep reading until it gets all of the bytes that it asks for. This is because of system buffering. 'write()' (and 'send()') will block until all bytes that it is writing are delivered. Q7) Your Client Skeleton has an argument 'struct sockaddr_in *sn'. It doesn't seem to be used for anything. A7) It might be useful in Part 2 for holding the server IP in u_long form, but it is questionable whether it belongs in the call line to SetupClient. Q8) What is PF_INET? A8) It's the same as AF_INET (see /usr/include/sys/socket.h). PF_INET stands for Internet Protocol Family, and AF_INET stands for Internet Address Family. Q9) My program is running but sometimes it seems to be reeeeeally slow. How can that be? A9) It could be a bug in your program. But I also noticed when I came in this morning, the load average on sarlacc.arl was 61 and it was due to 61 'xserv' processes running! 'xserv' gets confused sometimes. [ It would be nice if 'xserv' children were limited to a fixed amount of elapsed time. ] Q10) Could you tell me how to link my source file wiht lib533.a in the directory you gave us. A10) Assuming you are on a cec machine, I would do the following (or its equivalent): ln -s ~cs533/projects/proj1/lib xlib # symbolic link to lib dir gcc -o client client.c xlib/lib533.a -lsocket -lnsl You should check that the above path is correct. Q11) I just lost all of my files. What can I do to recover them? A11) It's probably too late to do anything although CEC does nightly backups. I recommend doing your own backups. I have a 'bkup' script that you can get from the CS533 web page. Read its header and try it out in a test directory before using it. You can use it to "snapshot" files. Q12) Where is the variable "s" in the 'socket()' call in SetupClient() coming from? Where is it declared? How is it passed back to main? A12) The skeleton is a skeleton: everything isn't there. 's' is passed back to the main routine through the return value of SetupClient(). Note also that the return looks like: return ((...) ? s : -1); This is a C if-expression (it does a test and has a value and is semantically different than an if-statement). In most cases, the socket descriptor 's' can be returned directly without the suggested test. Q13) What is the purpose of this assignment? A13) It prepares everyone for the "serious" programming assignments. After you finish this assignment, I will assume that everyone knows all of the details required to do simple connection-oriented socket programming. It also gets everyone familiar with the logistics of of socket programming and the 'xserv' resource (e.g., compiling, man pages). The assignment isn't really that hard intellectually, but there is a wide skill level in the class and there are numerous programming details that would be too painful and boring to go over in a lecture environment. [ Let me repeat: IF THE ASSIGNMENT HAS PUSHED YOU OVER YOUR PAIN THRESHHOLD, DROP THE COURSE. ] Q14) When I am sending an ACK back to the client, do I need to send a packet header? A14) Yes. 'xserv' expects the format header, body, header, body, .... Q15) Does an ACK packet have to have a zero-length body? A15) No. Q16) Does our program have to work with packet dropping and packet reordering or can we assume that none of these things will occur? A16) Your program should work with both packet dropping and reordering. Q17) How do we define an 'ACK'? With a string "ACK", or "ack"? With an an integer 1 for success, -1 for none? A17) Every packet has a header and a body. .../include/packet.h defines the format of a packet header. As stated in A4 above, there are two types of packets (there is a 'flag' field in the header): FLAG_DATA (data) and FLAG_DACK (acknowledgement). The body of an FLAG_DACK packet can be whatever you want. It can even be zero length. It could be a time stamp. It could be your fortune of the day. Whatever is useful. Q18) Since Part 2 includes Part 1, can we turn in just one piece of code? A18) I mentioned early on that there should be two submissions for Program A: Part 1 and Part 2. But Part 2 includes Part 1. So, why bother with Part 1. Let me revise my statement. You should submit the following (in terms of code): 1) Something that represents your best WORKING code, and 2) Something that represents your greatest effort. If #1 includes #2, then you can make one code submission. By working code, I mean something that runs and demonstrates some functionality. Some of you will get into a situation where your current code doesn't work for various reasons. This approach will allow some freedom in giving partial credit. Q19) My client seems to get out of sync with xserv. When I omit xserv from the path, everything seems to be ok. When I insert xserv, I can't seem to get past the first and sometimes first packet. Any ideas? A19) The problem could be anything, but here is a sketch of the 'xserv' protocol: clnt xserv child srvr ---- ----- ----- ---- socket() socket() bind() bind() listen() listen() socket() accept() accept() CONNECT2 XPORT [ Wait ] [ Wait ] connect() -----------> ... ... BANNER ... xfgets() <------------- write() ... HOST SPORT p1 p2 p3 p4 maxd write() --------------> xread() socket() ... connect() ----> ... success msg ... xfgets() <------------- write() ... ... <<< CONNECTION PROTOCOL COMPLETE >>> DATA HEADER write() ----------------------> xread() DATA write() ----------------------> xread() HEADER write() ------> xread() DATA write() ------> xread() ACK HEADER xread() <------ write() ACK xread() <------ write() ACK HEADER xread() <---------------------- write() ACK xread() <---------------------- write() ... etc ... The main things to remember are: 1) There are two phases: 1) xserv connection, 2) packet transmission to the server. 2) The client's incoming bytes are in a stream. The first part of the stream contains the 'xserv' connection bytes. That is followed by the ACK packet bytes which are logically grouped into header-body pairs. 3) There are TCP buffers that implement this stream view. Furthermore, a 'read()' call can return less than you ask for because it will return when it hits a buffer boundary even though there are other buffers that follow. 'xread()' and 'xfgets()' handle this buffer boundary problem. Q20) Should the client and server port fields in the packet header (i.e., 'dp' and 'sp') be the same? A20) Actually, 'xserv' doesn't even look at these fields and your server has no need to look at them. But I suggest you set the client port to 0 and the server port to be whatever you chose for the server. Q21) When writing a header packet to xserve from the client, write(int fd, char * buff, int n) would expect the packet header to be a character string. My question: what conversion or cast would be appropriate for a variable to type packet_hdr so that I could use write() to correctly pass it to xserve? A21) "char *" only means a pointer to a byte. There is no implication that in fact there is a string there (i.e., null character terminated array of bytes). So, 'buff' is a pointer to some memory area that hopefully has something useful in the next 'n' byte locations. "char *" could be used here in one of two ways depending on how you defined 'buff'. Approach 1 (static space allocation): struct packet_hdr buff; /* statically allocated hdr buffer */ int hdrsz; ... hdrsz = sizeof(struct packet_hdr); buff.dst.s_addr = serverIp; /* dest IP address */ ... buff.flag = FLAG_DATA; /* flags */ buff.dlen = htons(data_length); write (fd, (char *) buff, hdrsz); ... Approach 2 (dynamic space allocation): struct packet_hdr *buff; /* pointer to hdr buffer */ int hdrsz; ... hdrsz = sizeof(struct packet_hdr); buff = (struct packet_hdr *) calloc (1, hdrsz); if (buff == ...) ... error ... buff->dst.s_addr = serverIp; /* dest IP address */ ... buff->flag = FLAG_DATA; /* flags */ buff->dlen = htons(data_length); write (fd, (char *) buff, hdrsz); ... Q22) What is the packet size used for; i.e., the 200? Is it the size for every packet, that is both header and data, or just data? A22) The size of the data (body) portion except perhaps the last packet; i.e., the value of 'dlen' in the header. The last packet can be less than this when the file size is not an integral multiple of the packet size. The header is always 20 bytes or whatever the size of 'struct packet_hdr' is. Q23) What is the meaning of the error flag and loss probability command line arguments. What are their relations to p1, p2, p3 and p4? A23) The loss probabilities are p1, .. , p4. The error flag can be ignored or if trying to keep to the letter of the law, indicates whether the p values are all 0 or not. If you didn't use an error flag, you could just enter all 0's for the p values. Q24) I am running into some trouble with the xserv. The client successfully got connected with xserv, that is, the connection protocol completed. But in the data transmission phase, the data length read out by the server was always 0. When I skipped the xserv and transmitted directly between the server and the client, this problem disappeared. Any ideas? A24) This implies that the problem is in the Setup phase. A typical (but not necessarily your) problem is that you have sent a connect string that is not exactly correct in format. This connect string needs a "\n" at the end. I assume that you read xserv's reply to this connect string. You can see if in fact this is the problem, by sending a constant string that you know works. For example (you have to change this to your needs): char *cmsg = "hilton.cec 1800 0.0 0.0 0.0 0.0 1\n"; ... if (write(sockfd, cmsg, strlen(cmsg)) == -1) { ... error ... } ... if ((nbytes=xfgets(sockfd, creply, MAXDATASIZE)) == -1) { ... } If this works, then your problem is in your string that you think you are sending. A typical problem is people forget to send the "\n" or they send more than the string. At the receiving end, 'xserv' is executing 'xfgets()' looking for the newline. It assumes that the next 20 bytes (i.e., sizeof(struct packet_hdr)) contains the packet header of the first packet. Q25) Why does the following code end up setting 'plen' to 4 instead of 10? char *buff; int plen; buff = "0123456789"; plen = sizeof(buff); A25) Note the following: char *buff; char mybuff[10]; int plen, myplen; buff = "0123456789"; plen = sizeof(buff); // plen == 4 myplen = sizeof(mybuff); // myplen == 10 That is, buff is a pointer and therefore 4 bytes long. Never mind that it points to a 10-character string. You want 'strlen(buff)' in that case (maybe). 'mybuff' is a 10-byte object that is an array of 10 characters. 'sizeof' is a COMPILE TIME operator, not a RUN-TIME operator; i.e., it determines how big the object is by looking at the declaration, not how you use it. There are 2 versions of 'sizeof': 'sizeof(Type)' and 'sizeof ObjectExpression'. A type is like 'int', 'char', etc. Note that 'ObjectExpression' can be a parenthesized expression making the second form appear to be like the first form. Q26) My server doesn't seem to be getting any packets after the client establishes a connection to it (via 'xserv'). What could be wrong? A26) It could be all sorts of things. Certainly, any number of misunderstandings about C/C++ semantics could cause things to go terribly silent. But I have noticed that the most frequent causes are the following (not in order of occurrence): 1) Client Sends Wrong Connect Message The client sends a message like "hilton.cec 5000 0 0 0 0 1"; i.e., it forgets the newline ('\n'). For example" char msg = "hilton.cec 5000 0 0 0 0 1"; // missing '\n' write (sfd, msg, strlen(msg)); The fix: char msg = "hilton.cec 5000 0 0 0 0 1\n"; 'xserv' really wants the '\n' because it is executing a 'xfgets()' which is looking for the newline character. 2) Connect Message Too Long The client sends a message like "hilton.cec 5000 0 0 0 0 1\nXX...XX"; i.e., it sends more than the exact connect message needed. This can happen if you do the following (for example): int MAXSIZE = 200; char msg = "hilton.cec 5000 0 0 0 0 1\n"; write (sfd, msg, MAXSIZE); // send 200 bytes The fix: write (sfd, msg, strlen(msg)); // send only the string 3) Incorrect Header Length For example, int MAXSIZE = 400; struct packet_hdr hdr; write (sfd, hdr, MAXSIZE); 'xserv' can't guess when the packet header begins and when the packet body begins. The fix: struct packet_hdr hdr; write (sfd, hdr, sizeof(struct packet_hdr)); 4) Incorrect 'dlen' field in the packet header. For example, struct packet_hdr hdr; char body[BODYSIZE]; hdr.dlen = sizeof(struct packet_hdr); write (sfd, hdr, sizeof(struct packet_hdr)); write (sfd, body, BODYSIZE); The 'dlen' field should be the size of the packet body, not header: struct packet_hdr hdr; char body[BODYSIZE]; hdr.dlen = BODYSIZE; write (sfd, hdr, sizeof(struct packet_hdr)); write (sfd, body, BODYSIZE); 5) Ignored Header-Body Packet Discipline After 'xserv' gets the connect message, it expects packets to arrive with NO intervening or missing bytes. A "packet" is defined to be a header followed by a body. The header is EXACTLY sizeof(struct packet_hdr) bytes. The length of the body is EXACTLY the value in the 'dlen' field of the header.