www.xbdev.net
xbdev - software development
Friday April 19, 2024
home | contact | Support | WinSock with FTP". "( FTP basics through to a client ftp ". "application tutorial by bkenwright@xbdev.net)
>>
     
 

WinSock with FTP

( FTP basics through to a client ftp application tutorial by bkenwright@xbdev.net)

 

 

Well I thought I should write a small tutorial on how to use winsock with the ftp protocols....to some people the code might be a bit simple and has no error checking...but the tutorial is an introduction to how to create your very own Client FTP program.

If you grasp the basics from this tutorial, it shouldn't take you long to put together a fully functional ftp program such as CuteFTP or FlashFXP etc.

 

Also, I'm going to introduce the basics of the WinSock again...for example what each Winsock function call does etc...well where I think its important.

 

FTP...what does it mean?  Well FTP is an acronym for File Transfer Protocol, and its used to transfer files over the internet using TCP/IP.  The basic model of an FTP is that of a

client and a server.....we make a connection with the server, usually on port 21, then we can request a list of files, or upload a file...then we can close the connection.

 

 

Note: Nearly 99% of ftp servers use port 21.

 

Before any coding is even going to start, I've got to show you a list of the ftp command verbs:

 

Verb Desription
CWD Change the current directory on the server.
PWD Print the current directory on the server.
CDUP Moves up to the parent directory.
LIST List the contents of a directory.
MKD Creates a directory on the server.
RMD Removes a directory on the server.
DELE Removes a file from the server.
USER Sends the username for the login.
PASS Sends the password for the login.
ABOR Abort the transfer.
QUIT Closes the connection with the server.
STAT Gets teh current status of the server.
TYPE Toggles the binary flag on the server (TYPE A - Ascii, TYPE I Binary).
PORT Asks the server to connect the client.
PASV Requests a data connection on a new port.
RETR Requests the server to send a file.
STOR Sends a file from the client to the server.
APPE Same as STOR, except data is appended.
REST Start download at a certain point.
SYST Get the OS information of the server.
HELP Get help on a verb.
NOOP No operation.

 

 

Now onto the basics.....how does all this tie together?  Let me go through what we send and what we'll get back...so you'll know what to expect when we start coding.  First things first, we'll get our ftp address, (e.g. ftp.coolserver.com) ...then we'll connect to the server and listen!

For this tutorial, I just looked around on the web and found any public ftp server - ftp is: 'ajpo.sei.cmu.edu', you can try with any ftp server.

 

220-ada.pair.com NcFTPd Server (licensed copy) ready.

220-************************************************************************
220-* *
220-* [ada.pair.com] [sw-eng.falls-church.va.us] *
220-* At present, nothing is available via anonymous FTP. *
220-* Instead, please visit this web URL: http://sw-eng.falls-church.va.us *
220-* *
220-************************************************************************
220

 

Well there you go!  We connect to port 21 on 'ajpo.sei.cmu.edu' and the server sends us a hello message!  The number at the start of each line, is called the completion code (220 in this case), and indicates the type of message.  The server greeting has one of two reply completion codes - either 220 for success, or 421 if the server rejects us.

 

Now in reply to this greeting message we must send something back!  So what we send our username, in this case I'm just sending the word anonymous, as where going to log on as an anonymous.

 

USER anonymous

 

And in reply we get:

 

331 Guest login ok, send your complete e-mail address as password.

 

Okay okay, now you can see how this is going.... we send data and we get data...usually in ascii form......but before I start putting some code examples together..let me show a whole ftp client - server chat:

 

 

220-ada.pair.com NcFTPd Server (licensed copy) ready.

220-************************************************************************
220 - /* hello message */
220-************************************************************************
220

USER anonymous

331 Guest login ok, send your complete e-mail address as password.

PASS anonymouse@any.com

230 You are logged in as anonymous.

TYPE A

200 Type set to A

PASV

227 Entering Passive Mode (212,78,206,140,140,129)

RETR myfile.txt

150 Opening ASCII mode data connection for myfile.txt

226 Transfer complete

 

 

My god!  What was all that above your saying...well dont' get worried...you will learn in a sec what the above means.

 

We connect to the server, we get the hello message, then we send the message 'USER anonymous/r/n', and in return the server sends us a message saying to send our password...and so we send 'PASS anonymous @ .com'.

 

Usually the default transfer method is using ASCII, but just to make sure, I send the command 'TYPE A', and in response we get the return message '200 Type set to A', which means that data is transfered using 'Ascii' (e.g. text), as each line ending is with a CR/LF.

 

Next we want to do somthing a little more complex, we send the verb - 'PASV' which returns us '227 Entering Passive Mode (212,78,206,140,140,129)', this is an ip and a port address which will be used to transfer the data...the first 4 numbers are the ip address, and the second 2 are a port number, you work out the port number by multiplying the first number by 256 and add it to the second.

 

So in this example the ip and port would be:

ip: 212.78.206.140

port = 256*140  +  129  =  35969

 

All we have to do then is send which file we want (e.g. myfile.txt) and start listening on the other port, then the file will be send to it...we just buffer it and save it to a file.

 

 

CWD ./otherfolder

250 CWD command successful

TYPE I

200 Type set to I

 

 

How about a bit of coding....get a taste for how to make our own client ftp program...

 

It all begins.......

 

// This line is a compiler directive that includes the windows library

// during linking.  You could instead inside visual studio goto Project->

// settings" menu and under the "Link" tab add the necessary librarys instead.

#pragma comment(lib, "wsock32.lib")

 

#include <stdio.h>

#include <windows.h>

#include <winsock.h> 

 

WSADATA ws;

char buf[10000];

 

void output(char *str)

{

      FILE *fp = fopen("output.txt", "a+");

      fprintf(fp, "%s\n", str);

      fclose(fp);

}

 

 

int _stdcall WinMain(HINSTANCE, HINSTANCE, char* k, int l)

{

      int d = WSAStartup(0x101, &ws);

 

      sprintf(buf, "WSASTARTUP = %d", d);

      output(buf);

 

      return 0;

}

 

Output:

WSASTARTUP = 0

 

Well its not much to look at, but this is are starting stone!  Here above, we've created an output function so that we can write out any information to it, so we can look at it....I've also included the WinSock startup up funtion WSAStarup, which returns 0 if all went okay.  Don't forget to include the wsock32.lib, else you'll get linking errors.

 

#pragma comment(lib, "wsock32.lib")

 

#include <stdio.h>

#include <windows.h>

#include <Winsock.h>

 

 

WSADATA ws;

char buf[10000];

 

void output(char *str)

{

      FILE *fp = fopen("output.txt", "a+");

      fprintf(fp, "%s\n", str);

      fclose(fp);

}

 

 

int _stdcall WinMain(HINSTANCE, HINSTANCE, char* k, int l)

{

      int d = WSAStartup(0x101, &ws);

 

      sprintf(buf, "WSASTARTUP = %d", d);

      output(buf);

 

      // Open up a socket for out TCP/IP session

      SOCKET s = socket(AF_INET, SOCK_STREAM, 0);

      sprintf(buf, "SOCKET = %d", s);

      output(buf);

 

      // Set up socket information.

      struct sockaddr_in a;

      a.sin_family = AF_INET;

      a.sin_port = htons(21); // <- notice port 21 for ftp.

 

      // Get the ip address of our ftp

      struct hostent *h = gethostbyname("ajpo.sei.cmu.edu");

      sprintf(buf, "gethostbyname = %d", h);

      output(buf);

 

      sprintf(buf, "Host name  : %s\n", h->h_name);

      output(buf);

 

      sprintf(buf, "IP Address : %s\n",

                 inet_ntoa(*((struct in_addr *)h->h_addr)));

      output(buf);

     

      a.sin_addr.s_addr = inet_addr(inet_ntoa(*((struct in_addr *)h->h_addr)));

     

      // Actually connect to the server

      d = connect(s, (struct sockaddr *)&a, sizeof(a));

      sprintf(buf, "CONNECT = %d\n\n", d);

      output(buf);

 

 

      // We just listen to the open connection, and write

      // all the received information to our output file.

      char aa[1000] = {'/0'};

      int ii = recv(s, aa, sizeof(aa), 0);

      sprintf(buf, "~%s~", aa);

      output(buf);

 

 

      return 0;

}

 

Output:

WSASTARTUP = 0
SOCKET = 52
gethostbyname = 1358168
Host name : ns1.sw-eng.falls-church.va.us

IP Address : 216.92.6.187

CONNECT = 0


~
220-ada.pair.com NcFTPd Server (licensed copy) ready.
~

 

 

Well a lot of the lines I've outputted to the file are to show you what's actually happening inside, and it allows you to see if any errors have popped up while you where entering the code.

Notice the last line, which is the reply from the ftp server on port 21, it says '220-ada.pair.com NcFTPd Server (licensed copy) ready.', and as I mentioned before, the 220 indicates that the server is willing and ready.

 

 

Also remember that recv(..) is a blocking function...so when you call it, it wont' return or let you carry on with the code until it has received something...you'll find in windows that you can use asynchronous sockets which won't block, they usually send your application a message when data has been received.

 

 

Now for our next trick, lets have a try at talking to our ftp server....as you'll probably see in a minute, most of the hard work is done now..its just a matter of sending the correct verbs, and checking the received values.

 

#pragma comment(lib, "wsock32.lib")

 

#include <stdio.h>

#include <windows.h>

#include <Winsock.h>

 

 

WSADATA ws;

char buf[10000];

 

void output(char *str)

{

      FILE *fp = fopen("output.txt", "a+");

      fprintf(fp, "%s\n", str);

      fclose(fp);

}

 

 

int _stdcall WinMain(HINSTANCE, HINSTANCE, char* k, int l)

{

      int d = WSAStartup(0x101, &ws);

 

      sprintf(buf, "WSASTARTUP = %d", d);

      output(buf);

 

      // Open up a socket for out TCP/IP session

      SOCKET s = socket(AF_INET, SOCK_STREAM, 0);

      sprintf(buf, "SOCKET = %d", s);

      output(buf);

 

      // Set up socket information.

      struct sockaddr_in a;

      a.sin_family = AF_INET;

      a.sin_port = htons(21); // <- notice port 21 for ftp.

 

      // Get the ip address of our ftp

      struct hostent *h = gethostbyname("ajpo.sei.cmu.edu");

      sprintf(buf, "gethostbyname = %d", h);

      output(buf);

 

    sprintf(buf, "Host name  : %s\n", h->h_name);

      output(buf);

 

    sprintf(buf, "IP Address : %s\n", inet_ntoa(*((struct in_addr *)h->h_addr)));

      output(buf);

     

      a.sin_addr.s_addr = inet_addr(inet_ntoa(*((struct in_addr *)h->h_addr)));

     

      // Actually connect to the server

      d = connect(s, (struct sockaddr *)&a, sizeof(a));

      sprintf(buf, "CONNECT = %d\n\n", d);

      output(buf);

 

 

      // We just listen to the open connection, and write

      // all the received information to our output file.

      char aa[1000] = {'/0'};

      int ii = recv(s, aa, sizeof(aa), 0);

      sprintf(buf, "~%s~", aa);

      output(buf);

 

      // Send our username to the ftp-server

      output("Sending USER\r\n");

      strcpy(buf, "USER anonymous\r\n");

      send(s, buf, strlen(buf), 0);

 

      // lets get what the server says in reply.

      memset(aa, '\0', sizeof(aa));

      recv(s, aa, sizeof(aa), 0);

      sprintf(buf, "~\n%s\n~", aa);

      output(buf);

 

      // assuming all went okay, send our password.

      output("sending: PASS anonymous@anyone.com\r\n");

      strcpy(buf, "PASS anonymous@anyone.com\r\n");

      send(s, buf, strlen(buf), 0);

 

      // catch the response to our password.

      memset(aa, '\0', sizeof(aa));

      recv(s, aa, sizeof(aa), 0);

      sprintf(buf, "~\n%s\n~", aa);

      output(buf);

 

      // After logging in, the ftp server may send a happy

      // welcome message to use.

      memset(aa, '\0', sizeof(aa));

      recv(s, aa, sizeof(aa), 0);

      sprintf(buf, "~\n%s\n~", aa);

      output(buf);

 

      return 0;

}

 

Output:

WSASTARTUP = 0
SOCKET = 52
gethostbyname = 1358168
Host name : ns1.sw-eng.falls-church.va.us

IP Address : 216.92.6.187

CONNECT = 0


~220-ada.pair.com NcFTPd Server (licensed copy) ready.
~
Sending USER

~
220-************************************************************************
220-* *
220-* [ada.pair.com] [sw-eng.falls-church.va.us] *
220-* At present, nothing is available via anonymous FTP. *
220-* Instead, please visit this web URL: http://sw-eng.falls-church.va.us *
220-* *
220-************************************************************************
220

~
sending: PASS anonymous@anyone.com

~
331 Guest login ok, send your complete e-mail address as password.

~
~
230-You are user #8 of 16 simultaneous users allowed.
230-
230-************************************************************************
230-* *
230-* [ada.pair.com] [sw-eng.falls-church.va.us] *
230-* At present, nothing is available via anonymous FTP. *
230-* Instead, please visit this web URL: http://sw-eng.falls-church.va.us *
230-* *
230-************************************************************************
230-
230 Logged in anonymously.

~

 

 

Tadaaaa....yup, we've successfully logged into an ftp server, and authenticated ourselves.  Yup, I know in the beginning it was looking rather tricky, but its really simple once you get the basics down.  I'll tidy up the code a bit, and demonstrate how to get and send a file, and how to get information from the ftp server.... now maybe you might want to get a large mug of coffee about now...its not easy having to learn all this stuff in one big go...

 

Hold on... where going deeper!

 

 

Here is the code, now its exactly the same code as above, but I've put it into tidy parts....it will output the exact same as the above output, but its been organised into functions....a connection function, a send function, and a receive funtion.  As the only paramater that is important is the data which is send (e.g. USER anonymous) and the SOCKET number...SOCKET if you look deep in the .h files is just an unsigned integer...so we pass that to our recv and send functions...here is the code:

 

#pragma comment(lib, "wsock32.lib")

 

#include <stdio.h>

#include <windows.h>

#include <Winsock.h>

 

WSADATA ws;

char buf[10000];

 

void output(char *str)

{

      FILE *fp = fopen("output.txt", "a+");

      fprintf(fp, "%s\n", str);

      fclose(fp);

}

 

/************************************************************************/

/*                                                                      */

/*    Our connection function.                                          */

/*                                                                      */

/************************************************************************/

 

SOCKET ConnectFTP(char* ftpname, int port)

{

      WSAStartup(0x101, &ws);

 

      // Open up a socket for out TCP/IP session

      SOCKET s = socket(AF_INET, SOCK_STREAM, 0);

 

      // Set up socket information.

      struct sockaddr_in a = {AF_INET, htons(port)};

 

      // Get the ip address of our ftp

      struct hostent *h = gethostbyname(ftpname);

      a.sin_addr.s_addr = inet_addr(inet_ntoa(*((struct in_addr *)h->h_addr)));

     

      // Actually connect to the server

      connect(s, (struct sockaddr *)&a, sizeof(a));

 

      return s;

}

/************************************************************************/

/*                                                                      */

/*    Output our received data.                                         */

/*                                                                      */

/************************************************************************/

void receiving(SOCKET s, char* string = 0)

{

      char aa[1000] = {'/0'};

      int ii = recv(s, aa, sizeof(aa), 0);

      sprintf(buf, "~%s~", aa);

      output(buf);

      if(string !=0)

            strcpy(string, aa);

}

/************************************************************************/

/*                                                                      */

/*    Create a tidy send function.                                      */

/*                                                                      */

/************************************************************************/

void sending(SOCKET s, char* verb)

{

      strcpy(buf, verb);  strcat(buf, "\r\n");

      output("Sending: "); output(buf);

      send(s, buf, strlen(buf), 0);

}

/************************************************************************/

/*                                                                      */

/*    Out Entry point! Body of our program! :)                          */

/*                                                                      */

/************************************************************************/

int _stdcall WinMain(HINSTANCE, HINSTANCE, char* k, int l)

{

      SOCKET s1 = ConnectFTP("ajpo.sei.cmu.edu", 21);

 

 

      // Get hello message.

      receiving(s1);

 

      // Send our username to the ftp-server

      sending(s1, "USER anonymous");

 

      // lets get what the server says in reply.

      receiving(s1);

 

      // assuming all went okay, send our password.

      sending(s1, "PASS anonymous@anyone.com");

 

      // catch the response to our password.

      receiving(s1);

 

      // After logging in, the ftp server may send a happy

      // welcome message to use.

      receiving(s1);

 

      return 0;

}

 

Now that I've tidied up the code, let me send and record more of the FTP verb commands, and see what we get.....a lot of the code will be repeated, e.g. you will get familiar with certain functions.....but I think its good to be able to see the fully working program....the more times you go over it the more familiar you'll become with it.  So once your sure you understand how the above code works...have a go at sending and receiving your own 'verbs'...e.g. send the command to the server "HELP" and see what it sends back.

 

Well this code does more or less the same as above, but I've called some more of the commands on the server so show you some typical responses.

 

#pragma comment(lib, "wsock32.lib")

 

#include <stdio.h>

#include <windows.h>

#include <Winsock.h>

 

WSADATA ws;

char buf[10000];

 

void output(char *str)

{

      FILE *fp = fopen("output.txt", "a+");

      fprintf(fp, "%s\n", str);

      fclose(fp);

}

 

/************************************************************************/

/*                                                                      */

/*    Our connection function.                                          */

/*                                                                      */

/************************************************************************/

 

SOCKET ConnectFTP(char* ftpname, int port)

{

      WSAStartup(0x101, &ws);

 

      // Open up a socket for out TCP/IP session

      SOCKET s = socket(AF_INET, SOCK_STREAM, 0);

 

      // Set up socket information.

      struct sockaddr_in a = {AF_INET, htons(port)};

 

      // Get the ip address of our ftp

      struct hostent *h = gethostbyname(ftpname);

      a.sin_addr.s_addr = inet_addr(inet_ntoa(*((struct in_addr *)h->h_addr)));

     

      // Actually connect to the server

      connect(s, (struct sockaddr *)&a, sizeof(a));

 

      return s;

}

/************************************************************************/

/*                                                                      */

/*    Output our received data.                                         */

/*                                                                      */

/************************************************************************/

void receiving(SOCKET s, char* string = 0)

{

      char aa[1000] = {'/0'};

      int ii = recv(s, aa, sizeof(aa), 0);

      sprintf(buf, "~%s~", aa);

      output(buf);

      if(string !=0)

            strcpy(string, aa);

}

/************************************************************************/

/*                                                                      */

/*    Create a tidy send function.                                      */

/*                                                                      */

/************************************************************************/

void sending(SOCKET s, char* verb)

{

      strcpy(buf, verb);  strcat(buf, "\r\n");

      output("Sending: "); output(buf);

      send(s, buf, strlen(buf), 0);

}

/************************************************************************/

/*                                                                      */

/*    Out Entry point! Body of our program! :)                          */

/*                                                                      */

/************************************************************************/

int _stdcall WinMain(HINSTANCE, HINSTANCE, char* k, int l)

{

      SOCKET s1 = ConnectFTP("ajpo.sei.cmu.edu", 21);

 

 

      // Get hello message.

      receiving(s1);

 

      // Send our username to the ftp-server

      sending(s1, "USER anonymous");

      receiving(s1);

 

      // assuming all went okay, send our password.

      sending(s1, "PASS anonymous@anyone.com");

      receiving(s1);

      receiving(s1);

 

      // Get the FTP server system details

      sending(s1, "SYST");

      receiving(s1);

 

      // Get the FTP's current directory

      sending(s1, "PWD");

      receiving(s1);

 

      // Move our start pointer to 100 for file transfers

      sending(s1, "REST 100");

      receiving(s1);

 

      // Move it back to 0 ;)

      sending(s1, "REST 0");

      receiving(s1);

 

      // Move it back to 0 ;)

      sending(s1, "HELP");

      receiving(s1);

      receiving(s1);

 

      // Close our connection with the ftp server

      sending(s1, "QUIT");

      receiving(s1);

 

      return 0;

}

 

 

Output:

~
220-ada.pair.com NcFTPd Server (licensed copy) ready.
~
Sending:
USER anonymous
~
220-************************************************************************
220-* *
220-* [ada.pair.com] [sw-eng.falls-church.va.us] *
220-* At present, nothing is available via anonymous FTP. *
220-* Instead, please visit this web URL: http://sw-eng.falls-church.va.us *
220-* *
220-************************************************************************
220
~
Sending:
PASS anonymous@anyone.com
~
331 Guest login ok, send your complete e-mail address as password.
~
~
230-You are user #2 of 16 simultaneous users allowed.
230-
230-************************************************************************
230-* *
230-* [ada.pair.com] [sw-eng.falls-church.va.us] *
230-* At present, nothing is available via anonymous FTP. *
230-* Instead, please visit this web URL: http://sw-eng.falls-church.va.us *
230-* *
230-************************************************************************
230-
230 Logged in anonymously.
~
Sending:
SYST
~
215 UNIX Type: L8
~
Sending:
PWD
~
257 "/" is cwd.
~
Sending:
REST 100
~
350 Will attempt to restart at position 100.
~
Sending:
REST 0
~
350 Will attempt to restart at position 0.
~
Sending:
HELP
~
214-The following commands are recognized (* => unimplemented, + => extension).
~
~
214- ABOR CWD MKD OPTS+ REIN SITE STRU*
214- ACCT* DELE MLSD+ PASS REST SIZE SYST
214- ALLO* FEAT+ MLST+ PASV RETR SMNT* TYPE
214- APPE HELP MODE PORT RMD STAT USER
214- CDUP LIST NLST PWD RNFR STOR
214- CLNT+ MDTM NOOP QUIT RNTO STOU
214-
214 Send comments to support@pair.com.
~
Sending:
QUIT
~
221 Goodbye.
~

 

 

Well this is sure turning into a long tutorial, now for the next part....I've goto show you how to download a file from the server!  Its not going to be easy, but I'm sure you'll be able to manage....take my hand and follow me step by step through it...

 

I've commented the new lines of code in this example with //NEW NEW NEW..etc  so you can see which are the lines that I've added to get the IP and port address from the returned string from the server.

 

#pragma comment(lib, "wsock32.lib")

 

#include <stdio.h>

#include <windows.h>

#include <Winsock.h>

 

WSADATA ws;

char buf[10000];

 

void output(char *str)

{

      FILE *fp = fopen("output.txt", "a+");

      fprintf(fp, "%s\n", str);

      fclose(fp);

}

 

/************************************************************************/

/*                                                                      */

/*    Our connection function.                                          */

/*                                                                      */

/************************************************************************/

 

SOCKET ConnectFTP(char* ftpname, int port)

{

      WSAStartup(0x101, &ws);

 

      // Open up a socket for out TCP/IP session

      SOCKET s = socket(AF_INET, SOCK_STREAM, 0);

 

      // Set up socket information.

      struct sockaddr_in a = {AF_INET, htons(port)};

 

      // Get the ip address of our ftp

      struct hostent *h = gethostbyname(ftpname);

      a.sin_addr.s_addr = inet_addr(inet_ntoa(*((struct in_addr *)h->h_addr)));

     

      // Actually connect to the server

      connect(s, (struct sockaddr *)&a, sizeof(a));

 

      return s;

}

/************************************************************************/

/*                                                                      */

/*    Output our received data.                                         */

/*                                                                      */

/************************************************************************/

void receiving(SOCKET s, char* string = 0)

{

      char aa[1000] = {'/0'};

      int ii = recv(s, aa, sizeof(aa), 0);

      sprintf(buf, "~%s~", aa);

      output(buf);

      if(string !=0)

            strcpy(string, aa);

}

/************************************************************************/

/*                                                                      */

/*    Create a tidy send function.                                      */

/*                                                                      */

/************************************************************************/

void sending(SOCKET s, char* verb)

{

      strcpy(buf, verb);  strcat(buf, "\r\n");

      output("Sending: "); output(buf);

      send(s, buf, strlen(buf), 0);

}

/************************************************************************/

/*                                                                      */

/*    Out Entry point! Body of our program! :)                          */

/*                                                                      */

/************************************************************************/

int _stdcall WinMain(HINSTANCE, HINSTANCE, char* k, int l)

{

      SOCKET s1 = ConnectFTP("ajpo.sei.cmu.edu", 21);

 

 

      // Get hello message.

      receiving(s1);

 

      // Send our username to the ftp-server

      sending(s1, "USER anonymous");

      receiving(s1);

 

      // assuming all went okay, send our password.

      sending(s1, "PASS anonymous@anyone.com");

      receiving(s1);

      receiving(s1);

 

      // NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW

      // NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW

      // NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW

 

      // First send the command, PASV, which will inform the ftp server

      // that we are going to request a file, and it prepairs a port for us.

      sending(s1, "PASV");

      // Now a typically returned string would be in the form:

      // ->227 Entering Passive Mode (216,92,6,187,194,13)<-

      // so the tricky part is to get the ip and port from it.

      char szString[1000];

      receiving(s1, szString);

     

      // So our string is in buf, which is for example:

      // "227 Entering Passive Mode (216,92,6,187,194,13)"

     

      // Lets extract the string "216,92,6,187,194,13"

      char szIP[40];

      char* start = strchr(szString, '(' );

      char* end   = strchr(szString, ')' );

      int num = end - start;

 

      char str[30] = {'\0'};

      strncpy( str, start + 1, num - 1 );

 

      // str now contains "216,92,6,187,194,13"

      char* token = strtok( str , "," );

 

      // Lets break the string up using the ',' character as a seperator

      // Lets get the IP address from the string.

      strcpy(szIP, "");

      strcat(szIP, token);

      strcat(szIP, ".");  //szIP contains "216."

 

      token = strtok( NULL, "," );

      strcat(szIP, token);

      strcat(szIP, ".");  //szIP contains "216.92."

 

      token = strtok( NULL, "," );

      strcat(szIP, token);

      strcat(szIP, "."); // szIP contains "216.92.6."

 

      token = strtok( NULL, "," );

      strcat(szIP, token);// szIP contains "216.92.6.187"

     

      // Now lets get the port number

      token = strtok( NULL, "," );

      int intA = atoi(token);  // 194

      token = strtok( NULL, "," );

      int intB = atoi(token);  // 13

 

      int port = (intA * 256) + intB;

 

      // Lets display our output to a file to make sure its the correct one.

      sprintf(buf, "IP %s, Port %d", szIP, port);

      output(buf);

 

      // NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW

      // NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW

      // NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW

 

      // Close our connection with the ftp server

      sending(s1, "QUIT");

      receiving(s1);

 

      return 0;

}

 

Output:

~
220-ada.pair.com NcFTPd Server (licensed copy) ready.
~
Sending:
USER anonymous
~
220-************************************************************************
220-* *
220-* [ada.pair.com] [sw-eng.falls-church.va.us] *
220-* At present, nothing is available via anonymous FTP. *
220-* Instead, please visit this web URL: http://sw-eng.falls-church.va.us *
220-* *
220-************************************************************************
220
~
Sending:
PASS anonymous@anyone.com
~
331 Guest login ok, send your complete e-mail address as password.
~
~
230-You are user #7 of 16 simultaneous users allowed.
230-
230-************************************************************************
230-* *
230-* [ada.pair.com] [sw-eng.falls-church.va.us] *
230-* At present, nothing is available via anonymous FTP. *
230-* Instead, please visit this web URL: http://sw-eng.falls-church.va.us *
230-* *
230-************************************************************************
230-
230 Logged in anonymously.
~
Sending:
PASV

~
227 Entering Passive Mode (216,92,6,187,194,13)
~
IP 216.92.6.187, Port 49677
Sending:
QUIT
~
221 Goodbye.
~

 

Well your going to be thinking at this point...so what do we do with this new IP and port number....well we us this new IP and port number to either send or receive the file where interested in from or to the server.  We simply tell the server what where going to do, either download or send a file, then we get the okay message....we connect to this new IP and port, then send or receive it.

 

I''ve wrote the next piece of code....which is more or less the same as above, but with the added code to get a file from the server.

 

Take note!

 

#pragma comment(lib, "wsock32.lib")

 

#include <stdio.h>

#include <windows.h>

#include <Winsock.h>

 

WSADATA ws;

char buf[10000];

 

void output(char *str)

{

      FILE *fp = fopen("output.txt", "a+");

      fprintf(fp, "%s\n", str);

      fclose(fp);

}

 

/************************************************************************/

/*                                                                      */

/*    Our connection function.                                          */

/*                                                                      */

/************************************************************************/

 

SOCKET ConnectFTP(char* ftpname, int port)

{

      WSAStartup(0x101, &ws);

 

      // Open up a socket for out TCP/IP session

      SOCKET s = socket(AF_INET, SOCK_STREAM, 0);

 

      // Set up socket information.

      struct sockaddr_in a = {AF_INET, htons(port)};

 

      // Get the ip address of our ftp

      struct hostent *h = gethostbyname(ftpname);

      a.sin_addr.s_addr = inet_addr(inet_ntoa(*((struct in_addr *)h->h_addr)));

     

      // Actually connect to the server

      connect(s, (struct sockaddr *)&a, sizeof(a));

 

      return s;

}

/************************************************************************/

/*                                                                      */

/*    Output our received data.                                         */

/*                                                                      */

/************************************************************************/

void receiving(SOCKET s, char* string = 0)

{

      char aa[1000] = {'/0'};

      int ii = recv(s, aa, sizeof(aa), 0);

      sprintf(buf, "~%s~", aa);

      output(buf);

      if(string !=0)

            strcpy(string, aa);

}

/************************************************************************/

/*                                                                      */

/*    Create a tidy send function.                                      */

/*                                                                      */

/************************************************************************/

void sending(SOCKET s, char* verb)

{

      strcpy(buf, verb);  strcat(buf, "\r\n");

      output("Sending: "); output(buf);

      send(s, buf, strlen(buf), 0);

}

/************************************************************************/

/*                                                                      */

/*    Out Entry point! Body of our program! :)                          */

/*                                                                      */

/************************************************************************/

int _stdcall WinMain(HINSTANCE, HINSTANCE, char* k, int l)

{

      SOCKET s1 = ConnectFTP("ajpo.sei.cmu.edu", 21);

 

 

      // Get hello message.

      receiving(s1);

 

      // Send our username to the ftp-server

      sending(s1, "USER anonymous");

      receiving(s1);

 

      // assuming all went okay, send our password.

      sending(s1, "PASS anonymous@anyone.com");

      receiving(s1);

      receiving(s1);

 

 

      // First send the command, PASV, which will inform the ftp server

      // that we are going to request a file, and it prepairs a port for us.

      sending(s1, "PASV");

      // Now a typically returned string would be in the form:

      // ->227 Entering Passive Mode (216,92,6,187,194,13)<-

      // so the tricky part is to get the ip and port from it.

      char szString[1000];

      receiving(s1, szString);

     

      // So our string is in buf, which is for example:

      // "227 Entering Passive Mode (216,92,6,187,194,13)"

     

      // Lets extract the string "216,92,6,187,194,13"

      char szIP[40];

      char* start = strchr(szString, '(' );

      char* end   = strchr(szString, ')' );

      int num = end - start;

 

      char str[30] = {'\0'};

      strncpy( str, start + 1, num - 1 );

 

      // str now contains "216,92,6,187,194,13"

      char* token = strtok( str , "," );

 

      // Lets break the string up using the ',' character as a seperator

      // Lets get the IP address from the string.

      strcpy(szIP, "");

      strcat(szIP, token);

      strcat(szIP, ".");  //szIP contains "216."

 

      token = strtok( NULL, "," );

      strcat(szIP, token);

      strcat(szIP, ".");  //szIP contains "216.92."

 

      token = strtok( NULL, "," );

      strcat(szIP, token);

      strcat(szIP, "."); // szIP contains "216.92.6."

 

      token = strtok( NULL, "," );

      strcat(szIP, token);// szIP contains "216.92.6.187"

     

      // Now lets get the port number

      token = strtok( NULL, "," );

      int intA = atoi(token);  // 194

      token = strtok( NULL, "," );

      int intB = atoi(token);  // 13

 

      int port = (intA * 256) + intB;

 

      // Lets display our output to a file to make sure its the correct one.

      sprintf(buf, "IP %s, Port %d", szIP, port);

      output(buf);

 

      // NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW

      // NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW

      // NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW

 

      // At this very point, the variable port contains our port number,

      // and szIP has our IP address that we'll receive the file we

      // are requesting.

 

      // So we send the command RETR welcome.txt, then listen on the other

      // ip and port for the file to be sent.  After its been send, the

      // other port will be closed.

 

      SOCKET s2 = ConnectFTP(szIP, port);

 

      sending(s1, "RETR welcome.msg"); // Tell ftp server to send this file.

 

      receiving(s1);  // Listen for the okay from our ftp server.

 

      // Listen on our other port for the file...in this case the file

      // we are getting is a txt file called welcome.msg, I'll just get it

      // and put it to our text file output, you could save it to a file.

      receiving(s2);

 

      receiving(s1);   // Listen to a response from our server.

 

      // NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW

      // NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW

      // NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW

 

      // Close our connection with the ftp server

      sending(s1, "QUIT");

      receiving(s1);

 

      return 0;

}

 

Output:

~
220-ada.pair.com NcFTPd Server (licensed copy) ready.
~
Sending:
USER anonymous
~
220-************************************************************************
220-* *
220-* [ada.pair.com] [sw-eng.falls-church.va.us] *
220-* At present, nothing is available via anonymous FTP. *
220-* Instead, please visit this web URL: http://sw-eng.falls-church.va.us *
220-* *
220-************************************************************************
220
~
Sending:
PASS anonymous@anyone.com
~
331 Guest login ok, send your complete e-mail address as password.
~
~
230-You are user #11 of 16 simultaneous users allowed.
230-
230-************************************************************************
230-* *
230-* [ada.pair.com] [sw-eng.falls-church.va.us] *
230-* At present, nothing is available via anonymous FTP. *
230-* Instead, please visit this web URL: http://sw-eng.falls-church.va.us *
230-* *
230-************************************************************************
230-
230 Logged in anonymously.
~
Sending:
PASV
~
227 Entering Passive Mode (216,92,6,187,196,209)
~
IP 216.92.6.187, Port 50385
~
Sending:
RETR welcome.msg
~
150 Data connection accepted from 81.5.150.234:1063; transfer starting for welcome.msg (511 bytes).
~
Received File Is Shown here:
~
************************************************************************
* *
* [ada.pair.com] [sw-eng.falls-church.va.us] *
* At present, nothing is available via anonymous FTP. *
* Instead, please visit this web URL: http://sw-eng.falls-church.va.us *
* *
************************************************************************
~
~
226 Transfer completed.
~
Sending:
QUIT
~
221 Goodbye.
~

 

 

I'm sure your getting the hang of it by now... and I've started you off on the road to creating your own ftp client...or maybe even a ftp server.  To finish the tutorial I'll show you a text list of a number of commands sent and received from an ftp server.... I've added comments which are between the /* comment */ markings....so I can outline things within it.

 

/* Public FTP is ftp.io.com/pub/usr/rkg/public-ftp" */

 

 

 

/*--Comment:------------------------------------------------------------------

  Here we are just connecting to a public server ftp, and listen on the port

----------------------------------------------------------------------------*/

Connecting to ftp.io.com

Connected to ftp.io.com Port 21

220 ftp-01.io.com FTP server (Version wu-2.6.1(2) Thu Jan 11 15:33:27 CST 2001) ready.

 

 

/*--Comment:------------------------------------------------------------------

        Send our username and password

----------------------------------------------------------------------------*/

USER anonymous

331 Guest login ok, send your complete e-mail address as password.

PASS (hidden)

230-Welcome to Illuminati Online's Anonymous FTP site.

230-

230-*******************************************************************************

230-

230-If you upload something to one of our customer's incoming directories, please

230-send mail to that person/company informing them of the upload.

230-

230-We allow 512 concurrent users; 5 are currently logged in.

230-

230 Guest login ok, access restrictions apply.

 

/*--Comment:------------------------------------------------------------------

        As for the ftp server details

----------------------------------------------------------------------------*/

SYST

215 UNIX Type: L8

REST 100

350 Restarting at 100. Send STORE or RETRIEVE to initiate transfer.

REST 0

350 Restarting at 0. Send STORE or RETRIEVE to initiate transfer.

 

/*--Comment:------------------------------------------------------------------

    Check our working directory, it says "/" hence where in the root

    directory.

----------------------------------------------------------------------------*/

PWD

257 "/" is current directory.

 

 

/*--Comment:------------------------------------------------------------------

     Data transfer type set to A for Ascii

----------------------------------------------------------------------------*/

TYPE A

200 Type set to A.

PASV

227 Entering Passive Mode (199,170,88,105,167,102)

 

/*--Comment:------------------------------------------------------------------

    Note, that even the LIST, which is just a stream of text is sent

    to the PASV port, which we initilised by sending the command PASV.

----------------------------------------------------------------------------*/

LIST

150 Opening ASCII mode data connection for /bin/ls.

226 Transfer complete.

 

/*--Comment:------------------------------------------------------------------

    Change directory to "pub"

----------------------------------------------------------------------------*/

CWD pub

250 CWD command successful.

PWD

257 "/pub" is current directory.

 

PASV

227 Entering Passive Mode (199,170,88,105,225,137)

LIST

150 Opening ASCII mode data connection for /bin/ls.

226 Transfer complete.

 

/*--Comment:------------------------------------------------------------------

    (1) Set for binary transfer (TYPE I)

    (2) Send command PASV and get the transfer port and IP (PASV)

    (3) Tell the ftp which file we want (RETR .procmailrc)

    (4) Get the okay that the file is going to be sent

    * Read the file in on the PASV port

    (5) Receive file send complete message.

----------------------------------------------------------------------------*/

TYPE I

200 Type set to I.

PASV

227 Entering Passive Mode (199,170,88,105,126,158)

RETR .procmailrc

150 Opening BINARY mode data connection for .procmailrc (1212 bytes).

226 Transfer complete.

Transferred: .procmailrc 1 KB in 0.47 (1.18 KBps)

Transfer queue completed

Transferred 1 file totaling 1 KB in 1.75 (1.18 KBps)

 

/*--Comment:------------------------------------------------------------------

    Sending a file to the ftp!

----------------------------------------------------------------------------*/

 

TYPE I

200 Type set to I

PASV

227 Entering Passive Mode (212,78,206,140,201,154).

STOR data.txt

150 Opening BINARY mode data connection for data.txt

226 Transfer complete

 

 

/*--Comment:------------------------------------------------------------------

    Saying goodbye :D

----------------------------------------------------------------------------*/

 

QUIT

221 Goodbye

 

 

 

Further Reading:

  • RFC 959

Feedback:  As usual, with any tutorials, feedback is always appreciated...again this tutorial might be a little easy for some, or maybe a little complex for those unfamiliar with C and C++, but if you come across any errors or maybe something which you think would be invaluable, please feel free to email me any comments anytime.... Well until next time...

 

(bkenwright@xbdev.net)

 

 

 

 

 

 
Advert (Support Website)

 
 Visitor:
Copyright (c) 2002-2024 xbdev.net - All rights reserved.
Designated articles, tutorials and software are the property of their respective owners.