First Internet Client
From Web (19.11.1997)
Table of Contents
All this while we've been talking about creating ActiveX Objects and Java applets and other
Internet related stuff. Even though we talked long and hard about transferring files via the
Internet, we haven't really tackled the basic issues of HOW the files are transferred. We've
pointed out the various shortcomings of different languages and browsers and yet we've never
told you how they worked. Infact, come to think of it, we've really left you in the dark about
how the Internet really operates.
Well, it's confession time, we didn't know either !! Infact, if we hadn't worked for two
hard weeks cracking code and reading piles of books, we still wouldn't know. So, here it is,
the fruits of our labor, a complete tutorial, with source code and explanations about
nearly every aspect of the 'net from TCP/IP and DNS Servers, to Traceroute Ping. So
read on and broaden your horizons !!
I personally could never have predicted that the net would grow at such a pace that one day,
commercials would give web site addresses right at the end. Even the man on the street knows
that a programming by the name of Java exists. The Internet is no longer a geek hangout,
it's being slowly integrated into the global and International communications mainstream.
The Web has grown so fast and the software has become so complicated that in the last
six months, I've had to totally revamp my entire knowledge base.
The problem with the Internet is that although everyone knows about it, it is not a
technology that most programmers fully understand. Unlike the all the computer languages use ,
there is no central command or controlling body. Also, the net assures relative anonymity.
No one can know whether your working on a UNIX workstation, a Mac, a Pentium or a 286 with 1
MB RAM and a 40 MB hard disk !! All these rambling debates about whether UNIX is good or
bad or whether the Mac OS is better that Windows 95 are meaningless. This perhaps is the
real reason behind the feeling of equality in cyberspace.
While learning C under DOS for the first time ( a long long time ago, in a galaxy far far away !),
I realized that no matter how close the language may be to the computer, for me, it wasn't
close enough. So, after my C course, I went out and learnt assembly. I personally think
that the most productive time in my programming career was when I learnt to write a virus,
because after that, I knew DOS inside out. I was completely comfortable with it.
I could say "DOS, your mine !" with a certain amount of self confidence. I can't however,
say that about Windows95, because I don't know what the hell is going on under the hood.
( In DOS, there was no hood !! ) The same goes for the 'net, I really didn't know what
happened when I said http://www.neca.com/~vmis.
In India, it is below my dignity to wash, tune up or even fill up my own car ( AH ! the
pleasures of a large work force !! ). It is the driver job, not mine. Yet if I took care of
my machine myself, I'd know more about it, I'd know what makes it run. This is the reason
perhaps that Americans are better drivers!!
What I'm trying to say is that we can't understand something as amorphous as the Internet until
we get our hands dirty; unless we write our own code. Now, in India, I am quite a well
known public figure. So I'm often called upon to give these great bombastic lectures
about the Internet. I stand in front of a crowd full of eager listeners and I shoot my
mouth off about the 'net and until a week ago, I would feel like a fake, because I
really didn't know what I was talking about ! But now, that I've written my own programs,
blundered through my own code, I can truthfully say, " Internet, your mine !!".
Being a nice guy I like to share and share alike, so I'm going to try and teach you
how to write your own Internet software suite. We'll do the basics of WinSock programming
with TCP/IP and UDP.
Now there are already books available that teach you how to write an email client and
other Internet software, but they usually end up confusing people because around 95 % of
the code they list deals with the User Interface. Only 5 % of the code deals with the Internet.
Now at the moment, I really don't want to create a marketable product, that can come later.
What I want to do is understand the Internet related code and this is precisely the code
we're going to teach you.
Now, if you're going to learn from us, you'll have to follow our rules. First write the code the
way we want you to (No blinking, no breathing, no drooling and you have to type with the big
toe on your left foot) and then add your own embellishments later. In a break from
tradition we're going to provide you with finished polished code, along with the
rough and ready stuff we use to help you learn ( Learning Code we call it ). This
in itself should tell you how seriously we taking this and how important we think it is.
The reason we believe every programmer should learn this technology is because we think
that the Internet is the future. From now on, we have to stop thinking of machines as
islands, complete in themselves, but as one continuously connected nation. Even the humble
wordprocessor needs to be Internet ready, able to send and receive email and faxes.
Accounting packages should be able to log onto a specified server to collect the latest
information about a company or product. With all these advances, EVERYONE needs to
learn how to program for the 'net. After all, wouldn't you understand the
intricacies of the web better if you could write a program that connects to a site and then
tells you the exact route the TCP/IP packets will take to reach the said site ?
Now the code given here is in C/C++, but making the code Internet ready is a breeze.
You can convert your code into an ActiveX Object ( Check out our tutorial ) or
into a Java applet (we have a tutorial on this too ...) or into a Netscape
plugin ( ditto). We have a Traceroute program as an ActiveX Object which is
put up on our site. So when you visit our site, you can click in a certain window
and type in the name of the site you want to trace and see the route the packets
take from our server to the specified site.
To convert your code into an ActiveX Object, which can be used from under any language
that's OLE compliant, all you have to do is add a little more code, a little more complexity.
Once you've converted your program, every server on the Internet can have it. The
finished programs at the end have all kinds of error checks and also a decent user interface,
but if we were to try and teach using that code, you'd spend sleepless nights trying to
wean the chaff from the real code. So, we be teaching using rougher and more unpolished code ,
which you're probably used to if you've been visiting our site regularly. Infact, along with
the ActiveX Objects, we'll give you Java applets and Netscape Plugins. Maybe even some code
using LiveConnect or OLE Automation !
The good people from Microsoft often send us complementary email. Now that doesn't mean
that Bill Gates sends us mail ( after all, I said the GOOD people from Microsoft !! ),
it's the people behind Active Animation or ActiveX who write to us. And believe me,
I prefer their mails to any correspondence Gates may want to send (except for
large generous cheques!!). Unfortunately, their high command still hasn't
noticed us, so if you like this site, do us a favor and petition Microsoft to
put up the name of our site on their " To Visit " list ( Mailto : XXXXX ). Oh,
and by the way, If you intend to use our programs, please place an Easter egg
in them so that when the user clicks his mouse on the upper left-hand corner
of the screen, jumps up and down on his chair shouting " Bonga Boola Boola !! " ,
kisses his toes ( in turn, from right to left ) and it's my birthday ( 29th Feb. ),
you'll tell him where you got the code from.
A lot of the code here has been adapted from samples we found on the Internet and in
various publications. There are just too many names to be named ( and, to tell the truth,
a lot of the input was anonymous ) and we can't put them all up. But here are the
names of some of the people whose work helped us bring this tutorial to you :-
Sorry, but we haven't compiled the names yet ! Give us a little time.
Before we start off with the first of our programs, we'll take a short break and tell you a
little bit about how the Internet works. What we'll be telling you here is full of holes, so
if you know all this already, skip it.
You'll understand how the Internet works better if you have a basic understanding of how
the plain old telephone system ( POTS ) functions. For example, I pick up my phone in Bombay
and dial up someone in Delhi. Is my phone connected to the phone in Delhi by a physical
line ? of course not. The connection can be considered physical, but only in the loosest
sense. What we actually have here is a virtual connection one which only lasts
for as long as the communication itself. Even the route my voice takes along the wires
can vary, not only between one call and the next, but also within a call. So one moment
my voice will be routed via Bombay, Madras, Delhi and ten seconds later, via Bombay,
Calcutta, Delhi, depending on the line conditions and the load.
This concept of a virtual connection is at the very heart of the Internet. The routes
my TCP/IP packets take to and from a certain site can vary. One moment they'll come
down one pathway and a few seconds later, by another. This routing of
information packets is what information transfer on the 'net is based on. The
router is what telephone companies spend the most amount of time and
money on, because it is the router that calculates the load factors on each line
and decides which route a packet should take, optimizing the limited number of
telephone cables and speeding up information exchange. Infact, routers often
send the packets along convoluted and extremely complex routes in order to
bypass busy exchanges and land lines. In fact, most telephone exchanges in
the world today use the Packet Switching Networks (PSN's) explain above. This
means that every word you say is converted into a packet and send winging it's
way to it's destination.
Since the routers ( in their never ending quest for the fastest route ) force the information
to take such convoluted paths, these packets sometimes wander off and go AWOL. This is OK if
you're having a conversation with someone and you miss a vowel or two, but if, for instance,
you're transporting binary files the results can be disastrous. It was to combat this problem
of missing packets that the TCP/IP protocol was established. A protocol, by the way, is any
form of communication which follows certain predefined rules.
The TCP/IP protocol is actually two protocols sandwiched one above the other. The IP
(Internet Protocol) protocol deals exclusively with the routers. It's IP's job is to make
sure your packet goes from one end to the other in the shortest possible time. IP is the
one who informs the router about the location of it's destination, it's source and other
such details. The IP protocols primary concern is speed. It has to try and get to the
destination as fast as possible and it cares about nothing else. The IP protocol has
sacrificed reliability for speed and it shows. If the Internet we're to rely exclusively
on IP, the result would be absolutely chaotic !
It was to combat this problem of unreliability that the TCP ( Transmission Control Protocol )
protocol was established. The TCP protocol is the exact opposite of the IP protocol. It's
primary concern is reliability and it's makers forfeited speed to get it. It is the TCP
protocol that takes care of checksums and sequence, to make sure that every packet
reaches and is used in the correct order.
When TCP/IP was invented, the architects made it quite clear that TCP/IP would be
entirely machine and operating system independent. So these furious debates about the
supremacy of the Macintosh over Wintel machines or vice versa, no longer makes any
sense. On the Internet, it's impossible to distinguish between the two.
A misconception prevalent in the programming world is that something called
"TCP/IP programming" exists. TCP/IP is a very low level protocol and practically no
one writes TCP/IP code. It's like trying to write a word processor for Windows95,
in Assembler ! It's possible, but the people who try and do it often end up in
large comfortable farmhouse surrounded with electrified barbed wire, wearing strange
white jackets and learning to weave straw baskets !!
Of course, we were crazy enough to take the plunge ! Check out our tutorial's on the
various Internet Protocols, but read this tutorial first.
The only sane way to write Internet related code is to use Sockets Programming or
as it is called under Windows, WinSock Programming. The WinSock internally calls
TCP/IP, but it's easier to use because it equates Internet information transfers to
file transfers to and from your hard disk. So we'll be teaching you WinSock
programming in this tutorial and not direct TCP/IP.
Let's not waste anymore time over theoretical discussions on the workings of the Internet,
instead, let's jump right in and I promise I'll explain all the important concepts as we
proceed. After all, it makes more sense to explain the theory after you've seen
the source code and tried it out.
Here's a program that leads up to our first true Internet client. If you're already
familiar with C-SDK Windows programing, then jump ahead to the Time Client.
Note:-To run this program, create a project in Visual C++ ( We're using Visual C++ 4.0 )
and insert the file a1.cpp into the project a1.
Now build the project.
a1.cpp
#include <windows.h>
#include <stdio.h>
void abc(char *p)
{
FILE *fp=fopen("c:\\z.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
WNDCLASS a;HWND b;MSG c;
long _stdcall zzz (HWND,UINT,WPARAM,LPARAM);
int _stdcall WinMain(HINSTANCE i,HINSTANCE j,char *k,int l)
{
a.lpszClassName="a1";
a.hInstance=i;
a.lpfnWndProc=zzz;
a.hbrBackground=GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b=CreateWindow("a1","aaa",WS_OVERLAPPEDWINDOW,1,1,10,20,0,0,i,0);
ShowWindow(b,3);
while ( GetMessage(&c,0,0,0) )
DispatchMessage(&c);
return 1;
}
long _stdcall zzz (HWND w,UINT x,WPARAM y,LPARAM z)
{
if ( x == WM_LBUTTONDOWN)
{
MessageBox(0,"end","end",0);
}
if ( x == WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
This is a basic Windows program. We've initialized lpfnWndProc, a member of the structure
a which looks like WNDCLASS to the function zzz. This function will be our callback
function.So, whenever anything of importance happens to the window (the window is minimized,
maximized etc.), our call back function is called.
We'll be putting all our WinSock code in the callback function.
The Time Client
#include <windows.h>
#include <stdio.h>
void abc(char *p)
{
FILE *fp=fopen("z.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
WNDCLASS a; HWND b; MSG c; char aa[200]; SOCKET s; struct hostent h;
WSADATA ws; DWORD e; int ii,dw; char bb[100]; struct sockaddr_in Sa;
long _stdcall zzz (HWND,UINT,WPARAM,LPARAM);
int _stdcall WinMain(HINSTANCE i,HINSTANCE j,char *k,int l)
{
a.lpszClassName="a1";
a.hInstance=i;
a.lpfnWndProc=zzz;
a.hbrBackground=GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b=CreateWindow("a1","time client",WS_OVERLAPPEDWINDOW,1,1,10,20,0,0,i,0);
ShowWindow(b,3);
while ( GetMessage(&c,0,0,0) )
DispatchMessage(&c);
return 1;
}
long _stdcall zzz (HWND w,UINT x,WPARAM y,LPARAM z)
{
if ( x == WM_LBUTTONDOWN)
{
e=WSAStartup(0x0101,&ws);
sprintf(aa,"e = %ld",e);
abc(aa);
s = socket(PF_INET,SOCK_DGRAM,0);
sprintf(aa,"s = %ld",s);
abc(aa);
Sa.sin_family=AF_INET;
Sa.sin_addr.s_addr = inet_addr("140.252.1.32");
Sa.sin_port=htons(13);
strcpy (bb,"hello how are you");
e=sendto(s,bb,100,0,(struct sockaddr *)&Sa,sizeof(Sa));
sprintf(aa,"SendTo %ld",e);
int dw = sizeof(Sa);
recvfrom(s,bb,100,0,(sockaddr *)&Sa,&dw);
MessageBox(0,bb,"data from server",0);
MessageBox(0,"end","end",0);
}
if ( x == WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
This is it ! your very first Internet Client ! It doesn't seem like much, but it doesn't do much
either !! It's just the bare code and the user interface is absolutely pukey. But it works
and that's what counts.
To run this program, first create a project in Visual C++ ( We're using Visual C++ 4.0 )
and insert these files into the project :-
- A1.cpp - This is the file displayed above.
- Wsock32.lib - This is a lib file not displayed above.
Build the project. Before you run the .exe, be sure to log into your local Internet Service
Provider. Now run the file. You will be confronted with a beautifully rendered and artistically
designed blank window. Click anywhere in it and the Internet code in the Callback function is called.
The code itself is rather simple. WinMain() creates and initializes a window and we've associated a
callback function with it. The window is assigned certain properties and then maximized.
The callback, zzz() contains the real juicy bits. When you click in the window (WM_LBUTTONDOWN ),
the function zzz() is called and it inturn kicks off the code for the Time Client. The header file,
windows.h internally calls the file winsock.h.
In the first line, the function WSAStartup() is absolutely necessary. This is the function which
initializes the whole code. It's first parameter is 0x0101 which symbolizes the Winsock's version
number . 0x0101 stands for WinSock version 1.01 (you have to read it backwards and consider
the zero to be a decimal point). &ws is the location in memory of the structure tag WSAData.
The uses of &ws will be discussed later. If all went well, WSAStartup() will return a zero ,
a non-zero value implies that an error occurred.
#include <windows.h>
#include <stdio.h>
void abc(char *p)
{
FILE *fp=fopen("c:\\z.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
WNDCLASS a;HWND b;MSG c;char aa[200];char bb[20000];
WSADATA ws;DWORD e;
long _stdcall zzz (HWND,UINT,WPARAM,LPARAM);
int _stdcall WinMain(HINSTANCE i,HINSTANCE j,char *k,int l)
{
a.lpszClassName="a1";
a.hInstance=i;
a.lpfnWndProc=zzz;
a.hbrBackground=GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b=CreateWindow("a1","aaa",WS_OVERLAPPEDWINDOW,1,1,10,20,0,0,i,0);
ShowWindow(b,3);
while ( GetMessage(&c,0,0,0) )
DispatchMessage(&c);
return 1;
}
long _stdcall zzz (HWND w,UINT x,WPARAM y,LPARAM z)
{
if ( x == WM_LBUTTONDOWN)
{ abc("Before WSAStartup");
sprintf(aa,"wVersion....%d",ws.wVersion);
MessageBox(0,aa,aa,0);
abc(aa);
sprintf(aa,"wHighVersion....%d",ws.wHighVersion);
MessageBox(0,aa,aa,0);
abc(aa);
sprintf(aa,"szDescription....%s",&ws.szDescription);
MessageBox(0,aa,aa,0);
abc(aa);
sprintf(aa,"szSystemStatus....%s",&ws.szSystemStatus);
MessageBox(0,aa,aa,0);
abc(aa);
sprintf(aa,"iMaxSockets....%u",ws.iMaxSockets);
MessageBox(0,aa,aa,0);
abc(aa);
sprintf(aa,"iMaxUdpDg....%u",ws.iMaxUdpDg);
MessageBox(0,aa,aa,0);
abc(aa);
sprintf(aa,"lpVendorInfo....%s",ws.lpVendorInfo);
MessageBox(0,aa,aa,0);
abc(aa);
e=WSAStartup(0x0101,&ws);
sprintf(aa,"e..%ld",e);
MessageBox(0,aa,aa,0);
abc("After WSAStartup");
sprintf(aa,"wVersion....%d",ws.wVersion);
MessageBox(0,aa,aa,0);
abc(aa);
sprintf(aa,"wHighVersion....%d",ws.wHighVersion);
MessageBox(0,aa,aa,0);
abc(aa);
sprintf(aa,"szDescription....%s",&ws.szDescription);
MessageBox(0,aa,aa,0);
abc(aa);
sprintf(aa,"szSystemStatus....%s",&ws.szSystemStatus);
MessageBox(0,aa,aa,0);
abc(aa);
sprintf(aa,"iMaxSockets....%u",ws.iMaxSockets);
MessageBox(0,aa,aa,0);
abc(aa);
sprintf(aa,"iMaxUdpDg....%u",ws.iMaxUdpDg);
MessageBox(0,aa,aa,0);
abc(aa);
sprintf(aa,"lpVendorInfo....%s",ws.lpVendorInfo);
MessageBox(0,aa,aa,0);
abc(aa);
MessageBox(0,"end","end",0);
}
if ( x == WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
In this program, we've listed out the members of the structure with their respective values before
and after WSAStartup function is called. After running the program, check the file z.txt in the root
directory.
The next important function is socket(), which initializes the WinSock socket to be used for
communication. A socket is a hypothetical entity, created solely to help us understand Internet
programming better.
It's first parameter, PF_INET is a number that informs the socket that it is to be used for the
Internet. WinSock sockets can also be used over Novel and other networks and therefore the intended
use has to be specified. SOCK_DGRAM tells the socket that the protocol to be used for communication
is UDP/IP, or as it is commonly known, UDP (User Datagram Protocol).
UDP, like TCP is an Internet protocol which rides piggy back on IP. Unlike TCP however, UDP is not
a very stable or reliable protocol, but it is much faster than the former. UDP is used in cases
where reliability is not an issue, like with Real Audio and Internet Phone, where a few lost
packets don't really affect sound quality,
but where speed is of the essence. Since sending a simple request for the current date and time
is not really that demanding a job, UDP works fine. If the socket is created without problems,
then the socket function returns a zero, which is caught and displayed by s.
( SOCKET is a macro which stands for 'unsigned int' ).
After creating a socket, we have to initialize the members of a structure called Sa.
Sa.sin_family=AF_INET means that the packets will travel on the Internet.
Sa.sin_addr.s_addr = inet_addr ("140.252.1.32") fills up this member of the structure with
the IP address of the destination server. An IP address is a bit like a phone number.
For me to talk to you, I must have a phone ( with its own number ) and I must know your
phone number. To be on the Internet, every computer must have an IP address, otherwise
the packets don't know where to go. A unique IP address, which is a long number ( 232 bits ),
is given to each and every computer logged onto the Internet. If the IP number is permanent,
it means that it is the number of a server, which is always on-line. If the number is random,
it means it belongs to a dial-up subscriber, who is given an IP number, valid for only for the
length of the session.
When packet is sent, the IP header holds the IP address from which the packet has come.
That is, it holds the IP address of your computer, e.g. 10. The IP header also holds the
IP address of the destination computer, which is, for example, 22. Your data packet is first
sent to you ISP's router, who checks the IP header for the destination address. Since all
routers know the IP addresses of the other routers and also the range of IP addresses they
handle, your router, which handles IP address from 0 to 10 for example, sends the packet
to a router in Singapore, which handles IP address from 15 to 25. That router then sends the
data to the target computer, whose IP address of 22 falls within it's range. Of course,
this is a highly simplified example, involving only two routers. In actuality, your packet
may pass through about six to seven routers, going one way and about the same number coming back.
IP addresses are usually given in the Dotted Decimal Notation, where every char of the
long is given individually and separated with a dot. There is no compulsion to do so,
it just increases the readability of the IP address. However, to use the address, it has
to be converted into a long first and the function inet_addr does just that.
#include <windows.h>
#include <stdio.h>
void abc(char *p)
{
FILE *fp=fopen("c:\\z.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
WNDCLASS a;HWND b;MSG c;char aa[200];
WSADATA ws;DWORD e;long dd;
long _stdcall zzz (HWND,UINT,WPARAM,LPARAM);
int _stdcall WinMain(HINSTANCE i,HINSTANCE j,char *k,int l)
{
a.lpszClassName="a1";
a.hInstance=i;
a.lpfnWndProc=zzz;
a.hbrBackground=GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b=CreateWindow("a1","aaa",WS_OVERLAPPEDWINDOW,1,1,10,20,0,0,i,0);
ShowWindow(b,3);
while ( GetMessage(&c,0,0,0) )
DispatchMessage(&c);
return 1;
}
long _stdcall zzz (HWND w,UINT x,WPARAM y,LPARAM z)
{
if ( x == WM_LBUTTONDOWN)
{
dd = inet_addr("140.252.1.32");
sprintf(aa,"dd=%ld",dd);
abc(aa);
MessageBox(0,aa,aa,0);
MessageBox(0,"end","end",0);
}
if ( x == WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
Here's a small little program that demonstrates the effect inet_addr has on a
number in the Dotted Decimal Format.
Next we have Sa.sin_port = htons( 13 ). This member of the structure holds the port number
the packets must go to. The ports referred to here, are not the serial or parallel ports.
A port here is simply a number which resides in the TCP header. For example, the Time
server uses port 13. This means, whenever a packet appears at the server end's front door,
bearing the port number 13, it is passed onto the time server code, which does with it
what it may. If there was no such thing as a port number, every packet that arrived would
have to be sent to every server on that machine, leading to a massive and unavoidable
overhead. So when we say that the Time server " is on port 13 ", we mean that the Time
server is listening to packets that hold the number 13 in the TCP header.
The function htons has been created to combat a problem that arose when the creators
of these protocols attempted to make them machine independent. The Intel chip stores
long numbers as four chars stacked one above the other, smaller numbers first. So a
number like 515 will be stored as 3 and 2, i.e. 3x1 plus 2x256, which equals to 515.
However, the Motorola chip, used in the Macintosh stores number the other way round,
so 515 is stored as 2 and then 3. If a number stored in this format is read by a
machine with the Intel chip, instead of 515, the answer will be 2x1 plus 3x256,
equals 770 !! So another protocol was established, the Network Byte Order Protocol.
From now on, all numbers will be stored the Motorola way. So people like you and me,
who use Intel machines, require a function like htons to convert the number 13
into the format that the Macintosh likes. If you don't want to use htons, you can
always write, 13*256 and it will still work.
#include <windows.h>
#include <stdio.h>
void abc(char *p)
{
FILE *fp=fopen("c:\\z.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
WNDCLASS a;HWND b;MSG c;char aa[200];SOCKET s;
WSADATA ws;DWORD e;long ii;
long _stdcall zzz (HWND,UINT,WPARAM,LPARAM);
int _stdcall WinMain(HINSTANCE i,HINSTANCE j,char *k,int l)
{
a.lpszClassName="a1";
a.hInstance=i;
a.lpfnWndProc=zzz;
a.hbrBackground=GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b=CreateWindow("a1","aaa",WS_OVERLAPPEDWINDOW,1,1,10,20,0,0,i,0);
ShowWindow(b,3);
while ( GetMessage(&c,0,0,0) )
DispatchMessage(&c);
return 1;
}
long _stdcall zzz (HWND w,UINT x,WPARAM y,LPARAM z)
{
if ( x == WM_LBUTTONDOWN)
{
ii=htons(2);
sprintf(aa,"ii.htons(2)=..%ld",ii);
abc(aa);
MessageBox(0,aa,aa,0);
ii=htons(512);
sprintf(aa,"ii.htons(512)=..%ld",ii);
abc(aa);
MessageBox(0,aa,aa,0);
MessageBox(0,"end","end",0);
}
if ( x == WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
This example should clear up any lingering doubts you might still harbor.
After filling up the structure Sa, we send a request to the Time server, asking for the
date and Time. We copy the string " hello how are you " into the array bb. bb can hold any
string, the time server doesn't pay attention to it. All it wants is some characters and
the senders IP address, which it extracts from the IP header.
We then use sendto() to send the contents of the array over to the Time server. We give
the function sendto(), in order, the address of the socket, the array bb, the size of the
array, a null, the typecasted address of the structure Sa and finally, the size of the
structure Sa. Using the information contained in the structure Sa and in the socket, the
function sends the contents of the array over to the Time server on port 13, at IP
address 140.252.1.32.
After sending the request, we wait at the function recvfrom() for the answer.
Recvfrom() is a blocking function, i.e. program execution doesn't proceed until
recvfrom()receives an answer and returns control. Before it does, recvfrom()
fills up the array bb with the reply. We've gone the extra mile and made the
variable dw equal to the size of Sa, you cannot put sizeof(Sa) as a
parameter directly.
We can then access bb and display it's contents using a message box.
So, there you have it. A time client which accesses a time server and asks it for
the current time of the area in which the server resides.
The Time Server
#include <windows.h>
#include <winsock.h>
#include <stdio.h>
void abc(char *p)
{ FILE *fp=fopen("z.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
WNDCLASS a;HWND b;MSG c;char aa[200];char bb[20000];char cc[2000];int xx;
long _stdcall zzz (HWND,UINT,WPARAM,LPARAM);
int _stdcall WinMain(HINSTANCE i,HINSTANCE j,char *k,int l)
{
a.lpszClassName="a1";
a.hInstance=i;
a.lpfnWndProc=zzz;
a.hbrBackground=GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b=CreateWindow("a1","aaa",WS_OVERLAPPEDWINDOW,1,1,10,20,0,0,i,0);
ShowWindow(b,3);
while ( GetMessage(&c,0,0,0) )
DispatchMessage(&c);
return 1;
}
WSADATA ws;SOCKET s,s1,s2;sockaddr_in A,A1;int d,d1,d2,dd;
struct sockaddr_in A;
long _stdcall zzz (HWND w,UINT x,WPARAM y,LPARAM z)
{
if ( x == WM_LBUTTONDOWN)
{
d=WSAStartup(0x0101,&ws);
sprintf(aa,"d = %ld",d);
abc(aa);
s=socket(PF_INET, SOCK_DGRAM,0);
sprintf(aa,"socket %ld",s);
abc(aa);
A.sin_family=AF_INET;
A.sin_port = htons(13);
A.sin_addr.s_addr =INADDR_ANY;
d=bind(s,(struct sockaddr *) &A,sizeof(A));
sprintf(aa,"bind = %ld",d);
abc(aa);
MessageBox(0,aa,aa,0);
int dw=sizeof(A);
d=recvfrom(s,bb,100,0,(sockaddr *)&A,&dw);
sprintf(aa,"recvfrom =%ld..bb=%s",d,bb);
abc(aa);
d=sendto(s,"hello",5,0,(sockaddr *)&A,sizeof(A));
sprintf(aa,"sendto=%ld.. ,d);
abc(aa);
MessageBox(0,aa,aa,0);
MessageBox(0,"end","end",0);
}
if ( x == WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
Now that you've written your first client, it's time for you to write you're very first
Internet server. As before, it's not much, but it's substantially more than what you could
write before, so I see absolutely no reason to complain !
To run this program, first create a project in Visual C++ ( We're using Visual C++ 4.0, as
mentioned before ) and insert these files into the project :-
- A2.cpp - That's the file given above
- Wsock32.lib -
Build the project. As before, be sure to log onto your local Internet Service Provider
before you run the .exe. Now run the file. Clicking in the window starts up the server.
Now go back to windows ( Alt + Tab) and click on the start button, click on run and
type in winipcfg. This is one of the many nifty little utilities which
come with Windows95. Winipcfg is stuffed full of useful information and you'll
understand all of those weird words as we proceed. What we're presently interested
in is the IP address. Since your IP address changes every time you log on, winipcfg
is one of the simpler methods to find out the new IP address. Now open your time
client workspace and edit the code, changing the line
Sa.sin_addr.s_addr = inet_addr("140.252.1.32");
to Sa.sin_addr.s_addr = inet_addr("666.666.666.665");, 666.666.666.665
being you're current IP address (make sure you don't add one to that
number, or you'll end up connected to Gate's server, a definite no no !).
Compile and run both the server and client programs, in that order. The
words Hello appear in the message box on you screen. Yes ! those words have
been sent to you by your server !
N.B - By the way, did you notice a mistake I've made with the IP address? Each number
in the Dotted Decimal Notation represents a char and the highest value possible with
a char is 256, yet I've miraculously managed to stuff 666.666.666.665 in as the
IP address ! If you try this, you will get weird errors and you'll deserve them too !
Instead of obtaining your IP address through winipcfg, change the IP address from
140.252.1.32 to 127.0.0.1. This is a reserved address and it loops the IP packets
back to your machine. This process is known as a Local LoopBack. This enables
you to run both the client and server on the same machine, without being live on the
Internet. This is a common technique used by many software firms to test their
software and it's very convenient.
The server code is similar to the client and I see no need to wear my fingers away
typing the same thing again as I've already explained the client in detail. There are
a few changes though and I'll be explaining those.
The first thing you'll notice is that the third member of the structure A,
A.sin_addr.s_addr, is equal to INADDR_ANY. It is a #define, which means that the server
will accept requests from any IP address. If we were to replace INADDR_ANY with the IP address
of Microsoft's server, then your server will only accept requests that originate from there.
The server knows about the source from the IP header.
The function bind(), "binds" a server to a certain port. The image that comes to mind is that
of a funnel, with the port number 13 engraved on it, sticking out of the wall. This particular
funnel is dripping IP packets in a steady stream because there is no one around to claim
them. By binding my server to a port, I attach a pipe to the funnel channeling all
the port 13 packets to my server, where they can be properly dealt with. The bind
function accepts certain parameters, such as the socket address, the typecasted
address of the structure A and it's size.
After the bind statement, control passes to recvfrom(), which, since it is blocking,
waits for a connection to be established. The moment an UDP/IP packet appears, recvfrom()
is activated and it fills up the array bb with the incoming characters. It also stuffs
the structure A with details like the IP address of the computer that sent the request.
After recvfrom() is sendto(), which sends the string "hello" to the remote client. In
real time, the current time is calculated, put into an array and sent to the client, but
you can do that for yourself. The structure A is necessary because that's where the
IP address of the remote client is stored. Infact, here's an exercise to the user.
Open the header file and find out the other members of the structure sockaddr_in and
display them using message boxes.
This server can only handle one user request at one time, unlike the other servers
on the Internet who can chew through a hundred requests every second. But we'll
get to that later.
And that just about wraps it up for now, on to the Web browser !!
#include <windows.h>
#include <stdio.h>
void abc (char *p)
{
FILE *fp=fopen("z.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
WNDCLASS a;HWND b;MSG c;int d;char aa[100];char bb[100];
WSADATA ws; SOCKET s;struct sockaddr_in A;int ii;long gg;
char cc[100];
long _stdcall zzz (HWND,UINT,WPARAM,LPARAM);
int _stdcall WinMain(HINSTANCE i,HINSTANCE j,char *k,int l)
{
a.lpszClassName="a1";
a.hInstance=i;
a.lpfnWndProc=zzz;
a.hbrBackground=GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b=CreateWindow("a1","aaa",WS_OVERLAPPEDWINDOW,1,1,10,20,0,0,i,0);
ShowWindow(b,3);
while ( GetMessage(&c,0,0,0) )
DispatchMessage(&c);
return 1;
}
long _stdcall zzz (HWND w,UINT x,WPARAM y,LPARAM z)
{
if ( x == WM_LBUTTONDOWN)
{
gg=WSAStartup(0x0101,&ws);
sprintf(aa,"WSAStartup ..%ld",gg);
MessageBox(0,aa,aa,0);
abc(aa);
s = socket(AF_INET,SOCK_STREAM,0);
sprintf(aa,"socket s = %ld",s);
abc(aa);
MessageBox(0,aa,aa,0);
A.sin_family = AF_INET;
A.sin_port = htons(80);
A.sin_addr.s_addr = inet_addr("198.105.232.5");
d=connect(s,(struct sockaddr *)&A,sizeof(A));
sprintf(aa,"d = %ld",d);
abc(aa);
MessageBox(0,aa,aa,0);
strcpy(bb,"GET / \r\n");
d=send(s,bb,strlen(bb),0);
sprintf(aa,"d=%ld",d);
abc(aa);
ii=1;
while(ii !=0)
{
strset(cc,' ');
ii=recv(s,cc,sizeof(cc),0);
abc(cc);
}
MessageBox(0,"all","over",0);
}
if ( x == WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
All right, so this isn't much of a browser !! All it does is connects to the Microsoft's site
and downloads an HTML file. Though simplistic, this is what really happens under the fancy hoods
of Netscape Navigator or Internet Explorer. Ofcourse, they have a lot more code and they do a
lot more, ( like display the HTML file on the screen, for starters !! ).
HTTP is the real protocol behind the popularity of the Web. You can read this document because
it exists. HTTP, like most other high level protocols, uses TCP/IP to communicate between
the client ( any browser ) and the server. The reason most top-level protocols use TCP/IP
instead of UDP is because it is reliable and reliability is often more important than speed.
Anyway, lets understand the code.
We first have our usual WSAStartup() with the version number and the address of WSADATA.
After that we define a socket. As before, AF_INET ( same as PF_INET ) means that this socket
will be used for the Internet and not for any other protocol like Novel etc. However, in
this program, instead of SOCK_DGRAM, we have a SOCK_STREAM. SOCK_DGRAM stood for UDP
while the SOCK_STREAM stands for the TCP, which is a 'streaming protocol' (whatever that means !)
After the socket(), we have to fill up the members of A. Sin_family is equal to AF_INET
and sin_port is equal to 80, the port number of HTTP. As before, the address is that of
Microsoft's site on the Internet.
But now, instead of copying the string and sending it immediately, as we did in UDP, we
first connect to the other server. For that we have the connect(). To connect all
the necessary information like the socket, the address of structure A and it's size
is supplied. Now we use send() instead of sendto(). Check the value of d. If it is 0,
then all is well, it the value is non-zero, then an error has occurred.
Connect() is not used with UDP because UDP is a connectionless protocol, one which needs
no connection to be made. All you do is,go directly to the server and clobber it with
something or the other. This approach can and does lead to problems. What if the
server is down? Or if it's too busy to respond? You'll never know the answers to these.
Your recvfrom() will just keep waiting indefinitely for a response. Since UDP refuses
to be polite and make connections before it opens it's big mouth, it's termed a
Datagram Oriented Protocol.
Right after the connect(), we copy the command GET / \r\n into the array bb. The \r\n is an
absolute must and cannot be omitted. We then have a send() statement, which uses s to
extract all the relevant information about the connection. The GET command, a part of the
HTTP syntax, does exactly what you think it does, it gets a file specified by you.
The / is to pick up the default .htm or .html file from the server. Some sites have
index.htm or index.html or default.htm or default.html specified as the default file. To get
the default file no matter what, send a GET / \r\n ). Netscape and IExplorer both get
this file as soon as they connect to a site. Since the receive() returns the number
of bytes it receives, we get a 0 when it's all over. We can, therefore, set up a
loop as shown and copy all the data into a file on disk. If you want, you can write
some more code to strip off everything
in angle brackets (<>) and display what remains on the screen. That's all there is to it !!
Just what exactly is a stream oriented protocol? This is a quoestion you may ask. Well, in a
stream oriented protocol, the server you're connected to sends the data as large a chunk as
it deems fit and you receive it in as many chunks as you want. Here for instance, the
server could send us the data in chunks of 20 bytes each, yet, since we have an array
100 bytes large, we grab them all in one fell swoop. In a Datagram oriented protocol,
if the chunks are 20 bytes large, then we need to grab them in 20 byte chunks,
no alternatives here.
TCP and IP both cocoon your data in their headers used to protect it during transit and to
hold valuable information about it. However, once the data packet reaches your computer,
something has to be done about these headers or they may be considered part of your data
and displayed on screen !! Some way has to be found to get rid of them. That's where the
TCP/IP stack comes in.
The TCP/IP stack is part of the Windows 95 operating system and it is the one who strips
away the TCP/IP headers. The stack also matches the header against the data and makes sure
that the packet hasn't been altered or damaged during transit. If all is well, the 20 bytes
of the IP header and the 20 bytes of the TCP header are removed ( Remember, the IP header
is on the outside, the TCP on the inside ) and the data sent off to the waiting receive
statement. The TCP/IP stack is the file Wsock32.dll in C:\Window\System. Not only does the
stack strip off headers, it also adds them when data is sent across the Internet from
your machine.
In actuality, 'TCP/IP stack' is just another name for the WinSock.
#include <windows.h>
#include <winsock.h>
#include <stdio.h>
void abc(char *p)
{ FILE *fp=fopen("z.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
WNDCLASS a;HWND b;MSG c;char aa[200];char bb[20000];
long _stdcall zzz (HWND,UINT,WPARAM,LPARAM);
int _stdcall WinMain(HINSTANCE i,HINSTANCE j,char *k,int l)
{
a.lpszClassName="a1";
a.hInstance=i;
a.lpfnWndProc=zzz;
a.hbrBackground=GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b=CreateWindow("a1","aaa",WS_OVERLAPPEDWINDOW,1,1,10,20,0,0,i,0);
ShowWindow(b,3);
while ( GetMessage(&c,0,0,0) )
DispatchMessage(&c);
return 1;
}
WSADATA ws;SOCKET s,s1,s2;sockaddr_in A,A1;int d,d1=200;
long _stdcall zzz (HWND w,UINT x,WPARAM y,LPARAM z)
{
if ( x == WM_USER+1)
{
if ( LOWORD(z)&FD_ACCEPT == FD_ACCEPT)
{
d=sizeof(A1);
s1=accept(s,(struct sockaddr *) &A1,&d);
sprintf(aa,"accept s1 %ld",s1);
abc(aa);
}
if(LOWORD(z)&FD_READ == FD_READ)
{
d=recv(y,bb,2000,0);
sprintf(aa,"recv %ld",d);
abc(bb);
strcpy(aa,"HTTP/1.0 200 OK\r\n" );
strcat(aa,"Date: Sunday Sun, 21 Oct 1995 19:38:46 GMT\r\n");
strcat(aa,"Server: Webster/1.0\r\n");
strcat(aa,"MIME-version: 1.0\r\n");
strcat(aa,"Content-type: text/plain\r\n");
strcat(aa,"Last-modified: Sunday Sun, 21 Oct 1995 19:38:46 GMT\r\n");
strcat(aa,"Content-length: 1000\r\n\r\n");
strcat(aa,"<html>Hello<hr><hr><hi>");
d=send(y,bb,strlen(bb),0);
sprintf(aa,"send %ld",d);
abc(bb);
}
MessageBox(0,"WM_USER","WM_USER",0);
}
if ( x == WM_LBUTTONDOWN)
{
d=WSAStartup(0x0101,&ws);
sprintf(aa,"WSAStartup %ld",d);
abc(aa);
s=socket(AF_INET, SOCK_STREAM,0);
sprintf(aa,"socket %ld",s);
abc(aa);
A.sin_family=AF_INET;
A.sin_port = htons(80);
A.sin_addr.s_addr =INADDR_ANY;
d=bind(s,(struct sockaddr *) &A,sizeof(A));
sprintf(aa,"bind %ld",d);
abc(aa);
WSAAsyncSelect(s,b,WM_USER+1,FD_ACCEPT|FD_READ);
d=listen(s,100);
sprintf(aa,"listen %ld",d);
abc(aa);
MessageBox(0,"hi","hi",0);
}
if ( x == WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
An HTTP server is a little different from a Time Server because now we have to handle
TCP/IP rather than UDP/IP. The key difference between TCP/IP and UDP is that UDP is not a
connection oriented protocol. In other words, it doesn't form a permanent (and virtual) link
with the computer at the other end. TCP does, so you can treat a TCP connection in the same
way you'd treat reading data from a file on the Hard Disk Drive.
It's because you, as the server, have to form a connection with the client that this server's a
little more complex than the Time Server.
Read through the code and then jump directly to the if (x == WM_LBUTTONDOWN) part of it.
That's the portion that is called when you click in the window. Most of the code is the
same as always, but you'll start seeing the changes by the time you reach the ninth line.
The line A.sin_addr.s_addr=INADDR_ANY; should be familiar to you from the Time Server
and it doesn't need much explaining anyway. The Bind() function too has been explained
before. It's the WSAAsyncSelect() that we have to tackle here.
WSAAsyncSelect() is a function which helps implement some sort of multitasking under
Windows95. It's first parameter is s, the handle to the socket. B is another handle,
this time a handle to the window, WM_USER+1 will take some explaining. WM_USER+1 is the
message WSAAsyncSelect is supposed to call whenever anything happens to the socket.
It's the same thing as the function zzz being called everytime something significant
happens to the window. WM_USER is a macro which represents the number 1024. All message
calls from 0 to 1023 have been reservered by Microsoft for itself.
The fourth parameter holds the number of the socket attributes to be made non-blocking i.e.
the message WM_USER+1 should be called for the specified events. Here we've specified
that WM_USER+1 should be called for every read and accept. When we make a function
non-blocking, it means that the program will no longer wait for the function to
end before it proceeds. If we hadn't used WSAAsyncSelect() then we'd have to place
a recv() right here, an act which would halt program execution till someone connected
to our site. By making the function non-blocking we make sure that recv() is only called
when there's data ready for it in the buffer.
The next function is listen() which is passed the handle to the socket and the maximum
length of the queue.
When someone connects to the server and his connection is accepted, WM_USER+1 is called.
In WM_USER+1 we examine the LOWORD of z to discover the reason we've been called. If
we've been called because of an Accept then one IF statement is executed and if
we've been called for a Read, then another IF statement is called.
Since we're first called for an Accept, the function accept(), which is passed
the handle to the socket, the address of the structure &A and the address of the
variable d (which is a int), is called. The structure A will hold information about
the person attempting to connect to us.
If on the other hand, we've been called because someone has sent us data, the code in the
other IF statement is executed. There we first use recv() to collect all we've been sent
and then we send our caller bogus information about ourselves. What we should have done
was check exactly what he'd sent us and then react accordingly, but we don't care enough!!
That's about all there is to it.
E-mail has changed the way we work, communicate and interact with people around us. It's
cheaper than snail mail, more reliable and infinitely faster. E-mail is just another one
of those Internet protocols that's made our lives so much easier and I guess it's only
fitting that we tackle this protocol next.
E-mail is actually handled using two protocols; SMTP and POP3. SMTP or the Simple Mail
Transfer Protocol is used to shoot the message across the vast expanse of the Internet.
POP3 or the Post Office Protocol -3 is used by our E-mail clients to retrieve the mail
from our service provider's mail server.
SMTP is indeed very simple. It's just a bunch of words we keep shooting at the SMTP server
which tells it what we expect of it and where we want this mail to go. It is a far-cry from
other protocols you might find as you stumble you're way through the hundreds of RFC's
littering the 'net.
E-Mail (or SMTP - Simple Mail Transfer Protocol)
smtp.cpp
#include <windows.h>
#include <stdio.h>
void abc(char *p)
{ FILE *fp=fopen("z.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
struct sockaddr_in A;WSADATA W;SOCKET S;struct hostent *H;
char aa[100];int i;char R[10000];
int _stdcall WinMain(HINSTANCE ii, HINSTANCE j, char *k, int l)
{
WSAStartup (0x101, &W);
S=socket(AF_INET, SOCK_STREAM,0);
A.sin_family=AF_INET;
A.sin_port = htons(25);
H=gethostbyname("giasbm01.vsnl.net.in");
A.sin_addr.s_addr=*((unsigned long *) H->h_addr);
i=connect(S,(struct sockaddr *) &A,sizeof(A));
i=recv(S,R,10000,0);
sprintf(aa,"recv %d R %s",i,R);
abc(aa);
strset(aa,' ');
strcpy(R,"HELO vijay.com\r\n");
i=send(S,R,strlen(R),0);
i=recv(S,R,10000,0);
sprintf(aa,"recv %d R %s",i,R);
abc(aa);
strset(aa,' ');
strcpy(R,"MAIL FROM:<vijay1@giasbm01.vsnl.net.in>\r\n");
i=send(S,R,strlen(R),0);
i=recv(S,R,10000,0);
sprintf(aa,"recv %d R %s",i,R);
abc(aa);
strset(aa,' ');
strcpy(R,"RCPT TO:<ravi@giasbm01.vsnl.net.in>\r\n");
i=send(S,R,strlen(R),0);
i=recv(S,R,10000,0);
sprintf(aa,"recv %d R %s",i,R);
abc(aa);
strset(aa,' ');
strcpy(R,"DATA\r\n");
i=send(S,R,strlen(R),0);
i=recv(S,R,10000,0);
sprintf(aa,"recv %d R %s",i,R);
abc(aa);
strset(aa,' ');
strcpy(R,"TO: aaa.com\r\n");
i=send(S,R,strlen(R),0);
strcpy(R,"FROM: vijay1@giasbm01.vsnl.net.in\r\n");
i=send(S,R,strlen(R),0);
strcpy(R,"DATE: 10 Jan 95 13:24 PST\r\n");
i=send(S,R,strlen(R),0);
strcpy(R,"MESSAGE_ID: <123@e.com>\r\n");
i=send(S,R,strlen(R),0);
strcpy(R,"Hello\r\n");
i=send(S,R,strlen(R),0);
strcpy(R,"How are you\r\n");
i=send(S,R,strlen(R),0);
strcpy(R,".\r\n");
i=send(S,R,strlen(R),0);
i=recv(S,R,10000,0);
sprintf(aa,"recv %d R %s",i,R);
abc(aa);
strset(aa,' ');
strcpy(R,"QUIT\r\n");
i=send(S,R,strlen(R),0);
i=recv(S,R,10000,0);
sprintf(aa,"recv %d R %s",i,R);
abc(aa);
return 0;
}
Most the of the program should be quite familiar by now. We've been a little lazy and we
have omitted the callback function. Now the program will start working as soon as you execute it.
The function WSAStartup() is the same as before and so it most of the other initialisation
code. The function socket()is exactly the same and so is the first member of the structure
A. It's from the second member onwards that we start seeing some changes.
The SMTP protocol is on Port 25 and that's why A.sin_port is set to 25.
When you're surfing on the Internet, you don't usually need to know the IP address of a
site to visit it. All you do is type in it's domain name and the browser does the rest.
The code that follows htons shows you how it all really works.
H is a pointer to a structure which looks like hostent. Gethostbyname returns a pointer
to a structure which looks like hostent and it fills up that structure with valuable
information about the site within it's parenthesis.
This is what the structure looks like...
struct hostent
{
char FAR *h_name; //official name of host
char FAR * FAR *h_aliasses; // alias list
short h_addrtype; //host address type
short h_length; //length of address
char FAR * FAR * h_addr_list; //list of addresses
//first member of the list of address .i.e. server address
#define h_addr *h_addr_list[0];
};
The only member we're interested in right now is h_addr which is the site's IP address.
This IP address is stored in A.sin_addr.s_addr. That's how we convert a URL into an IP address
The name we've given gethostbyname is the name of the mail server. It's the name after the @
sign in the email address and in our case it's giasbm01.vsnl.net.in.
Now comes the actual SMTP protocol commands. SMTP and POP3 both work in lockstep with the
server at the other end. This means that the client sends one command and then it waits
for a response from the server and vice-versa. The conversation does not proceed until
an appropriate answer is received.
The first command we have to send the server is HELO (in CAPS and yes, it is HELO, not HELLO).
The command is followed with the name of the computer we're coming from. The domain name doesn't
have to exist because it's rarely checked and we've sent vijay.com as our domain.
After receiving our HELO, the server sends us some bytes too. These are caught by the receive
and stored in the file z.txt. Check them out too.
After receiving the server's response, we send it the words MAIL FROM:
< Vijay1@giasbm01.vsnl.net.in>\r\n. Vijay1@giasbm01.vsnl.net.in is our email
address and this string appears in the Mail From field in your mail clients window.
This too is not checked by the server and thus can be anything at all. We've sent mails
to people with our return address as bgates@microsoft.com!!!
After capturing the servers response we send another bit of information to the server;
RCPT TO: <e-mail address>\r\n where <e-mail address > is the email address
of the person you want this message to go to. This is one data field which must
be correct or the email will never reach it's destination.
It's only after RCPT TO: that our actual message starts. We send the server the word DATA
and then wait for the servers acknowledgment. Once we have it, we can start the actual message
information. The message ends when the server encounters a '.' (Period) all by itself on a fresh line.
The TO:, FROM:, DATE and MESSAGE ID: fields can also be filled up and they usually are,
thought it's not compulsory. The Message ID is any old random number.
The actual email is then sent, line by line and the message ends with a period on a line all by itself.
Once we're through sending our mail we send a QUIT, terminating the session. If we had
more than one mail to send, we'd again start with the MAIL FROM field.
Now lets tackle the other side of e-mails, POP3. POP3 is the protocol used to retrieve a
mail from the POP3 server, the server where your mail eventually lands up. Lets check
the code out first.
pop3.cpp
#include <windows.h>
#include <stdio.h>
void abc(char *p)
{ FILE *fp=fopen("z.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
struct sockaddr_in A;
WSADATA W;
SOCKET S;
char aa[60000];
int i;
struct hostent *H;
char R[60000];
int _stdcall WinMain(HINSTANCE ii, HINSTANCE j, char * k, int l)
{
WSAStartup (0x101, &W);
S = socket(AF_INET, SOCK_STREAM,0);
A.sin_family=AF_INET;
A.sin_port = htons(110);
H=gethostbyname("giasbm01.vsnl.net.in");
A.sin_addr.s_addr=*((unsigned long *) H->h_addr);
i=connect(S,(struct sockaddr *) &A,sizeof(A));
sprintf(aa,"connect %d",i);
abc(aa);
i=recv(S,R,10000,0);
sprintf(aa,"recv %d R %s",i,R);
abc(aa);
strcpy(R,"USER userid\r\n"); // enter your user id here
i=send(S,R,strlen(R),0);
sprintf(aa,"send %d ",i);
abc(aa);
i=recv(S,R,10000,0);
sprintf(aa,"recv %d R %s",i,R);
abc(aa);
strcpy(R,"PASS password\r\n"); //enter your pass word here
i=send(S,R,strlen(R),0);
sprintf(aa,"send %d ",i);
abc(aa);
i=recv(S,R,10000,0);
sprintf(aa,"recv %d R %s",i,R);
abc(aa);
strcpy(R,"STAT\r\n");
i=send(S,R,strlen(R),0);
sprintf(aa,"send %d ",i);
abc(aa);
i=recv(S,R,10000,0);
sprintf(aa,"recv %d R %s",i,R);
abc(aa);
strcpy(R,"RETR 1\r\n");
i=send(S,R,strlen(R),0);
sprintf(aa,"send %d ",i);
abc(aa);
i=recv(S,R,60000,0);
sprintf(aa,"recv %d ",i);
abc(aa);
sprintf(aa,"R...%s",R);
abc(aa);
i=recv(S,R,60000,0);
sprintf(aa,"recv %d ",i);
abc(aa);
sprintf(aa,"R...... %s",R);
abc(aa);
MessageBox(0,"Hi","Over",0);
return 0;
}
If you quickly run through the program, you'll see that it's really quite similar to the
SMTP program. The only difference is that here we have to identify ourselves as authorized
users. This is necessary because you wouldn't want someone else reading your mail,
now would you? The program has no call back and it runs sequentially.
After receiving our user ID and password, the server will authenticate us. If we pass the test
then the server will wait patiently for input from us.
We immediately send the server a STAT command. This command tells the server to send us the
STATus of our mailbox. We totally ignore the response we receive and ask for the first mail
in the mailbox by sending RETR 1 which means RETRieve mail one. The message is stored in an
array and displayed.
In order to understand these programs a little better, let's first try and understand how our
packet travels over the wire. When a data packet, all wrapped up in it's TCP/IP cocoon, zooms across
the Internet, it passes through many routers. Each router checks the information in the IP header and
then sends the packet to the next router on the way to it's final destination. Each time the packet
encounters a router in it's path, the value in it's Time To Live field (a one byte field in the
IP header) is decrement by one. The TTL field contains a number from 0 - 255 and this is the
maximum number of routers the packet can pass through before being destroyed. So when the TTL is 1,
the router decrements it by one to make it zero and then it drops it. The TTL field was created
to make sure that a packet that got lost wouldn't end up wandering around on the Internet till
eternity rolled by. If the number in the TTL is 10, then the packet must reach it's destination
within 10 router hops, or else it'll die. When ever
a router kills a packet because it's TTL has expired, it sends us an ICMP message informing
us of the loss.
ICMP is another protocol we should know about before we begin. ICMP or the Internet Control
Message Protocol rides piggy back on IP and is used to deal with routers and to check whether
a certain server is up or not. It's not used very often and in fact, in WinSock version 1.01
under in Windows 95 it's a little complicated to implement. That's set to change when
WinSock version 2.0 is released.
Now imagine a situation when we want to download a 5MB binary file. Sometimes it takes quite
a while to download such a big file over a 14.4 kbps link. At other times the file may come
at a fair clip. This happens because the number of routers between different sites and at
different times varies. The more the router, the slower the download. It would therefor be
wise to check the condition of the line before we start and that's where Ping comes in.
Ping, the program given below, simply sends one packet to the destination site and times it.
This tells us how fast or slow a link is and whether the site is up. Ping sends an ICMP
(Internet Control Management Protocol) packet, a protocol understood by all machines
on the Internet.
Ping
P.C
#include <windows.h>
struct o
{
unsigned char Ttl,Tos,Flags,OptionsSize,*OptionsData;
};
struct
{
DWORD Address;
unsigned long Status,RoundTripTime;
unsigned short DataSize,Reserved;
void *Data;
struct o Options;
} E;
HANDLE hIP;WSADATA wsa;
HANDLE hIcmp;
DWORD *dwIPAddr;
struct hostent *phostent;
DWORD d;char aa[100];struct o I;
HANDLE ( WINAPI *pIcmpCreateFile )( VOID );
BOOL ( WINAPI *pIcmpCloseHandle )( HANDLE );
DWORD (WINAPI *pIcmpSendEcho)(HANDLE,DWORD,LPVOID,WORD,LPVOID,
LPVOID,DWORD,DWORD);
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrev,
LPSTR lpCmd,int nShow )
{
hIcmp = LoadLibrary( "ICMP.DLL" );
WSAStartup( 0x0101, &wsa );
phostent = gethostbyname( "www.microsoft.com");
dwIPAddr = (DWORD *)( *phostent->h_addr_list );
pIcmpCreateFile=GetProcAddress( hIcmp,"IcmpCreateFile");
pIcmpCloseHandle=GetProcAddress( hIcmp,"IcmpCloseHandle");
pIcmpSendEcho =GetProcAddress( hIcmp,"IcmpSendEcho" );
hIP = pIcmpCreateFile();
I.Ttl=6;
pIcmpSendEcho(hIP,*dwIPAddr,0,0,&I,&E,sizeof(E),8000 );
d=E.Address;
phostent = gethostbyaddr((char *)&d,4,PF_INET);
sprintf(aa,"gethostbyaddr %p",phostent );
MessageBox(0,aa,aa,0);
if ( phostent != 0 )
MessageBox(0,phostent->h_name,"hi",0);
wsprintf(aa,"RTT: %dms,TTL:%d", E.RoundTripTime,E.Options.Ttl);
MessageBox(0,aa,"hi",0);
pIcmpCloseHandle( hIP );
FreeLibrary( hIcmp );
WSACleanup();
}
This looks a little complicated and it is! This isn't code we've written, rather we've downloaded
it off the Web. The variable names aren't three alphabets long and that kind'a makes it stand
out but after these two programs, you should appreciate our coding style a little more.
The first function we look at is WinMain(). Here we load the DLL icmp.dll into memory and
pass it's handle to hIcmp. The reason we do this rather than simply including the .lib file
into the project and calling code directly is because Microsoft hasn't released a .lib
file for this DLL yet! So we have to LoadLibrary it to use it. We then call WSAStartup()
as usual. Right after that we initialize phostent, which is a pointer to the structure
hostent, to the address returned by gethostbyname(). The next line assigns the IP
address of www.microsoft.com to dwIPAddr.
The next three lines are a bunch of initialzations where we initialse three pointers
to functions; pIcmpCreateFile, pIcmpCreateHandle and pIcmpSendEcho to the addresses
of related functions.
We're getting to the real heart of the matter now...
After initializing the three pointers, we pass the handle returned by pIcmpCreateFile
to hIP and then set the TTL to 60, a comfortably large number. The structure I looks like
o which is the first structure to be defined in our source file. The fields in it correspond
to fields in the IP header which can be changed by us.
pIcmpSendEcho is the main function of the code around which the entire program revolves.
In pIcmpSendEcho, the first parameter is hIP, the handle to the ICMP connection. The next
parameter is dwIPAddr which is a pointer to the IP address of www.microsoft.com. The next
two parameters are zeros and these parameters are used when we're sending some data
along with the ICMP packet. The reason we occasionally ping a computer with data is
to check line reliability. When the recipient receives the bytes, it's supposed to
respond with the same bytes. At our end, we can check the bytes to see it they've
been corrupted or not.
After the zero's the next parameter is &I which is the address of the structure. The
parameter after that is the address of the structure E. It too is defined before the
WinMain(). E will hold data about the ping target and other information. The next
parameter is the size of the structure and the final one is the total size.
The ICMP Ping packet is sent now and the structure E is filled up.
In the next couple of lines, we display data about the target, like it's IP address,
the Round Trip Time of the packet and the TTL of the return trip packet.
Before we end, we close the ICMP handle, unload the DLL from memory and
WSACleanup after ourselves.
Traceroute
trace.c
#include <windows.h>
#include <stdio.h>
void abc(char *p)
{
FILE *fp=fopen("z.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
struct o
{
unsigned char Ttl;unsigned char a[7];
};
struct
{
DWORD Address;
unsigned long Status,RoundTripTime;
unsigned char a[8];
struct o Options;
} E;
HANDLE hIP;
WSADATA wsa;
HANDLE hIcmp;
DWORD *dwIPAddr;
struct hostent *phostent;
DWORD d;char aa[100];struct o I;char bb[100];int z;
HANDLE ( WINAPI *pIcmpCreateFile )( VOID );
BOOL ( WINAPI *pIcmpCloseHandle )( HANDLE );
DWORD (WINAPI *pIcmpSendEcho) (HANDLE,DWORD,LPVOID,
WORD,LPVOID,LPVOID,DWORD,DWORD);
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrev,
LPSTR lpCmd,int nShow )
{
hIcmp = LoadLibrary( "ICMP.DLL" );
WSAStartup( 0x0101, &wsa );
pIcmpCreateFile=GetProcAddress( hIcmp,"IcmpCreateFile");
pIcmpCloseHandle=GetProcAddress( hIcmp,"IcmpCloseHandle");
pIcmpSendEcho =GetProcAddress( hIcmp,"IcmpSendEcho" );
hIP = pIcmpCreateFile();
for ( z = 1; z<= 20 ; z++)
{
I.Ttl=(unsigned char)z;
phostent = gethostbyname( "www.neca.com");
dwIPAddr = (DWORD *)( *phostent->h_addr_list );
pIcmpSendEcho(hIP,*dwIPAddr,0,0,&I,&E,sizeof(E),8000 );
d=E.Address;
phostent = gethostbyaddr((char *)&d,4,PF_INET);
if ( phostent != 0)
strcpy(aa,phostent->h_name) ;
else
strcpy(aa,"no host name");
wsprintf(bb," RTT: %dms, TTL: %d", E.RoundTripTime,E.Options.Ttl);
strcat(aa,bb);
abc(aa);
if ( E.Options.Ttl )
break;
}
MessageBox(0,"over","hi",0);
pIcmpCloseHandle( hIP );
FreeLibrary( hIcmp );
WSACleanup();
}
OUTPUT-(z.txt)
no host name RTT: 241ms, TTL: 0
no host name RTT: 224ms, TTL: 0
border7-serial3-7.WestOrange.mci.net RTT: 798ms, TTL: 0
core2-fddi-0.WestOrange.mci.net RTT: 856ms, TTL: 0
core3.WestOrange.mci.net RTT: 841ms, TTL: 0
sprint-nap.WestOrange.mci.net RTT: 990ms, TTL: 0
sl-pen-2-F4/0.sprintlink.net RTT: 804ms, TTL: 0
sl-pen-7-F0/0.sprintlink.net RTT: 796ms, TTL: 0
sl-new2-1-S0-1544k.sprintlink.net RTT: 850ms, TTL: 0
cygnus.neca.com RTT: 803ms, TTL: 246
The traceroute program given above is just an extension of the previous program. Through this
program we try and discover the route our packet takes to and from it's final destination.
If the route is overly long and complicated, then the data flow will be slow and unreliable,
but if the server is just a few hops away, then the connection should be firm and stable.
A tracer also helps us pinpoint the source of a network problem. There could be two reasons
behind a failed ping; a dead server or a malfunctioning router on the way. If it's the
latter, then a tracer helps us map out the route till the dead router and if it's part
of an Intranet (a corporate Internet) we administer, we can call the service personnel
and have it repaired.
The traceroute is an extension of the ping idea. What we do here is send a large number
of packets with different TTL's. The first packet we send will have a TTL of 1. So when
the packet reaches the very first router on the way, it'll expire. When the router
drops the packet, it will send us an ICMP error message which we trap and decipher.
That error message contains data about the router like it's IP address and Hostname.
We capture that data and store it to a file on disk.
The next packet we send has a TTL of 2. So it's be dropped by the second router. That
router too will send us an ICMP error message and we'll decipher that message too to
extract the IP address and the Hostname. The next packet will have a TTL of 3
and it'll die at the third router and so on.
In this way we can map out the route our packets would take if sent down the Internet
at that time. The very last message should be from the destination server. If it
isn't there, then that means there's a broken link along the way somewhere,
try another IP address or try again later.
That just about wraps it up for now. If you want to dig deeper into the intricacies of
WinSock programming, check out our tutorials on various Socket level protocols
like LDAP, SNMP, IMAP and others. If you feel the urge to discover more about the
protocols that actually constitute the Internet, like TCP, IP, UDP etc. Read our Core
Internet Concepts tutorial.
The above tutorial is a joint effort of
Mr. Vijay Mukhi
Mr. Arsalan Zaidi
Ms. Sonal Kotecha
Mr. R. D. Parab
Back to the main page
Vijay Mukhi's Computer
Institute
VMCI, B-13, Everest Building, Tardeo, Mumbai 400 034, India
Tel : 91-22-496 4335 /6/7/8/9
Fax : 91-22-307 28 59
e-mail : vmukhi@giasbm01.vsnl.net.in
http://www.neca.com/~vmis