Win32 Assembly Programming Asmsockguide
Win32 Assembly Programming Asmsockguide
Winsock or windows socket takes the concept from Unix. The idea behind sockets is to use them as communication
devices between different machines in the network. Each machine can create one or more sockets to connect to
other machines. Sockets make uses of TCP/IP protocol as such, it operates in the higher network layers. We use
sockets in any higher protocol that wants to use TCP/IP as its transport media such as HTTP,FTP and so on. The
socket itself doesn't understand or care about the content that passes through it. It just does its job of sending and
receiving data to from its remote counterpart.
Types of Socket
There are two types of socket: stream socket and datagram socket. A stream socket makes use of TCP so its
transmission requires connection and is reliable. You use a stream socket when you want to send large files over the
net or you want sequenced data packets (that is, the order of data packets is important). A datagram socket
provides simple transfer of data. It's not guaranteed to be reliable (the data may not reach its destination),
sequenced (the data packets may arrive in different order than intended), or unduplicated (the destination socket
may receive two or more identical copies of the same data packets). HTTP and FTP and some other protocols use
stream sockets while some broadcast protocols use datagram sockets.
You can think of stream socket connection as a telephone chat. You first have to make a call and if the call is
successful, a connection is established. Then you can exchange information with the other end in a reliable way. If
some communication problem occurs you know of it immediately and can take measures to rectify it. Datagram
socket connection is like sending several mails to someone. You cannot know beforehand that they will reach the
intended person. Even if he received them, there's no guarantee that the mails will reach him in the order you sent.
And the mails may not reach the target at all.
The socket model sometimes uses client-server concept that is, one socket is thought of as server since it has
services that it can render for other sockets, the opposite end is the client which asks the server for some services.
HTTP and FTP make uses of this client-server concept.
Byte Ordering
open in browser PRO version
pdfcrowd.com
Since we must deal with IP addresses in winsock programming, we should know of different byte ordering first.
There are two types of byte ordering: big Endian and little Endian. In big Endian scheme, the leftmost byte are stored
in the most significant byte. Little Endian scheme is the reverse of big Endian. For example, if the IP address is
205.34.67.24, in big Endian scheme it will be 205 34 67 24. But in little Endian, it will be 24 67 34 205.
Intel CPU uses little endian while some other CPUs such as Motorola uses big endian. The final word is: the internet
uses big endian scheme so if you use a CPU with little endian byte ordering, you must convert the IP addresses
before using them with the net.
Blocking and non-blocking modes
Socket functions can operate in two modes: blocking and non-blocking. Originally, in Berkeley Unix implementation,
the sockets operate in blocking mode, that is, a socket function will not return until the operation is completed. We
can call "blocking mode" synchronous operation and "non-blocking mode" asynchronous operation. Blocking
operation may take an arbitrarily long time to complete such as waiting for the data to arrive from the remote socket.
During that time, the program will seem frozen. This is usually unacceptable in Windows environment. So Windows
implementation of socket API includes asynchronous (non-blocking) versions of the original blocking functions. You
should use non-blocking versions whenever possible since it conforms to Windows paradigm and provides better
results than the blocking ones.
Ports
When you create a socket and connect it to the remote socket, you must specify the port that the sockets will
communicate with each other. Ports in this case is not hardware ports like COM1 or COM2. Ports in winsock
programming are virtual ones for communication purpose only. Maybe an example will make this clear. Say, the
server creates a socket and instructs it to listen for incoming connection on port 21, although there may be many
network packets coming into the server, those packets that are destined for port number 21 will be routed to that
socket. Several Internet protocols has their own default ports. HTTP uses port 80 (decimal) and FTP uses port 21
(decimal). These are default ports only. It means if both client and server agree to communicate via different ports,
they can do so without any repercussion.
Winsock Programming Overview
Programming winsock normally includes these steps:
open in browser PRO version
pdfcrowd.com
1.
2.
3.
4.
5.
6.
7.
pdfcrowd.com
If this function is not successful, you cannot use any winsock function. In fact, this function also serves as a
negotiation routine for the best version of winsock api service for the application. After the call is successful,
WSADATA structure will be filled with the capabilities of the current winsock implementation. One of the members is
the highest version of winsock that the library supports. Say, if the application requests for at least winsock version
1.1 support and the current winsock library can support version 2, WSAStartup call will be successful and the
winsock library returns 200h in a member of WSADATA. If the application can make use of winsock 2 support, it
may call WSACleanup to close the previous initialization and call WSAStartup again, this time with 200h in its
wVersionRequired parameter. If your application supports only winsock 1.1, you don't have to examine the
WSADATA structure.
Code Snippet:
.data
wsadata WSADATA <>
.....
.code
.......
invoke WSAStartup, 101h,addr wsadata
.if eax!=NULL
<An error occured>
.else
<The initialization is successful. You may proceed with other winsock calls>
.endif
Socket Creation
After the successful WSAStartup call, you can proceed to create the socket.
socket PROTO af:DWORD, type:DWORD, protocol:DWORD
Parameters
open in browser PRO version
pdfcrowd.com
af == Address format which at the current time there is only one: PF_INET
type == type of the socket you want to create, stream or datagram one. If you want a stream socket, use
SOCK_STREAM else use SOCK_DGRAM
protocol == if the af param is AF_UNSPEC (unspecified), you must specify the protocol here. However, since we
always use PF_INET, you can use 0.
Return Value
If the call is unsuccessful, the return value is INVALID_SOCKET and you can call WSAGetLastError to retrieve the
actual error code. If the call is successful, it returns the socket descriptor which you must use in subsequent winsock
calls.
Comment:
You must create at least one socket to be used as the communication device from your end. After successful call,
you must save the returned socket descriptor for use with subsequent winsock function calls.
Code Snippet:
.data?
sock dd ?
....
.code
....
invoke socket,AF_INET,SOCK_STREAM,0
.if eax!=INVALID_SOCKET
mov sock,eax
.else
invoke WSAGetLastError
...
.endif
open in browser PRO version
pdfcrowd.com
pdfcrowd.com
Return Value
If the call is successful, the return value is NULL. Otherwise it returns SOCKET_ERROR and you may call
WSAGetLastError to retrieve the actual error code.
Comment
This function is the instrument of non-blocking paradigm. It lets an application specify which winsock events it's
interested in and when the registered winsock events occur, the winsock library will send the specified message to
the window. Contrast this to the blocking scenario in which you must poll for the winsock events. This function also
changes the socket to non-blocking mode. I recommend that you use WSAAsyncSelect whenever applicable since
it conforms to Windows paradigm.
If you don't want the winsock library to send notifications to your window anymore, you must call WSAAsyncSelect
with value 0 in lEvent parameter. However, beware that there may be winsock messages in the queue before you
cancel winsock notification. You must be prepared to handle them. Normally you should extract them from the
message queue by PeekMessage call with PM_REMOVE flag.
When a winsock event that the application is interested occurs, the message specified by msg parameter will be
sent to the window procedure of the window specified by hwnd parameter. With the message, wParam contains the
socket descriptor, high word of lParam contains error code (if any) and the low word of lParam contains the event.
Code Snippet
.data?
hwnd dd ?
; handle of the window to receive the winsock message.
socket dd ?
; socket descriptor
....
.const
WM_SOCKET equ WM_USER+100 ; create a custom window message. You can use any name not
; limited to WM_SOCKET and you can use any number not
; limited to 100.
......
.code
open in browser PRO version
pdfcrowd.com
...........
invoke WSAAsyncSelect, socket, hwnd,WM_SOCKET, FD_CONNECT+FD_READ+FD_CLOSE
; Register interest in connect, read and close events.
.if eax==SOCKET_ERROR
<put your error handling routine here>
.else
........
.endif
WndProc PROC hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
.......
.if uMsg==WM_SOCKET
; the message we specified in WSAAsyncSelect
mov eax,lParam
.if ax==FD_CONNECT
; the low word of lParam contains the event code.
shr eax,16
; the error code (if any) is in the high word of lParam
.if ax==NULL
<no error occurs so proceed>
.else
<an error occurs. Put your error handling routine here>
.endif
.elseif ax==FD_READ
shr eax,16
.if ax==NULL
<no error occurs so proceed>
.else
<an error occurs. Put your error handling routine here>
.endif
.elseif ax==FD_CLOSE
shr eax,16
.if ax==NULL
open in browser PRO version
pdfcrowd.com
sockaddr_in STRUCT
sin_family WORD
?
sin_port WORD
?
sin_addr DWORD
?
sin_zero BYTE 8 dup (?)
sockaddr_in ENDS
open in browser PRO version
pdfcrowd.com
You must fill in this structure and pass its address to connect.
sin_family is the same as af parameter in socket call. You must use AF_INET here.
sin_port is the port that the socket will use to communicate with the remote socket. This value depends
on the higher level protocol that you want to use. If you want to connect to the remote socket for HTTP,
use port 80 (decimal). However, note that the port value MUST be in network byte order that is big
Endian. So you cannot use the port value per se but you must call htons to convert the value to network
byte order first. This is one of the most common error the newcomers to winsock programming
encounter.
sin_addr is the IP address of the remote host. Again, you must convert the IP address to network byte
order before using it.
sin_zero is reserved. Don't mess with it.
namelen == the size of SOCKADDR_IN structure
Return Value
Depend on the mode of the socket.
non-blocking mode: it returns SOCKET_ERROR and you must call WSAGetLastError to retrieve the error
code. If the error code is WSAEWOULDBLOCK ,it means that the operation is in progress and cannot return
immediately. The application will be informed of the result later by custom window message specified in
WSAAsyncSelect call. In a nutshell, WSAEWOULDBLOCK is not an error.
blocking mode: The return value indicates the success or failure of the call.
Code Snippet
.data
sin SOCKADDR_IN <>
IPAddress db "206.34.234.23",0
open in browser PRO version
pdfcrowd.com
Port dd 80
.data?
socket dd ?
.code
........
mov sin.sin_family, AF_INET
invoke htons, Port
; convert port number into network byte order first
mov sin.sin_port,ax
; note that this member is a word-size param.
invoke inet_addr, addr IPAddress ; convert the IP address into network byte order
mov sin_addr,eax
invoke connect,socket,addr sin,sizeof sin
.if eax==SOCKET_ERROR
; assuming we use non-blocking mode, connect
; will always return SOCKET_ERROR
invoke WSAGetLastError
; retrieve the actual error code
.if eax!=WSAEWOULDBLOCK
; if it's not WSAEWOULDBLOCK
<put your error handling code here>
; it means a true error occurred
.endif
.endif
If you only got URL string such as "http://members.xoom.com/Iczel", you must parse the string for the host name, in
this case "members.xoom.com". And pass the address of the host name as a parameter to gethostbyname
function which has the following syntax:
gethostbyname PROTO lphostname:DWORD
Parameters
lphostname == pointer to the host name string.
open in browser PRO version
pdfcrowd.com
Return Value
If successful, it returns a pointer to hostent structure which is allocated by Windows sockets implementation. If the
call fails, it returns NULL and you may call WSAGetLastError to retrieve the error code.
hostentStru STRUCT
h_name
DWORD
?
h_alias DWORD
?
h_addr WORD
?
h_len
WORD
?
h_list DWORD ?
hostentStru ENDS
Note that in windows.inc supplied by hutch, hostent structure is named hostentStru.
h_name Official name of the host (PC).
h_alias A NULL-terminated array of alternate names.
h_addr The type of address being returned; for Windows Sockets this is always PF_INET.
h_len The length, in bytes, of each address; for PF_INET, this is always 4.
h_list Pointer to a pointer that points to the list of ip addresses. In summary, h_list is a double pointer
indirection. Addresses are returned in network byte order so you can use them immediately.
Comment
This function is used to retrieve the IP address(es) of the host specified as a string. Notice that what you want mostly
is in h_list member.
Code Snippet
.data
sin SOCKADDR_IN <>
hostname db "members.xoom.com",0
Port dd 80
; We use port 80, HTTP port for demonstration purpose
open in browser PRO version
pdfcrowd.com
.data?
socket dd ?
.code
........
mov sin.sin_family, AF_INET
invoke htons, Port
; convert port number into network byte order first
mov sin.sin_port,ax
; note that this member is a word-size param.
invoke gethostbyname, addr hostname
mov eax,[eax+12]
; move the value of h_list member into eax
mov eax,[eax]
; copy the pointer to the actual IP address into eax
mov eax,[eax]
; copy IP address into eax
mov sin.sin_addr,eax
invoke connect,socket,addr sin,sizeof sin
.if eax==SOCKET_ERROR
; assuming we use non-blocking mode, connect
; will always return SOCKET_ERROR
invoke WSAGetLastError
; retrieve the actual error code
.if eax!=WSAEWOULDBLOCK
; if it's not WSAEWOULDBLOCK
<put your error handling code here>
; it means a true error occurred
.endif
.endif
pdfcrowd.com
pdfcrowd.com
pdfcrowd.com
pdfcrowd.com
.if eax==NULL
invoke GlobalAlloc, GHND, available_data
mov hMemory,eax
invoke GlobalLock, eax
mov buffer,eax
invoke recv, socket, buffer, available_data, 0
mov actual_data_read, eax
.....
<use the data in buffer>
....
invoke GlobalUnlock, buffer
invoke GlobalFree, hMemory
.endif
pdfcrowd.com
.data?
socket dd ?
....
.code
....
invoke closesocket, socket
.if eax==SOCKET_ERROR
<put your error handling code here>
.else
endif
pdfcrowd.com
.code
.....
invoke WSACleanup
.if eax==SOCKET_ERROR
<put your error handling code here>
.else
.endif
[Iczelion's Winsock Section][Iczelion's Win32 Assembly Homepage]
pdfcrowd.com