Reputation: 369
I'm trying to code a TCP FTP service for a multi-threaded server. I found this tutorial http://www.mario-konrad.ch/wiki/doku.php?id=programming:multithreading:tutorial-04 which is very helpful to understand the multithreading of clients for the TCP protocol. In fact, this code create a server that can accept multiple connections from different clients simultaneously.
However, I'm struggling to find how to apply the ftp service on it. Precisely how to put and get a file to and from the FTP server.
Any help please?
Upvotes: 1
Views: 21323
Reputation: 1909
FTP uses two TCP connections to transfer files: a control connection and a data connection.
Establish a control connection to the FTP server, and log in.
Next, establish the data connection. If you are connecting from behind a router then send the PASV
command to ask the server to listen on a new data socket and send the IP/port back to you. If you're not behind a router then you will need to listen on a new data socket and use the PORT
command to send the IP/port to the server.
Once the data connection is established, send the STOR (upload) or RETR (download) command over the control connection to begin the transfer.
Data going over the control socket would look something like this:
(Open Control Connection)
SERVER: 220 System Ready
CLIENT: USER MyUserName
SERVER: 331 Please specify the password.
CLIENT: PASS MyPassword
SERVER: 230 Login successful.
CLIENT: TYPE I
SERVER: 200 Switching to Binary mode.
CLIENT: PASV
SERVER: 227 Entering Passive Mode (173,254,254,254,211,37)
(Client connects data connection to the specified address)
CLIENT: RETR example.html
SERVER: 150 Opening BINARY mode data connection for example.html (10403 bytes).
SERVER: 226 File send OK.
(Both close the data connection)
CLIENT: QUIT
SERVER: 221 Goodbye
(Both close control connection)
Upvotes: 1
Reputation: 1750
The code below is an assignment I did for a networking paper last year. Hope it helps.
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <winsock.h>
#include <winsock2.h>
#define BUFFERSIZE 800
#define WSVERS MAKEWORD(2,0)
WSADATA wsadata;
void wy_fileName_collector(char *_buffer, char *_nameBuffer);
int main(int argc, char *argv[])
{
//INITIALIZATION
struct sockaddr_in localaddr,remoteaddr;
struct sockaddr_in remoteaddr_act;
SOCKET s,ns;
SOCKET s_data_act=0;
char send_buffer[BUFFERSIZE],receive_buffer[BUFFERSIZE];
char fileName[40];
int n,bytes,addrlen;
memset(&localaddr,0,sizeof(localaddr));//clean up the structure
memset(&localaddr,0,sizeof(remoteaddr));//clean up the structure
//WSASTARTUP
if (WSAStartup(WSVERS, &wsadata) != 0)
{
WSACleanup();
printf("WSAStartup failed\n");
exit(1);
}
//SOCKET
s = socket(PF_INET, SOCK_STREAM, 0);
if (s <0)
{
printf("socket failed\n");
}
localaddr.sin_family = AF_INET;
if (argc == 2) localaddr.sin_port = htons((u_short)atoi(argv[1]));
else localaddr.sin_port = htons(1234);//default listening port
localaddr.sin_addr.s_addr = INADDR_ANY;//server address should be local
//BIND
if (bind(s,(struct sockaddr *)(&localaddr),sizeof(localaddr)) != 0)
{
printf("Bind failed!\n");
exit(0);
}
//LISTEN
listen(s,5);
while (1)
{
addrlen = sizeof(remoteaddr);
//NEW SOCKET newsocket = accept
ns = accept(s,(struct sockaddr *)(&remoteaddr),&addrlen);
if (ns <0 ) break;
printf("accepted a connection from client IP %s port %d \n",inet_ntoa(remoteaddr.sin_addr),ntohs(localaddr.sin_port));
//Respond with welcome message
sprintf(send_buffer,"\n==220 Welcome to Alan's FTP site== \r\n\n");
bytes = send(ns, send_buffer, strlen(send_buffer), 0);
while (1)
{
n = 0;
while (1)
{
//RECEIVE
bytes = recv(ns, &receive_buffer[n], 1, 0);//receive byte by byte...
//PROCESS REQUEST
if ( bytes <= 0 ) break;
if (receive_buffer[n] == '\n')
{ /*end on a LF*/
receive_buffer[n] = '\0';
break;
}
if (receive_buffer[n] != '\r') n++; /*ignore CRs*/
}
if ( bytes <= 0 ) break;
printf("-->DEBUG: the message from client reads: '%s' \r\n", receive_buffer);
/**
* @brief Exception handling
*/
if(strncmp(receive_buffer,"USER",4) && strncmp(receive_buffer,"PASS",4) && strncmp(receive_buffer,"SYST",4)
&&strncmp(receive_buffer,"PORT",4) && strncmp(receive_buffer,"STOR",4) && strncmp(receive_buffer,"RETR",4)
&&strncmp(receive_buffer,"LIST",4) && strncmp(receive_buffer,"NLST",4) && strncmp(receive_buffer,"QUIT",4))
{
sprintf(send_buffer,"202 Command not implemented, superfluous at this site. \r\n");
bytes = send(ns, send_buffer, strlen(send_buffer), 0);
}
if (strncmp(receive_buffer,"USER",4)==0)
{
printf("Logging in \n");
sprintf(send_buffer,"331 Password required \r\n");
bytes = send(ns, send_buffer, strlen(send_buffer), 0);
if (bytes < 0) break;
}
if (strncmp(receive_buffer,"PASS",4)==0)
{
printf("Typing password (anything will do... \n");
sprintf(send_buffer,"230 Public login sucessful \r\n");
bytes = send(ns, send_buffer, strlen(send_buffer), 0);
if (bytes < 0) break;
}
if (strncmp(receive_buffer,"SYST",4)==0)
{
system("ver > tmp.txt");
FILE *fin=fopen("tmp.txt","r");//open tmp.txt file
sprintf(send_buffer,"150 Transfering... \r\n");
bytes = send(ns, send_buffer, strlen(send_buffer), 0);
char temp_buffer[80];
while (!feof(fin))
{
fgets(temp_buffer,78,fin);
sprintf(send_buffer,"%s",temp_buffer);
send(s_data_act, send_buffer, strlen(send_buffer), 0);
}
fclose(fin);
sprintf(send_buffer,"226 File transfer completed... \r\n");
bytes = send(ns, send_buffer, strlen(send_buffer), 0);
if (bytes < 0) break;
}
//PORT
if(strncmp(receive_buffer,"PORT",4)==0)
{
s_data_act = socket(AF_INET, SOCK_STREAM, 0);
//local variables
unsigned char act_port[2];
int act_ip[4], port_dec;
char ip_decimal[40];
sscanf(receive_buffer, "PORT %d,%d,%d,%d,%d,%d",&act_ip[0],&act_ip[1],&act_ip[2],&act_ip[3],(int*)&act_port[0],(int*)&act_port[1]);
remoteaddr_act.sin_family=AF_INET;//local_data_addr_act
sprintf(ip_decimal, "%d.%d.%d.%d", act_ip[0], act_ip[1], act_ip[2],act_ip[3]);
printf("IP is %s\n",ip_decimal);
remoteaddr_act.sin_addr.s_addr=inet_addr(ip_decimal);
port_dec=act_port[0]*256+act_port[1];
printf("port %d\n",port_dec);
remoteaddr_act.sin_port=htons(port_dec);
if (connect(s_data_act, (struct sockaddr *)&remoteaddr_act, (int) sizeof(struct sockaddr)) != 0)
{
printf("trying connection in %s %d\n",inet_ntoa(remoteaddr_act.sin_addr),ntohs(remoteaddr_act.sin_port));
sprintf(send_buffer, "425 Something is wrong, can't start the active connection... \r\n");
bytes = send(ns, send_buffer, strlen(send_buffer), 0);
closesocket(s_data_act);
}
else
{
sprintf(send_buffer, "200 Ok\r\n");
bytes = send(ns, send_buffer, strlen(send_buffer), 0);
printf("Data connection to client created (active connection) \n");
}
}
/**
* @brief STOR
*/
if((strncmp(receive_buffer,"STOR",4)==0))
{
memset(&fileName, 0, strlen(fileName));
wy_fileName_collector(receive_buffer, fileName);
if(fopen(fileName,"w") == NULL)
{
printf("@alan:line1\n");
sprintf(send_buffer,"450 Requested file action not taken. \r\n");
bytes = send(ns, send_buffer, strlen(send_buffer), 0);
}
else
{
FILE *fout=fopen(fileName,"w");
sprintf(send_buffer,"150 File status okay; about to open data connection. \r\n");
bytes = send(ns, send_buffer, strlen(send_buffer), 0);
while(1)
{
n = 0;
while(1)
{
//RECEIVE
bytes = recv(s_data_act, &receive_buffer[n], 1, 0);//receive byte by byte...
//PROCESS REQUEST
if ( bytes <= 0 ) break;
if (receive_buffer[n] == '\n')
{ /*end on a LF*/
receive_buffer[n] = '\0';
break;
}
if (receive_buffer[n] != '\r') n++; /*ignore CRs*/
}
if ( bytes <= 0 ) break;
fprintf(fout,"%s\n",receive_buffer);
}
sprintf(send_buffer,"226 File transfer completed... \r\n");
bytes = send(ns, send_buffer, strlen(send_buffer), 0);
fclose(fout);
closesocket(s_data_act);
}
}
/**
* @brief RETR
*/
if((strncmp(receive_buffer,"RETR",4)==0))
{
memset(&fileName, 0, strlen(fileName));
wy_fileName_collector(receive_buffer, fileName);
if(fopen(fileName,"r")==NULL)
{
sprintf(send_buffer,"450 Requested file action not taken. \r\n");
bytes = send(ns, send_buffer, strlen(send_buffer), 0);
}
else
{
FILE *fin=fopen(fileName,"r");//open tmp.txt file
sprintf(send_buffer,"150 Transfering... \r\n");
bytes = send(ns, send_buffer, strlen(send_buffer), 0);
char temp_buffer[80];
while (!feof(fin))
{
fgets(temp_buffer,78,fin);
sprintf(send_buffer,"%s",temp_buffer);
send(s_data_act, send_buffer, strlen(send_buffer), 0);
}
fclose(fin);
sprintf(send_buffer,"226 File transfer completed... \r\n");
bytes = send(ns, send_buffer, strlen(send_buffer), 0);
}
closesocket(s_data_act);
}
//LIST or NLST
if ( (strncmp(receive_buffer,"LIST",4)==0) || (strncmp(receive_buffer,"NLST",4)==0))
{
system("dir > tmp.txt");
FILE *fin=fopen("tmp.txt","r");//open tmp.txt file
sprintf(send_buffer,"150 Transfering... \r\n");
bytes = send(ns, send_buffer, strlen(send_buffer), 0);
char temp_buffer[80];
while (!feof(fin))
{
fgets(temp_buffer,78,fin);
sprintf(send_buffer,"%s",temp_buffer);
send(s_data_act, send_buffer, strlen(send_buffer), 0);
}
fclose(fin);
sprintf(send_buffer,"226 File transfer completed... \r\n");
bytes = send(ns, send_buffer, strlen(send_buffer), 0);
closesocket(s_data_act);
}
//QUIT
if (strncmp(receive_buffer,"QUIT",4)==0)
{
printf("Quit \n");
sprintf(send_buffer,"221 Connection closed by the FTP client\r\n");
bytes = send(ns, send_buffer, strlen(send_buffer), 0);
if (bytes < 0) break;
closesocket(ns);
}
}
//CLOSE SOCKET
closesocket(ns);
printf("disconnected from %s\n",inet_ntoa(remoteaddr.sin_addr));
}
closesocket(s);//it actually never gets to this point....use CTRL_C
}
/**
* @brief Return file name from the string passed in.
*/
void wy_fileName_collector(char *_buffer, char *_nameBuffer)
{
char bf[BUFFERSIZE];
char sep[2] = " "; //separation is space
char *word;
int wcount=0;
strcpy(bf, _buffer);
for (word = strtok(bf, sep);word;word = strtok(NULL, sep))
{
wcount++;
if(wcount == 2) // jump the first space"_".
{
strcpy(_nameBuffer, word);
}
}
}
Upvotes: 4