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