Winsock - A Guided Tour

From Web (09.06.1997)

Table of Contents

1. Preamble

This page is in Pre Alpha. That means no grammer checks, no editting and speeling mistakes galore! The explanations and the final version will come soon. Check it out at your own risk!

2. A Guided Tour

Open Netscape and type www.microsoft.com in the Location text box and press enter. Wait for a few seconds and what happens after that is some what similar to what happened when Alibaba said 'open sesame'. The world of Internet is full of amusing, exciting and informative things. There is something for everyone. The Internet has revolutionized the way we communicate, it's faster and it's cheaper. It is going to affect everyone's life some way or another. One of the by-products of any new technology, and the Internet is no exception, is lots of new jargon. Knowing more jargon doesn't really mean you know more than the guy next door. So rather than adding to our list of jargons, it would be a better idea to learn about things like writing an E-mail server, a browser or an FTP client. Hang on, hang on, we really mean it, you can do it. And not only this but much more.

'Tutorial' may not be the right word for what follows next. So we will call it a Guided Tour to Sockets programming. So lets fasten our belts and sit tight, as we are about to begin a most exciting tour.

3. Basics of...

Before we start off with our first 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, just 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, we pick up our phone in Bombay and dial up someone in Delhi. Is our phone directly connected to the phone in Delhi by a long wire running up from our phone to the other phone? The answer is no. The connection can be considered direct, but only in the loosest way. What we actually have here is a connection which only lasts for as long as the communication itself. Even the route our voice takes along the wire can vary, not only between one call and the next, but also within a call. So one moment our 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 route our TCP/IP packets take vary. One moment they'll come down one pathway and a few seconds later, by another. This is known as routing. This routing of information packets is what information transfer on the 'net is based on. The router is what telephone companies spend the most 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. In fact, 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) explained 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 a binary file 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 pre-defined rules.

The TCP/IP protocol is actually two protocols sandwiched one above the other. The IP (Internet Protocol) deals exclusively with the routers. It's IP's job 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. IP has no mechanism by which it can tell us that a given packet has actually reached its destination.

It was to combat this problem of unreliability, that the TCP ( Transmission Control Protocol ) was introduced. The TCP is the exact opposite of the IP. 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 the destination and is used in the correct order.

When TCP/IP was invented, the architects made it quite clear that TCP/IP would be entirely hardware 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 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, learning to weave straw baskets !!

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 from and to your hard disk. So we'll be teaching you WinSock programming, not direct TCP/IP.

4. Browser, Ah nearly...

Lets not waste anymore time over theoretical discussions about how the Internet works. Instead, lets jump right in and we promise we'll explain all the important concepts as we go along. After all, it makes more sense to explain the theory after you've seen the source code and tried it out for yourself.

We have always believed in something called step by step learning. Some would say this would increase the learning curve, But at the end of the day, you would appreciate it because by then you would have understood the technology better.

Note:WSock32.lib has to be included in project before building the EXEs

Program #1
httpc.cpp

#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[100];char bb[100];char cc[100];
WSADATA ws;SOCKET s;int ii;long gg;struct sockaddr_in A;
char hh[]="HTTP/1.0\r\n""User-Agent:AuthClient\r\n""Accept:*/*\r\n";
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);
    A.sin_family=AF_INET;
    A.sin_port=htons(80);
    A.sin_addr.s_addr=inet_addr("202.54.3.20");
    d=connect(s,(struct sockaddr*)&A,sizeof(A));
    sprintf(aa,"d=%ld",d);
    abc(aa);
    strcpy(bb,"GET / ");
    strcat(bb,hh);
    strcat(bb,"\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(ii);
    }
  }
  if ( x == WM_DESTROY)
    PostQuitMessage(0);
  return DefWindowProc(w,x,y,z);
}

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

1. httpc.cpp - This is the file displayed below.

2. Wsock32.lib - This is a lib file located in Drive:\msdev\lib\.

Build the project. Before you run the EXE, be sure to log onto 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.

This is it ! your very first Internet Client ! It doesn't seem like much!! We have neglected to put any padding on this program, it's just the bare code and the user interface is absolutely pukey. But it works and that's what counts.

The above program will connect to a web server and get the default home page of the same when you click in the window aaa. When you click in the window the Callback Function zzz gets called. The function zzz contains most of the Internet related code.

gg=WSAStartup(0x0101,&ws);

This function expects the version number of the wsock32.dll we intend to use, as the first parameter (we'll be using 1.01). The second parameter is the address of the structure which looks like WSADATA. All that WSAStartup() does is loads wsock32.dll into memory and fill up the structure 'ws'.

This is the most important function in this code. If this line is not there then nothing is going to work. If successful, this function will return 0. The next three lines actually show us the value of gg, and then dump this value into z.txt.

sprintf(aa,"WSAStartup..%ld",gg);
MessageBox(0,aa,aa,0);
abc(aa);

As we want to talk to other computers on the network, we have to create a socket. The function socket() is called with three parameters. The first parameter AF_INET simply means we want to use this program on the Internet. WinSock sockets can also be used over Novell and other networks and therefore the intended use has to be specified. The second parameter, SOCK_STREAM means TCP. TCP is a connection based protocol, i.e., a connection must be established before any information can be exchanged. The function will return a value which is a handle to the socket that we have just created. This handle will be used later to refer to the socket.

s=socket(AF_INET,SOCK_STREAM,0);
sprintf(aa,"Socket s=%ld",s);
abc(aa);

We have already created a structure A which looks like sockaddr_in. We'll initialize members of this structure as shown below. To understand the second member i.e. sin_port, we have to first understand something about ports. When one computer wants to talk to another, it communicates through a port. 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 avoidable overhead. So when we say that the HTTP server " is on port 80 ", we mean that the HTTP server is listening to packets that hold the number 80 in the TCP header.

IANA (Internet Assigned Numbers Authority) is the body which has standardized these ports by actually associating each of the ports with a different number. For example port number 80 is HTTP. The function htons() converts little endian numbers to big endian numbers. The last parameter is the protocol number which is usually set to 0.

Next we will initialize the third member with the IP address of our favorite site. The function Inet_addr fills up this member of the structure with the IP address of the destination server. 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. An IP address is a bit like a phone number. For me to be able to talk to you, I have to have a phone ( with its own number ) and I have to know your phone number. To be on the Internet, every computer has to have an IP address, otherwise the packets don't know where to go. A unique IP address, which is a long number ( 32 bits ), is give to each and every computer on 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 which is stable only for as long as the session lasts.

A.sin_family=AF_INET;
A.sin_port=htons(80);
A.sin_addr.s_addr=inet_addr("202.54.3.20");

We are finally ready with all the preliminary settings required before making a connection. To make a connection we call the function connect with the handle of the socket, s and all the additional information which will be required. If the function is successful, it returns a 0. Connect is a blocking function; that means the program will wait at connect till it finishes. That means all subsequent commands have to wait till connect has sent it's data.

d=connect(s,(struct sockaddr*)&A,sizeof(A));
sprintf(aa,"d=%ld",d);
abc(aa);

At this point we send a request to the server. GET / is an HTTP command which is our way of asking for the default HTML file.

strcpy(bb,"GET /");
strcat(bb,hh);
strcat(bb,"\r\n");
d=send(s,bb,strlen(bb),0);
sprintf(aa,"d=%ld",d);
abc(aa);
ii=1;

This last loop will make sure that we receive the entire HTML page.

while(ii!=0)
{
  strset(cc,' ');
  ii=recv(s,cc,sizeof(cc),0);
  abc(ii);
}

Finally what we have is a HTML file which is nothing but a plain text file with HTML tags. If you don't believe what we say open file z.txt and see for yourself. Now if we can write some code to interpret these HTML tags then we have a Browser.

5. ... Pages, more pages

Now that you've written your first client, how about writing your very first Internet server. When we start Netscape and type in www.microsoft.com, we see a good looking screen with lots of information about Microsoft. So lets write an HTTP server.

An HTTP server is not very difficult. A user asks for a page and you send it. What we have to understand is that we are not the only people requesting the page, there could be hundreds of people who also want to access the page at the same time. All of this has to be handled by the server.

As before, it's not much, but it's substantially more than what you could write before, so we see absolutely no reason to complain !!

Program #2
https.cpp

#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,"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);
}

As earlier, build the project and run the exe file. Click in the window. If you see a MessageBox saying hi, then you can be rest assured that you server is up and running. The code is some what similar to the HTTP client.

After creating the socket we fill up the structure sockaddr_in. The last member of the structure i.e. A.sin_addr.s_addr is initialized with the value INADDR_ANY. When we are running a server we expect lots of people to connect to our server from various IP addresses. INADDR_ANY tells the server that anybody can connect to it. As HTTP servers receive requests on port number 80 we have to bind our server to that port. What this means is whenever the server receives a packet with port number 80, it means the server has to process the packet.

If the server has to attend to more than one client request we have to make all the blocking functions non-blocking. For this reason we implement the function WSAASyncSelect(). WSASyncSelect requires four parameters, the handle of the socket s, the handle of the window a1, and a macro, WM_USER. Whenever we want to send our own message to the specified window then we use a number greater than WM_USER. Microsoft has reserved all the messages up to WM_USER. The last parameter is what event we want to trap e.g. FD_READ, FD_ACCEPT etc. Now blocking functions are made non-blocking by using WASASyncSelect(). A server can't send packets unless it gets a request from the client. Till that moment the server listens at the port. Listen is a blocking function, but as we have used WSASyncSelect() it makes it non-blocking. The moment the port gets a packet with port 80, the server send a WM_USER+1 message to the a1 window with FD_ACCEPT.

The code in the callback zzz simply checks if the request is an FD_ACCEPT and then transfers control to the another socket s1. Socket s is now free to listen to new requests from some other IP address. If the request is an FD_READ then the callback starts sending the data i.e. a html page, using the new socket s1. Try this program out with earlier client program.

6. What's the time, please...

Now that we have some knowledge of sockets under our belt, and that we are more confident than when we had started let's see what's the time around the world. The time that our time client program will show us is the time at the server.

\*-----------------------------------------------------------------
Program #3
timec.cpp
WinSock.lib has to be included in project before building the EXE
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);
}

Build the project. Make sure you are logged onto Internet before you run the .exe file. Clicking in the window starts up the client. You must have already noticed that this program is almost the same as the previous one. So we will only discuss the new functions.

In the function socket, the first parameter is PF_INET which is the same as AF_INET. The second parameter that we are passing to this function is SOCK_DGRAM. 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 as reliable, 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. UDP is connection-less protocol i.e. when you want to send data you are not required to establish a connection (sendto is the function that we use in this case and not send. As send does not specify the destination IP address the data would not know where it is destined to and hence we first connect).The UDP protocol does not guarantee message delivery.

If the socket is created without problems, then the socket function returns a positive number, which is caught and displayed by s.

After creating a socket, we have to initialize the members of a structure. The Time server uses port number 13. This means that on the server end, whenever a packet appears which bears the port number 13, it is passed onto the time server.

After filling up the structure Sa, we have to send a request to the Time server, asking for the date and Time. So we copy the string "Hello, How are you" into the array bb. The array bb can hold any string, at all the time server doesn't pay attention to it. All it wants is 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 use function sendto in this case for the simple reason that UDP is a non-connection oriented protocol. That means UDP unlike TCP does not check whether the packet has reached the destination or not. When we use connect we are actually making sure that the server wants to communicate with us. In this case we have not established the connection. So we use the function sendto, the parameter to the function sendto, the handle 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. The function 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, as you can not put sizeof(Sa) directly as a parameter.

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.

7. Time Machine or...

After having written the time client you may be feeling an unstoppable urge to know how does the thing works from the other end. A program called a Time Server is running at the other end whose sole aim is to tell the current time to who ever asks for it. Once you see the code for it you will see how simple the stuff really is.

\*-----------------------------------------------------------------
Program #4
times.cpp
WinSock.lib has to be included in project before building the EXE
Time Server
------------------------------------------------------------------*\
#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];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);
}

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 we'll go back to windows and click on the start button, then click on run and type in winipcfg. This is one of the many nifty little features of Windows95. Winipcfg is stuffed full of useful information and you'll understand all of those weird words as we go along. What we're presently interested in is the IP address. Since your IP address changes every time you log on and then log off, you'll have to get your IP address by this method after you log on. Now open your time client workspace and edit the code, changing the line from

Sa.sin_addr.s_addr = inet_addr("140.252.1.32");

to

Sa.sin_addr.s_addr = inet_addr("123.123.123.123");

123.123.123.123 being your current IP address. Compile and run and wonders of wonders ! the words Hello appear in the message box ! Yes ! those words have been sent by your server!

Instead of following this tedious method, you could try this one. In the line Sa.sin_addr.s_addr = inet_addr("140.252.1.32"); change the IP address to 127.0.0.1. This is a reserved address and it loops the IP packets back to your machine in a process known as 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 software firms to test their software.

The server contains much the same code as the client and seeing that we've already explained the client in detail, we see no need to wear our fingers away typing the same thing again. There are a few changes though and we'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 a macro INADDR_ANY. This 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, for example, then your server will only accept requests that originate from there. The server know where the requests come from because the source IP address is written in the IP header.

The function bind, "binds" a server to a certain port. Whenever I read this particular line, 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 IP packets to my server. 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 the recvfrom, which, since it is blocking, waits for a packet to arrive. 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 finished, it passes control to sendto, which then sends the string "hello" to the remote client. In an actual Time server, 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. In fact, here's an exercise to the user I just dreamt up. 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, quite unlike the servers that abound on the Internet who can chew through a hundred requests every second. But we'll get to that later.

8. To, My... With lots of...

Gone are the days when we used to sit back, when we used to apply pen to paper and send those beautiful lines to our dear ones. The pen was regarded as being mightier than the sword. In the age of the Internet we do 'write' to our dear ones, but the similarity ends there. E-mailing a person is considered a better option. A person without an e-mail address is considered as homeless. Today the keyboard is considered mightier than the pen. This tutorial was 'penned' using a keyboard too!!

E-mails have changed the way we work, communicate and interact with people around. E-mail provides us with unparalleled edge in terms of speed, convenience, and cost benefits over other forms of communications. Many a companies the world over have set up shops as e-mail service providers. We know that we may be sounding as one of those sales representatives from these companies. But honestly we don't own an alliance with any one of them. It is our endeavor to provide you with the basic knowledge of the facts regarding the various protocols used in conjunctions with e-mail. So tighten your seat-belts as we are about to take off. SMTP or the Simple Mail Transfer Protocol is one of the protocols that is used to for e-mailing documents. We know that it is hard to believe, but it is true, SMTP as it's name suggest is indeed simple. it is simple to understand and implement. It is a far-cry from protocols which infest the world of computers and whose only desire is to confuse mankind. Below we present programs which will be helpful in clearing some of the mysteries surrounding this protocol.

----------------------------------
Program #5
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;
}

Beginning afresh is akin to put our best foot forward. Hence we will create a new project workspace and add this code to it. In case you have lost track of what is happening, let us remind you that you had visited this page to learn more about sockets programming. So in keeping with the spirit of things we will add the WSOCK32.LIB file to the project and then create a exe. Being live on the 'Net has been a catch-phrase of this decade and in keeping with the time please ensure that you are connected to the Internet.

WSAStartup()is the shining light for all winsock programmers. Forgetting this keyword will be his (or her, we don't want to appear sexist)worst nightmares come true. This is followed by the creation of a socket S. It's time to fill up the members of the structure Sockaddr_in. As e-mail is effected using the TCP/IP protocol and since TCP is a connection based protocol, the second parameter is SOCK_STREAM. The SMTP server 'listens' on port 25. This information is used to initialize the 'sin_port' member of the 'Sockaddr_in' structure. One of the pre-requisites for sending an e-mail is that we have to know the address of the target person. Without this it will akin to shooting in the dark. However computers do not understand names, they are known by their IP address. The IP address is a series of numbers which are difficult to remember. The IP address of a person can be obtained from a person's e-mail address by using a simple function called gethostbyname(). This function require a name of the server or host. For the uninitiated, the server/host name is the string that follows the '@' sign in the e-mail address. In our case we will use giasbm01.vsnl.net.in. The function will return a pointer to the structure hostent. Now we need to understand the member of structure hostent.

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 last member h_addr, is the pick of the lot as it contains the IP address of the server. Having secured the IP address, we have the necessary information for effecting a connection. Etiquette demands that we greet the person with whom we would like to have a conversation. This is true in the world of e-mailing too !!

The first command we send the server is HELO. No, that's not a typographical mistake, it's a four letter word that the server will understand and yes, it should be in Capitals. We send HELO followed by any name you like. Now this could be anything, the server on the other side does not check if the machine vijay1.com exits or not. This communication is two way, so whenever we send some bytes across, we have to be ready to receive some bytes also. When we send HELO, the server accepts it and sends us a reply. This reply is captured by the recv() function which is called next.

The next command is MAIL FROM: <E-mail address>\r\n, where <E-mail address> is your email address. The \r\n are compulsory. Servers usually don't check to see if the person who is sending the e-mail has a valid email address (MAIL FROM). This means that I can put Bill Gates in the MAIL FROM line and the server would happily pass the message on!

After MAIL FROM we have RCPT TO: <e-mail address>/r/n, where <e-mail address> is the email address of the person you want to send mail to. This address had better be genuine, or the server won't accept it.

We send the server the string 'DATA'. The server will reply and say that we can start sending anything we want, but when we're through, we should send a './r/n' on a new line. So we start sending our message from here onwards. When we finish, we dutifully send a './r/n'.

TO:, FROM:, DATE and MESSGE ID:are semi-reserved words of SMTP and must be sent next with the appropriate information. MESSAGE ID is a any random number which will identify the message.

If we're through with the session, we send a QUIT and break off.

--------------------------------------------------------
Post Office

----------------------------------
Program #6
POP3(Post Office Protocol)
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 go through the program you'll see that it's quite similar to the SMTP program. Here we have to identify ourselves as a authorized user by giving our user id and password. Unless we do so we will not be allowed to see our mail. There is no callback here and this program runs sequentially. At the end of the program, we display a MessageBox. When we see the MessageBox we'll know that everything over.

As we said earlier we are required to give our user id and password, USER <user id> is the syntax for specifying our user id. The server will reply and ask for a password. PASS <password> is the syntax for specifying our password. After receiving the password, the server will wait for more input from us.

Once the server has verified that you are an authorized user, it allows you to proceed. STAT is a command which is used to retrieve information about our mailbox e.g. the total number of new mails. The POP3 server will send us the status of our mailbox along with the numbers of individual messages and the total no of bytes occupied. The RETR command will now be used to retrieve messages. RETR 1 means get the first mail from the mailbox.

9. Pinging

In order to understand this program better, let's first try and understand how our packet travels over the wire. If we want to visit Microsoft's site the browser sends an HTTP request to the Microsoft's site all wrapped up in a TCP/IP packet. The IP part of the TCP/IP packet holds the source IP address as well as the destination IP address. So a packet from you will hold your IP address e.g. 10 as well as the IP address of your target e.g. 22. Your packet is first sent to your ISP's router, who checks the IP header for the destination address. Since all routers theoretically know the IP address of other routers and also which routers handle which range of IP address, your router, which handles IP address from 0 to 10, sends the packet to a router in Japan router, which handles IP address from 15 to 25. That router then send 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.

What happens to that packet from our computer to the Microsoft's site is what we have to understand. When a packet is sent across the wire to its destination its meets many routers on its way. When the packet reaches one such router, the router decrements the TTL (Time To Live) by one. The TTL is a number which represents the maximum number of routers a packet can meet on its way to its destination. When the TTL is zero the packet is dropped by the router.

The TTL is an unsigned char. That means that the maximum number of routers a packet can meet is 255.

When the packet finally reaches its final destination, the server sends a reply.

Now imagine a situation when we want to download a 5 MB binary file. Obviously it will take a long time to download such a big file over a 14.4 kbps link. At other times the file may come at a fast clip. This happens because the number of routers between different sites and at different times varies. The more the routers, normally the slower the download. It would be wise therefore 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 routers.

------------------------------------------------------------
Program #7
Ping
P.C
WSOCK32.LIB
------------------------------------------------------------
 #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();
 }

We are explicitly loading ICMP.DLL which is in the C:\windows\system directory. The function gethostbyname returns a pointer to hostent, which gives us the IP address of the site microsoft.com. One way to call the function in the DLL is to add the .lib file to the project and call the function as if they were local functions. Another way is to load the DLL file dynamically and call code using the pointer to the functions in the library. To get the address of the functions in the memory we use a function called GetProcAddress(). This function expects two parameter, the first one is a handle to the DLL and the second is the name of the function. We then call the function IcmpCreateFile() to initiate the process. We also initializing TTL, a member of the structure to 6. This means that if the site is seven routers away, then it'll never reach the site.

IcmpSendEcho() is a function used to send an echo request. This function will fill up the structure E. E.Address will give us the IP address of the last router reached. The structure will also give us the return trip time in milliseconds and the TTL of return trip.

Before we end, we close the handle and unload the DLL from memory.

10. Bond, James

The program given below is simply an extension of the previous program. Here we'll try and discover the path our packet took to reach it's target. We'll be printing out the names and IP address of the routers it met on it way. To do this we'll first set the TTL to 1 and then increment it. So when our packet meets the first router, i.e. VSNL's (our ISP) router, it will be dropped. We'll then increase the TTL by one and now the second router will drop the packet and so on. Routers send back ICMP messages with all the data we need. We'll display this data on the screen.

--------------------------------------------------------------
Program #8
Tracer
trace.C
WSOCK32.LIB
--------------------------------------------------------------
 #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

This is the output we got, your output will be different. The last line should be the name of the destination you specified. If it isn't there, try again.