Introduction
I love TCP/IP. The strength of TCP/IP is it's compatibility with nearly any lower-layer network infrastructure. The fact that its protocols are based on open standards enhances it's standing. Windows sockets provide direct access to the transport layer, OSI layer 4. And the 2 services it provides are UDP and TCP. One is connectionless and the other is connection oriented. Typically in the client-server model, every network application has a communication end point. There are 2 types of end points, client and server. By definition, a client sends the first packet and server receives it. Well I am not going to discuss anything more on Windows sockets, because we are going to write our own sockets, I presume anyone reading this article should have a basic understanding of sockets, HDLC (High level data link layer) and LLC (Logical link layer).
HDLC (High Level Data link layer)
High-Level Data Link Control, also know as HDLC, is a bit oriented, switched and non-switched protocol. It is a data link control protocol, and falls within layer 2, the Data Link Layer, of the Open Systems Interface (OSI) model. HDLC specifies the following three types of stations for data link control:
- Primary station - this completely controls all data link operations issuing commands from secondary stations and has the ability to hold separate sessions with different stations.
- Secondary station - this can only send responses to one primary station. Secondary stations only talk to each other via a primary station.
- Combined station - this can transmit and receive commands and responses from any other station.
Configuring a channel for use by a station can be done in one of three ways:
- Unbalanced - this configuration allows one primary station to talk to a number of secondary stations over half-duplex, full-duplex, switched, unswitched, point-to-point or multipoint paths.
- Symmetrical - where commands and responses are multiplexed over one physical channel when two stations with primary and secondary parts have a point-to-point link joining them.
- Balanced - where two combined stations communicate over a point-to-point link which can be full/half-duplex or switch/unswitched.
When transferring data, stations are in one of three modes:
- Normal Response Mode (NRM) where the secondary station needs permission from the primary station before it can transmit data. Mainly used on multi-point lines.
- Asynchronous Response Mode (ARM) where the secondary station can send data without receiving permission from the primary station. This is hardly ever used.
- Asynchronous Balanced Mode (ABM) where either station can initiate transmission without permission from the other. This is the most common mode used on point-to-point links.
LLC (Logical Link Layer)
LLC is a subset of High-Level Data Link Control (HDLC) and uses the Asynchronous Balanced Mode (ABM) subclass of HDLC. It sits in the data link layer between the (Media Access Control) MAC layer and the layer 3 protocols and forms an important part of the 802.2 specification.
Having understood the basic HDLC and LLC layers, we shall now proceed to implementing the high level layer. Let's see how the sockets are implemented
Understanding sockets
What exactly happens when you call a Windows socket? I am just trying to explain it. It does not run.
#define AS(NAME) NAME, *p##NAME, **pp##NAME
#define STRUCT typedef struct
typedef Uchar AS(Octet) ;
typedef Octet AS(MACaddr) ;
typedef Uchar AS(LSAP) ;
typedef u_int SOCKET;
STRUCT
{
MACaddr addr ;
LSAP port ;
} AS(NSAP) ;
STRUCT
{
Bool allocated ;
Bool bound ;
Bool listening ;
Bool connection_pending ;
Bool connected ;
Bool broken ;
} AS(SocketState) ;
STRUCT
{
SocketState state ;
short type ;
NSAP local_name ;
NSAP remote_name ;
Ulong when_connected ;
ECODE why_broken ; HWND async_hwnd ;
Ushort async_msgtype ;
} AS(SocketCB) ;
#define MAX_SOCKETS 6
static SocketCB sock_cb[MAX_SOCKETS] ;
#define ARRAYSZ(x) (sizeof(x)/sizeof((x)[0]))
SOCKET PASCAL FAR MYsocket( int af, int type, int protocol)
{
short i ;
if(af != AF_LLC || !(type EQ SOCK_STREAM || type EQ SOCK_DGRAM))
return(INVALID_SOCKET) ;
for(i = 1 ; i < ARRAYSZ(sock_cb) ; i++)
if(sock_cb[i].state.allocated EQ 0)
{
memset(&sock_cb[i], 0, sizeof(sock_cb[i])) ;
sock_cb[i].state.allocated = 1 ;
sock_cb[i].type = type ;
return(i) ;
}
return(INVALID_SOCKET) ;
}
That is how the Windows socket functionality looks internally.. Now lets move on to Listen
function.
Function: listen
- A server must prepare to accept a connection attempt from a client by calling
listen
. After listening on a socket it is necessary to prepare to
- Detect an incoming connection request from a client with
accept()
or select()
.
Parameters
s
: socket
backlog
: Length of pending connection queue
int PASCAL MyListen(SOCKET s, int backlog)
{
pSocketCB scb ;
if(s < 1 || s >= MAX_SOCKETS)
return(SOCKET_ERR_BAD_SOCK) ;
scb = sock_cb + s;
if(scb->state.allocated EQ 0)
return(SOCKET_ERR_BAD_SOCK) ;
if(scb->state.connected ||
scb->state.connection_pending || scb->state.broken)
return(SOCKET_ERR_INUSE) ;
if(!scb->state.bound)
return(SOCKET_ERR_UNBOUND) ;
scb->state.listening = 1 ;
return(0) ;
}
Looks so simple uh??. I will add more functions if everyone likes the article.