Whole ftp server consist of two executables server.out control_connection.out. The server executable can operate in two modes depending on filename name, transport.out is just hard link to server.out.
It take care of binding socket, listening on appropriate port and accepting clients connections. For each incoming conneciton server forks and execs control_connection.out with stdin set as socket out an stdout as socket in. Executable server.out takes one optional parameter representing port on which server is going to listen. If no parameter is specifed server is listening on default ftp port 21. It implements ipv4/ipv6 dualstack with ipv6 mapped ipv4 addresses. It is listening on every interface, wildcard socket is used.
Control connection then handles communication with one client. After all communication with client is done process ends thus socket descriptors are closed. It support all commands specifed above in specification.
If client requires data transfer control connection process forks and execs transport.out with three pipes between them. Executable transport.out requires ip address and socket descriptor of pipe intended for communication with parent(control connection). Through this pipe transport sends two bytes representing port on which transport is listening on. Transport process then accept conneciton from clien and waits for signals from control connection. If the signal SIGUSR1 is recieved, transport process reads from its input and forward data to socket. Otherwise if signal SIGUSR2 is recieved transport process reads from socket and forward data to stdout.
It is splited to several modules. Control_connection.c has communication loop which parses clients command and execute right command handler. If the command is unrecognized common reply is sent to client. Because this is only small implementation of ftp server the commands handlers calls are just staticaly hardcoded. The entire list of them is in commands.h. Commands handler function names has following pattern exec_<command_name>
_cmd(char *params) . Commands implementation is splitted to modules according to kind of commands job. Every command module can include control_connection.h file which provides fundamental state structures and helper function for communication. The structures are following:
This variable holds ip address of interface client is connected to. It is in ipv6 ipv4 mapped format. It is mainly required for transport connection.
extern char *loc_adr;
extern int ipv4;
This structure holds transport connection data. In/out descriptors for data transmissions, port on which is server transport connection listening on and process id of that process.
struct trans_con{
int trans_in, trans_out;
unsigned short port;
pid_t pid;
};
Following structure holds user session. It can be created by create_session and unallocated by free_session functions. If any user is logged on it is filled with valid data otherwise session is NULL. User is username, cur_path is current server working directory and it is relative to root_path. Root_path is absolute path of users storage in respect to server filesystem. It shouldnt be possible to get higher than root_path. Trans_con variable points to struct trans_con which is representing valid transport connection, otherwise it is NULL. If there is any command requesting another command call following him. Such a command name can be saved to next_seq_cmd variable and conntrol connection then ensure right error message is sent to client when the bad sequence of command is provided by client.
extern struct session{
char *user;
char *cur_path;
char *root_path;
struct trans_con *trans_con;
char *next_seq_cmd;
} *session;