CSS 432
FAQ on Final Project: Network Application


Please ignore Q1, Q3, Q6, Q8, Q10, Q11, Q13, Q14, Q15, and Q17, all of that were intended for a server design.

Q1: Should our FTP server be able to accept multiple client connections?

For our FTP server do we have to assume we will multiple clients connected at once? Just for clarification on how an FTP servers work: if you have multiple clients connecting at once to ONE ftp server, do you have to spawn an instance of the server process for each client connected? In such a case then, wouldn't each instance of the server process have to use a unique port number for the persistent active connection generally on port 21?

A: Yes

Once the ftp server accepts a new connection, it must spawn a child process that handles this connection. The parent ftp server must always wait for a new connection on a given port or a default port #21. Each child must use a free port when a passive mode is requested by its client.

Q2: 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

Q3: Why is the discrepancy between "telnet hostname port" and ftp -p port hostname

In the example on a lecture slide, you create an ftp with the command sequence:
   >telnet hostname port
but in the assignment we do
   >ftp -p port hostname.
why the discrespancy

A: No reason

If I try to find some reasons, the unix ftp can receive only one argument, (i.e., hostname). All the other parameters must be given as -vdingkfxut options. So, the project specification somewhat follows this format.

Q4: 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 );

Q5: 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.

Q6: Does the client first create a temporary connection of port 21?

To clarify, the client create a temp connection of port 21. at this point it has to send a userID and a password in order to connect to the server.

A: If the client does not receive a -p option, you can do so.

If the client has receive a -p option, it must establish a connection of the port given in -p. This option is necessary to communicate with your own ftpd that must run on a port rather than 21.

Q7: 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.

Q8: How can the server get its local IP address?

I am following up about my question how to get the local IP address for my server to send back its IP address to the client. I tried using getsockname on the binded socket, but that did not work.

A: Use gethostname, gethostbyname, and inet_ntoa

Use the following code:
#define MAX 200 or what you like
char hostname[MAX];
bzero( hostname, MAX );
gethostname( hostname, MAX );
struct hostent* host = gethostbyname( hostname );
char *ipAddr = inet_ntoa( *( struct in_addr * )*host->h_addr_list );
You'll receive the IP address in ipAddr. For more details of each system call, use man.

Q9: 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 << "): ";

Q10: For the FTP server, how should it handle sending files in binary or ascii mode?

According to the RFC for FTP, ASCII mode should send each line with a CRLF character (\r\n) at the end. The problem I am having is when the server open’s a binary file but in ASCII mode as requested by the client, how do we figure out where the end of line is to append CRLF when we are dealing with binary data? Is it sufficient to just open a file in the corresponding mode and read its entire contents and send it, or do we need to do further processing depending on the mode?

A: Simply assume that the FTP server can handle only the binary mode for file transfer.

For the FTP client, you have to always direct the FTP server to transfer data in the binary mode. Use "TYPE I". For the "ls" command, both the client and server should assume the ASCII mode.

Q11: How can we check a valid password on the client when not using anonymous?

A: The server should read the passwd file in its local directory for a validation.

The server must scan all account/password pairs in this file and check if there is such a paper that matches the account and password given by the client through the USER and PASS commands.

Q12: 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 <fcnt.h>

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

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

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

Q14: How does the server change its working directory?

A: Use the open and fchdir commands.

   #include <sys/types.h>
   #include <sys/stat.h>
   #include <fcnt.h>
   #include <unistd.h>

   int dirfd = open( directoryName, O_DIRECTORY | O_RDONLY );
   fchdir( dirfd );

Q15: How can the server send the contents of its current working directory?

A: Use system( "/bin/ls -l" ) and dup2.

Here is a recommended squence:
   create a pipe.
   fork a child process.
   let the child map the pipe input to descritor 1, (i.e., stdout) using dup2.
   let the child run system("/bin/ls -l") to pass ls outputs to the pipe input.
   let the parent read the ls outputs through the pipe output.

Q16: 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.

Q17: I got "./ftpd: Permission denied"

When trying to run your server program, i get a permission denied error. Here is the ouput:
   [user@uw1-320-29 put]$ ./ftpd -p 3375
   -bash: ./ftpd: Permission denied

A: Try chmod and a different port.

You might have changed your ftpd's file mode for some reason. Furthermore, use the last five digitas of your student id for the sever port.
   chmod 700 ftpd
   ./ftpd -p 33750