CSS 432
FAQ on Final Project: Network Application


Q1: How many lines should the ftp client expect to read as a server reply?

I have a question about the replies the server sends back. For replies, what can the client assume as far as the message size or line count? I am running into a problem where if I don't know how many lines to read for each reply, I am not getting all of the data. If I just keep looping, I will read all of the data, but as soon as no data is left, I go into a read call that blocks and waits for incoming data. So basically my question is, what can we assume about the server replies, and if we can assume nothing, how can we make sure we read the entire reply without going into a read call that blocks?

I read the RFC about server replies and how the first line and the last line should contain a common sequence to tell the client that more data exists on additional lines and that no more data is left after the last line. Should we use this implantation for our client?

A: Use poll( &ufds, 1, 1000 ) to check if you have more data to read

While RFC mentions the first and the last line format returned from the server, all you need is just use the poll system call.
   #include <sys/poll.h>
   struct pollfd ufds;

   ufds.fd = sd;                     // a socket descriptor to exmaine for read
   ufds.events = POLLIN;             // check if this sd is ready to read
   ufds.revents = 0;                 // simply zero-initialized
   int val = poll( &ufds, 1, 1000 ); // poll this socket for 1000msec (=1sec)

   if ( val > 0 ) {                  // the socket is ready to read
      char buf[BUFLEN];
      int nread = read( sd, buf, BUFLEN ); // guaranteed to return from read 
                                           // even if nread < BUFLEN

Q2: How do we read from cin without knowing the # of reads in advance?

Since we have to have the program handle input in a variety of ways, how do we read from the console (cin) without know the # of reads in advance?

A: Use cin.getline( )

Here is a code example. After receiving a cin intput in command[], you have to lexically analyze its contents.
   #define 10000                     // allocate a big character array

   char command[CMD_MAX];            // receive a cin input
   cin.getline( command, CMD_MAX );

Q3: Which messages need to have the crlf delimiter and how do we add it to them?

A: All commands must have the crlf "\r\n" delimiter at their tail. Also, all server responses must have this delimiter, too.

Q4: Do we need to fork the client application in case when receiving data over the passive ftp connection?

For our project you talked about forking the client application in class when receiving data over the passive ftp connection. For example in order:
   Send PASV
   Passively Connect()
   Fork() a child
   Send LIST
What I cannot figure out is why the client needs to fork for getting the data? Currently my client is complete and, get, put and ls work just like the actual FTP program without using a fork. Is there some specific reason we need to fork that I am not realizing?

A: It is always safe to let a child process or a thread read data from the server.

If your client sends a "LIST" command and thereafter tries to read data from the server, the server might have already sent data and closed the passive connection before your client actually reads the data, in which case you will receive a "broken pipe" error. To prevent this error, you would like to spawn a child process or a thread and make them read to read data, (i.e., call read( )) before you actually send a "LIST" command. Although the spawned process or a thread may be blocked for a read first, once the server receives "LIST" and returns data, it can immediately read data. That's the reason why you may need to spawn another instance to read data. In summary, my recommended sequence will be:
   send a PASV command to the server
   receive a server response
   establish a "data" connection
   fork a child process/thread and let it be blocked on read( )
   send a RETR command to the server
   the child reads all data from the server and terminates itself.

Q5: For the client do we have to get the system username who is logged and display it in the prompt like the real FTP client?

A: Yes. Use getlogin.

A code example is:
   #include <unistd.h>
   #include <stdio.h>

   char *serverIp;     // let it point to one of argv[] that includes serverIp.

   string userString( getlogin( ) );
   cout << "Name (" << serverIp << ":" << userString << "): ";

Q6: What file modes does the client have to specify when writing to its local disk a file received from the server?

A: Use S_IRUSR, S_IWUSR, S_IRGRP, and S_IROTH.

For the get command, the client should set these file modes before writing a fie received from the server:
   #include <sys/types.h>
   #include <sys/stat.h>
   #include <fcntl.h>

   mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
   int file = open( filename, O_WRONLY | OCREAT, mode );

Q7: I received a multiple defintion error when compiling my program.

When i tried to put the socket into one class and compile the ftp and ftpd programs, i am getting a multiple definition error for all of the functions. any idea why?

A: Use #ifndef, #define, and #endif

If you code many classes that may refer to each other, the compiler may read the same header file repeatedly, which causes this multiple definition error. Use #ifndef, #defin, and #endif in your header file. Assuming your header file name is Socket.h, your file should be:
   #ifndef _SOCKET_H_
   #define _SOCKET_H_

   your class definition

   #endif
This way prevents the compiler from scanning the same class definition.

Q8: Although I converted all C++ string into C chars, write( ) still does not work.

Here is my code:
char sendCmd[100];
cin >> cmd;
strcpy (sendCmd, "PASS ");
strcat (sendCmd, cmd);
strcat (sendCmd, "\r\n");
int nwrite = write(clientSd, sendCmd, sizeof(sendCmd) );
What's wrong?

A: Make sure the exact number of bytes you will send

In the above example, you'll always send 100 bytes. Assuming that cmd includes "abc", sendCmd includes "PASS abc\r\n" which is 10-byte long. Note that sendof( sendCmd ) always return 100 in the above case.

Q9: I have so much trouble with getline( )

A: Use cin >>.