_________________ /_ /\ \/ _______ / \ / / / / / / /______/ / / / __/ / / _______ \ __/ / / / / \ / /______/ / / _/ / / /______________/ / BLACK SUN RESEARCH FACILITY \ \ / HTTP://BLACKSUN.BOX.SK \______________\/ WINDOWS INTERNET PROGRAMMING {part 2} ================================================= WRITTEN BY [ cos125@hotmail.com :E-MAIL ] BINARY RAPE [ 114603188 :ICQ# ] [ www.geocities.com/wininetprogram :WEB SITE ] [ http://blacksun.box.sk :TURORIALS ] Thanks to cyberwolf for letting me write this and BSRF for releasing it.
Disclaimer
None of the information or code in this tutorial is meant to be used against others
or to purposely damage computer systems and/or cause any loss of or damage to property.Further more, neither myself or any other contributor to, or member of, the Blacksun
research Facility (BSRF) can be held responsible for damage or loss of property to
computer systems as a result of this tutorial.In this tutorial the code is provided as a learning aid so you can see how its done
its not meant for you to use against yourself or others.If you don't agree with any of this then please stop reading...... now!
CONTENTS
1. Introduction
2. UNIX and Windows
3. Error Codes
4. Port Numbers
5. Include Files
- 5.1 socket()
-5.2 bind()
-5.3 connect()
-5.4 listen()
-5.5 accept()
-5.6 gethostname()6. Common Functions
7. Renamed Functions
8. Blocking Routines
9. Additional Functions
10. Porting Code
-10.1 DNS Program
-10.2 Streaming Server
-10.3 Streaming Client11. Planning
12. Last WordsAPPENDIXES
A - The Compiler
______________________
1.0 INTRODUCTION
In the last part in this series of tutorials I discussed windows sockets programming using
the winsock API and in that document I mentioned that the windows Sockets implementation is
based on the Berkeley Sockets idea, therefore socket programming on systems such as UNIX
and Linux, which are also based on the Berkeley API would be quiet similar. This aids us
in porting from platform to platform, making it easy to move whole programs from UNIX to
windows in a very short time.This tutorial will discuss and illustrate the differences in code and functions between the
platforms and sample source code and applications will be provided to show how to port the
applications piece by piece.I suggest that you first read Part 1 in this series of tutorials and also Bracaman's basic
UNIX sockets tutorial, also available from blacksun.box.sk and also from code.box.sk.Any add on information for this tutorial and updates are available as usual from:
http://www.geocities.com/winnetprogram.
2.0 UNIX AND WINDOWS
=====================Unix and Windows handle sockets differently, UNIX treats sockets the same as a file handle
which is a small integer while in windows it is an unsigned type called SOCKET.So from the start UNIX and windows actually think of there respective sockets differently.
To best explain the differences the following is an exert from bracamans tutorial and
describes sockets from the Unix point of view:
"In a very simple way, a socket is a way to talk to other computer.
To be more precise, it's a way to talk to other computers using standard Unix file
descriptors.In Unix, every I/O actions are done by writing or reading to a file descriptor. A file
descriptor is just an integer associated with an open file and it can be a network connection,
a terminal, or something else."
3.0 ERROR CODES
=======================================In UNIX error codes are available trough the errno variable. In windows we use the function
WSAGetLastError() to obtain these error codes.
_________________________
4.0 PORT NUMBERS
=======================================In both Unix and Windows you define the port numbers by entering the destination port number
as a parameter to the function htons(), however in winsock.h several port numbers are defined
for common ports so that you can also use these.The following is a list of the default names and there relative port numbers:
1. IPPORT_ECHO - 7 2. IPPORT_DISCARD - 9 3. IPPORT_SYSTAT - 11 4. IPPORT_DAYTIME - 13 5. IPPORT_NETSTAT - 15 6. IPPORT_FTP - 21 7. IPPORT_TELNET - 23 8. IPPORT_SMTP - 25 9. IPPORT_TIMESERVER - 37 10. IPPORT_NAMESERVER - 42 11. IPPORT_WHOIS - 43 12. IPPORT_MTP - 57
5.0 INCLUDE FILES
=======================================In UNIX there are a number of include files to use in socket programming, following is a
list of these functions and related #include files:
[ #include <sys/types.h> ]
[ #include <sys/socket.h> ]
[ #include <sys/types.h> ]
[ #include <sys/socket.h> ]
[ #include <sys/types.h> ]
[ #include <sys/socket.h> ]
[ #include <sys/types.h> ]
[ #include <sys/socket.h> ]
[ #include <sys/socket.h> ]
[ #include <netdb.h> ]
You will need some general socket include files also in UNIX programming:
#include <netinet/in.h>
#include <arpa/inet.h>
Your average list of include files at the top of a UNIX socket program would therefore
look something like the following:#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
In windows the header file for socket and internet programming is contained in windows.h,
therefore the top of a windows socket programming would look like this:#include <windows.h>
The name of the header file for windows socket programming is winsock.h and including
this file in your project as well wont cause any errors of course but there’s just no need.Windows programs also need to be linked to the file Wsock32.lib before they can be
compiled.Consult your compilers documents for further information on this or proceed to Appendix 1
- The compiler.
6.0COMMON FUNCTIONS
=======================================Both Unix and Windows sockets have a set of functions common to both platforms. These are
mostly the functions dealing with TCP and UDP and all conversion functions and structures
are the same for both platforms.For example htons() and inet_addr() are the same on both platforms, also so is the
structures sockaddr and sockaddr_in.
Here is a list of common functions.
1. Socket()
2. Bind()
3. Listen()
4. Connect()
5. Accept()
6. Send()
7. Recv()
8. Sendto()
9. Recvfrom()
10. Gethostname()
7.0 RENAMED FUNCTIONS
=======================================There are some functions which exist in both windows and UNIX socket programming but
during the conversion the names have changed slightly.The following table contains a comparison of renamed functions in windows and UNIX.
+===============+==================+ | Unix Function | Windows Function | +===============+==================+ | close() | closesocket() | +---------------+------------------+ | ioctl() | ioctlsocket() | +---------------+------------------+ | read() | recv() | +---------------+------------------+ | write() | send() | +---------------+------------------+FIG 1. - Comparison of Windows and Unix Socket functions.
8.0 BLOCKING ROUTINES
=======================================In windows you can use blocking routines but they are not recommended. In windows 3.1
using the event driven paradigm it is possible to have a blocked operation disturbed
by other event driven activity.Soon you will not be able to have blocking routines in Winsock applications so it is
not recommended you use them at all in this scenario as this would limit distribution
possibilities.
9.0 ADDITIONAL FUNCTIONS
=======================================In windows there are some functions which aren't seen in UNIX sockets. In every
windows socket program you must call WSAStarup() before you can call any socket
functions or use any code.Additionally every WSAStartup() function has a corresponding WSACleanup() which
shuts down the Winsock and cleans up after us.Every Windows socket program must contain both of these functions.
10.0 PORTING CODE
=======================================Now that we have discussed the different parts of the program in Unix and its relevant
Windows parts we can look at some real code.
The first program we come across is Bracamans DNS application. Here’s the Unix Code.
/* <---- SOURCE CODE STARTS HERE ----> */
#include <stdio.h>
#include <netdb.h> /* This is the header file needed for gethostbyname() */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(int argc, char *argv[])
{
struct hostent *he;if (argc!=2){
printf("Usage: %s <hostname>\n",argv[0]);
exit(-1);
}if ((he=gethostbyname(argv[1]))==NULL){
printf("gethostbyname() error\n");
exit(-1);
}printf("Hostname : %s\n",he->h_name); /* prints the hostname */
printf("IP Address: %s\n",inet_ntoa(*((struct in_addr *)he->h_addr))); /* prints IP address */
}
/* <---- SOURCE CODE ENDS HERE ----> */
This is a very small but still a very useful program. If we attempt to compile this
right away under Microsoft Visual C++ We will get an error saying that it can not
find an include file, so our first duty is to remove all of the Unix Socket include
files and replace them with the line:#include <windows.h>
remembering to leave stdio.h right where it is.
When I tried compiling it now I got several more errors so I changed the
main() fuction from what it is above to:void main(int argc, char **argv) and the program then compiled.
However I then got several linker errors. Remember when socket programming on windows
you must link to the file Wsock32.lib.After I linked to the proper .lib file the program compiles perfectly, without the
need to touch a single line of the socket code!!This is how compatible different platforms can be with socket code, however this is a
very small program and this is not usually the case. The following is the windows
source code for the port of Bracamans DNS program.Remember you will get an error unless you include WSAStartup() and WSACleanup()!!
/* <---- SOURCE CODE STARTS HERE ----> */
#include <windows.h>
#include <stdio.h>int main(int argc, char *argv[])
{WSADATA wsdata;
WSAStartup(0x0101,&wsdata);
struct hostent *he;
if (argc! = 2)
{
printf("Usage: %s hostname\n",argv[0]);
return -1;
}if ((he = gethostbyname(argv[1])) == NULL)
{
printf("gethostbyname() error\n");
return -1;
}printf("Hostname : %s\n",he->h_name); /* prints the hostname */
printf("IP Address: %s\n",inet_ntoa(*((struct in_addr *)he->h_addr))); /* prints IP address */WSACleanup();
return -1;}
/* <---- SOURCE CODE ENDS HERE ----> */
This program has almost as few lines as the UNIX alternative and requires practically
no porting at all!Like I said you wouldn’t usually have a program that runs on windows with such little altering.
Lets discuss porting Bracamans TCP streaming server.
/* <---- SOURCE CODE STARTS HERE ----> */
#include <stdio.h> /* These are the usual header files */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define PORT 3550 /* Port that will be opened */
#define BACKLOG 2 /* Number of allowed connections */main()
{
int fd, fd2; /* file descriptors */struct sockaddr_in server; /* server's address information */
struct sockaddr_in client; /* client's address information */int sin_size;
if ((fd=socket(AF_INET, SOCK_STREAM, 0)) == -1 ){ /* calls socket() */
printf("socket() error\n");
exit(-1);
}server.sin_family = AF_INET;
server.sin_port = htons(PORT); /* Remember htons() from "Conversions" section? =) */
server.sin_addr.s_addr = INADDR_ANY; /* INADDR_ANY puts your IP address automatically */
bzero(&(server.sin_zero),8); /* zero the rest of the structure */
if(bind(fd,(struct sockaddr*)&server,sizeof(struct sockaddr))==-1){ /* calls bind() */
printf("bind() error\n");
exit(-1);
}if(listen(fd,BACKLOG) == -1){ /* calls listen() */
printf("listen() error\n");
exit(-1);
}while(1){
sin_size=sizeof(struct sockaddr_in);
if ((fd2 = accept(fd,(struct sockaddr *)&client,&sin_size))==-1){ /* calls accept() */
printf("accept() error\n");
exit(-1);
}
printf("You got a connection from %s\n",inet_ntoa(client.sin_addr) ); /* prints client's IP */
send(fd2,"Welcome to my server.\n",22,0); /* send to the client welcome message */
close(fd2); /* close fd2 */
}
}/* <---- SOURCE CODE ENDS HERE ----> */
Well lets try and compile shall we...
Straight away we should clear the obvious problems, link to Winsock32.lib and
only include windows.h and stdio.h.Having done so we receive 2 errors, the first pertains to bzero which we do not
have in our little program so we are going to just remove the line that contains
it. Once we do so we now have only 1 error, woohoo!This error tells us that the function close() is not a valid identifier which is
what I said earlier, close() has been replaced by closesocket() in windows so we
change that as well to closesocket().We run this program and we recieve a socket error :(. But remember we never entered
WSAStartup() and WSACleanup() in this program so we have to do that first and then
our program will work :).If you run the program the command prompt should remain blank, just leave the program
as it is now and move onto the next section to figure out where to go from here!!First of course here’s the Windows code for the port ;).
/* <---- SOURCE CODE STARTS HERE ----> */
#include <stdio.h> /* These are the usual header files */
#include <windows.h>
#define PORT 3550 /* Port that will be opened */
#define BACKLOG 2 /* Number of allowed connections */main()
{
WSADATA wsdata;WSAStartup(0x0101,&wsdata);
int fd, fd2; /* file descriptors */
struct sockaddr_in server; /* server's address information */
struct sockaddr_in client; /* client's address information */int sin_size;
if ((fd=socket(AF_INET, SOCK_STREAM, 0)) == -1 ) /* calls socket() */
{
printf("socket() error\n");
exit(-1);
}server.sin_family = AF_INET;
server.sin_port = htons(PORT); /* Remember htons() from "Conversions" section? =) */
server.sin_addr.s_addr = INADDR_ANY; /* INADDR_ANY puts your IP address automatically */
if(bind(fd,(struct sockaddr*)&server,sizeof(struct sockaddr))==-1) /* calls bind() */
{
printf("bind() error\n");
exit(-1);
}
if(listen(fd,BACKLOG) == -1) /* calls listen() */
{
printf("listen() error\n");
exit(-1);
}
while(1)
{
sin_size=sizeof(struct sockaddr_in);if ((fd2 = accept(fd,(struct sockaddr *)&client,&sin_size)) == -1) /* calls accept() */
{
printf("accept() error\n");
exit(-1);
}
printf("You got a connection from %s\n",inet_ntoa(client.sin_addr) ); /* prints client's IP */
send(fd2,"Welcome to my server.\n",22,0); /* send to the client welcome message */
closesocket(fd2); /* close fd2 */
WSACleanup();
return -1;
}
}/* <---- SOURCE CODE ENDS HERE ----> */
[ 10.3 ] STREAMING CLIENT
/* <---- SOURCE CODE STARTS HERE ----> */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> /* netbd.h is needed for struct hostent =) */#define PORT 3550 /* Open Port on Remote Host */
#define MAXDATASIZE 100 /* Max number of bytes of data */int main(int argc, char *argv[])
{
int fd, numbytes; /* files descriptors */
char buf[MAXDATASIZE]; /* buf will store received text */
struct hostent *he; /* structure that will get information about remote host */
struct sockaddr_in server; /* server's address information */if (argc !=2) { /* this is used because our program will need one argument (IP) */
printf("Usage: %s <IP Address>\n",argv[0]);
exit(-1);
}if ((he=gethostbyname(argv[1]))==NULL){ /* calls gethostbyname() */
printf("gethostbyname() error\n");
exit(-1);
}if ((fd=socket(AF_INET, SOCK_STREAM, 0))==-1){ /* calls socket() */
printf("socket() error\n");
exit(-1);
}server.sin_family = AF_INET;
server.sin_port = htons(PORT); /* htons() is needed again */
server.sin_addr = *((struct in_addr *)he->h_addr); /*he->h_addr passes "*he"'s info to "h_addr" */
bzero(&(server.sin_zero),8);if(connect(fd, (struct sockaddr *)&server,sizeof(struct sockaddr))==-1){ /* calls connect() */
printf("connect() error\n");
exit(-1);
}if ((numbytes=recv(fd,buf,MAXDATASIZE,0)) == -1){ /* calls recv() */
printf("recv() error\n");
exit(-1);
}buf[numbytes]='\0';
printf("Server Message: %s\n",buf); /* it prints server's welcome message =) */
close(fd); /* close fd =) */
}/* <---- SOURCE CODE ENDS HERE ----> */
That’s the source code for the Unix client and of course the windows one doesn't
look very different.
/* <---- SOURCE CODE STARTS HERE ----> */
#include <windows.h>
#include <stdio.h>#define PORT 3550 /* Open Port on Remote Host */
#define MAXDATASIZE 100 /* Max number of bytes of data */int main(int argc, char *argv[])
{
WSADATA wsdata;WSAStartup(0x0101,&wsdata);
int fd, numbytes; /* files descriptors */
char buf[MAXDATASIZE]; /* buf will store received text */
struct hostent *he; /* structure that will get information about remote host */
struct sockaddr_in server; /* server's address information */if (argc !=2) { /* this is used because our program will need one argument (IP) */
printf("Usage: %s <IP Address>\n",argv[0]);
exit(-1);
}if ((he=gethostbyname(argv[1])) == NULL){ /* calls gethostbyname() */
printf("gethostbyname() error\n");
exit(-1);
}if ((fd=socket(AF_INET, SOCK_STREAM, 0))==-1) /* calls socket() */
{
printf("socket() error\n");
exit(-1);
}server.sin_family = AF_INET;
server.sin_port = htons(PORT); /* htons() is needed again */
server.sin_addr = *((struct in_addr *)he->h_addr); /*he->h_addr passes "*he"'s info to "h_addr" */
if(connect(fd, (struct sockaddr *)&server,sizeof(struct sockaddr))==-1) /* calls connect() */
{
printf("connect() error\n");
exit(-1);
}if ((numbytes=recv(fd,buf,MAXDATASIZE,0)) == -1) /* calls recv() */
{
printf("recv() error\n");
exit(-1);
}buf[numbytes] = '\0';
printf("Server Message: %s\n",buf); /* it prints server's welcome message =) */
closesocket(fd); /* close fd =) */
WSACleanup();
return -1;
}/* <---- SOURCE CODE ENDS HERE ----> */
There’s actually no real difference with this port and the last. The same lines are
changed and the same functions are included as before.Start the program by switching to its directory on the command line and typing
streamclient.exe local host
Where streamclient.exe is the name of the stream client program we just ported
naturally :).Just make sure that the previous example, the streaming server is running and
your away. The screen will print the line "Welcome to my server." Congratulations
you’ve ported your first Unix Socket client and server to windows and you received
a line of text back from your own server :).
11.0 Planning
=======================================When porting its probably best to go trough things like a check list before attempting
to compile the bloody thing. Here’s a list of some recommendations to run trough first.1. Replace all network header files with windows.h or winsock.h.
2. Make sure to add WSAStartup() and WSACleanup() before and after the code.
3. Replace functions such as close() and ioctl() with windows counterparts.
4. Take care of problems such as bzero() and add any windows specific features like
default ports.
With so few and simple operations like this it would be pretty damn easy to write
a program that performs these actions for you, I doubt it would be complete but hey
it would save you a lot of time in the long run, especially with larger applications.
12.0 LAST WORDS
==============Well that’s it for this tutorial, or at least this part of it. More parts are planned so
hopefully you should see them on blacksun soon :). This part covered the basics of
windows programming, there was no point in writing about UNIX programming as bracaman
has released a very good tutorial on basic UNIX sockets programming which is available
from blacksun.box.sk and code.box.sk.I will be discussing Unix sockets again however in the next part of this tutorial but
mostly in a porting sense. To see what’s planned for future parts so far just look down :).
Part 2. - GENERAL SOCKETS - Porting to windows and cross platform code.
Part 3. - RAW Sockets - Have more control over packets with raw sockets.
Part 4. - ADVANCED - A real world example by building an internet communication suite.
Part 5. - FINISHING OFF - Putting it all together in one big program.So that’s what’s still to come, but I may change some of these future tutorials at any
time before there released if I do so it will be to improve the series in my view and
remember send me comments and suggestions and your ideas might also change the layout
of following tutorials.
Well thank you for reading this tutorial and visit my website to keep up to date with
the series and for add on code and articles to the series.- BR ;)
Id really like to thank Bracaman for everything including allowing me to use code from
his tutorial and please remember that this tutorial should be read with his (after his
1 even :P), so thanks for everything Bracaman it helped so much :).
All of the programs in this tutorial have been tested under Microsoft Visual C++ 6.0,
im running Windows 2000 Professional edition and I have an Intel Pentium 2.To set up the compiler for Winsock programming you need to link Wsock32.lib to your project.
Under Visual C++ do the following.1. Select the File view tab.
2. Right Click the files menu and go to Settings.
3. Select the Link tab in Project Settings.
4. Add Wsock32.lib to the list of .lib files and press ok.The winsock.h header file is included in windows.h so don’t worry about that.