In-Depth Network Programming in C++

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 5

https://www.codeproject.

com/Tips/5345359/In-Depth-Network-Programming-in-Cplusplus

In-Depth Network Programming in C++


Mirzakhmet Syzdykov 20 May 2023 Network programming in C++
We provide the system primitives on the example of two networking programs, or utilities, which work on the Transfer
Control Protocol (TCP) and User Datagram Protocol (UDP) for basic and system operations
 Download source code for CPing - 355 KB
 Download source code for CSocks - 3.4 MB

Introduction
In this article, we introduce the basic primitives used to work with sockets, which are defined in winsock2.h file
for the version 2.0.

We will also present the two useful utility programs which solve various networking tasks.

Of course, we could use Microsoft Foundation Classes (MFC) for asynchronous programming, however, our
approach is more optimal for system network programming.

Thus, CPing program presented in this article is a utility which pings user-defined protocols and measures the
speed of connection.

Another example like CSocks presents the tunneling algorithm for proxying on SOCKS-5 protocol for
messengers like Internet Relay Chat (IRC).

Background
The article is to be studied according to the Request For Comment (RFC) standard for CSocks project as it uses
the command order for SOCKS-4/5 internet TCP protocol and, thus, operates on user or higher level, rather,
than same "ping" utility which operates on system level and protocol like Internet Control Message Protocol
(ICMP).

Thus, we introduce the same ping utility in CPing project, which works as is in order to test
functionality of HyperText Transfer Protocol (HTTP) and others that operate on the user-defined level.

Using the Code


Before proceeding to the description of programming techniques for network programming using
sockets, we will describe several functions of Winsock API:

 socket() - create socket entity


 send() - send data packet to the end point of socket
 recv() - receive data packet from the same end point
 setsockopt() - set socket options like timeout, etc.
 connect() - connect to the end point of socket which differs from the host machine on which
the networking program works
 select() - select the present time active socket on which the actions were made from the end
point
Let's proceed to the initialization for sockets' library as follows in the CPing utility:

C++
#include <windows.h>
#include <winsock2.h> // necessary
#include "CPing.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

CPing::CPing()
{
iTimeOut = 1000;
iBytesToRecv = 0;
iLastError = WSAStartup (MAKEWORD(2,0),&wsadata); // initialize Windows Sockets
strcpy (szNoop, NOOP);
}

CPing::~CPing()
{
WSACleanup(); // clean up the Windows Sockets cache
}

The class CPing is defined as follows:

C++
Shrink ▲
#ifndef __CPING_CLASS
#define __CPING_CLASS

#define MAX_SENDS 1111111


#define NOOP "NOOP"

typedef struct {
unsigned int iTimeSend; // measured time to send TCP packet
unsigned int iTimeRecv; // measured time to receive TCP packet
unsigned int iTotalSent, iTotalRecvd; // total number of bytes sent and received
unsigned int iPort; // TCP protocol port
} pingstore;

class CPing
{
public:
CPing();
~CPing();
char szNoop[256];
int iLastError, iTotalRes, iBytesToRecv;
unsigned int iTimeOut, iTotalSent, iTotalRecvd;
unsigned int PingContinuous
(char* szHost, unsigned int iPort, unsigned int iPackets);
unsigned int PingConnective
(char* szHost, unsigned int iPort, unsigned int iPackets);
pingstore* Res;
private:
WSADATA wsadata;
};

#endif
To be clear enough, we have to present an example of the usage of object-oriented programming
with the support of windows sockets in the CPing utility as follows:

C++
Shrink ▲
unsigned int CPing::PingContinuous
(char* szHost, unsigned int iPort, unsigned int iPackets)
{
struct hostent* host = NULL;
struct sockaddr_in saddr;
unsigned int s = 0;
unsigned int dw1, dw2, dw3;
char szBuffer[256];

if (!iBytesToRecv) iBytesToRecv = strlen(szNoop);

if (iPackets>MAX_SENDS) return (0);


free (Res);
Res = (pingstore*)malloc (sizeof(pingstore)*iPackets);
memset (Res, 0, sizeof(pingstore)*iPackets);

s = socket(AF_INET, SOCK_STREAM, 0);


if (!s) return (0);
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&iTimeOut, sizeof(iTimeOut));
setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char*)&iTimeOut, sizeof(iTimeOut));

host = gethostbyname (szHost);


if (host==NULL) return (0);
saddr.sin_family = AF_INET;
saddr.sin_port = htons(iPort);
saddr.sin_addr = *((struct in_addr*)host->h_addr);

if (connect (s,(struct sockaddr*)&saddr, sizeof(saddr)) == -1) return (0);


for (int i=0;i<iPackets;i++)
{
iTotalRes++;
sprintf (szBuffer, "%s\r\n", szNoop);
dw1 = GetTickCount();
int iSent = send (s, szBuffer, strlen(szBuffer), 0);
dw2 = GetTickCount();
int iRecv = recv (s, szBuffer, iBytesToRecv, 0);
dw3 = GetTickCount();
Res[i].iPort = iPort;
Res[i].iTimeSend = dw2-dw1;
Res[i].iTimeRecv = dw3-dw2;
Res[i].iTotalSent = ((iSent==SOCKET_ERROR)?0:iSent);
Res[i].iTotalRecvd = ((iRecv==SOCKET_ERROR)?0:iRecv);
if (iRecv<=0)
{
closesocket (s);
return ((iTotalRes)?1:0);
}
}
closesocket (s);
return (1);
}

Another example like CSocks network utility for proxying on SOCKS-5 protocol is defined as follows:
C++
Shrink ▲
#ifndef __CSOCKS_HEADER
#define __CSOCKS_HEADER

#include "common.h"
#include "cauth.h"

class CSocks {
private:

public:
PSOCKSNOTIFYPROC pNotifyProc;
u_short uPort, mode;
u_int uAccept;
u_long LastError;
CSocksBasicAuth* basicauth = NULL;

CSocks() {
uAccept = 0;
mode = SOCKS_MODE_TCP;
uPort = SOCKS_DEF_PORT;
LastError = SOCKS_ERROR_NONE;
pNotifyProc = NULL;
};

~CSocks() {
if(uAccept) closesock(uAccept);
};

bool DNSAddrLookup(char* sHost, struct in_addr* addr);


bool StartChaining();
bool SocksTCPTunneling(u_int sres, u_int sdest);
bool SocksUDPTunneling(void* sadest, char* sData, u_int len);
bool PrepareListening();
char* GetLastError();
virtual bool ForceConnection(u_int sock) = 0;
};

#endif

We present this class for the example realization of the network operation like tunneling when the
network data are passed through the mediate socket - this concept primarily is used in proxy
software, this operation is defined as follows ( sres and sdest are sockets between which the
tunneling operation performs):

C++
Shrink ▲
bool CSocks::SocksTCPTunneling(u_int sres, u_int sdest)
{
register u_int sockr, sockw, ret;
register u_int uread, uwrote;
char szBuffer[1024];
struct fd_set fd;
struct timeval tv = {0,0};

do
{
FD_ZERO(&fd);
FD_SET(sres,&fd);
FD_SET(sdest,&fd);

if((ret = select(0,&fd,NULL,NULL,&tv))>0 && VALID_SOCKET(ret))


{
if(FD_ISSET(sres,&fd))
{
sockr = sres;
sockw = sdest;
}
else
{
sockr = sdest;
sockw = sres;
}

uread = recv(sockr,szBuffer,1023,0);

if (uread >= 1023) break;

szBuffer[uread] = 0;
uwrote = 0;
if(!VALID_SOCKET(uread) || uread==0) break;

while(uwrote<uread)
{
ret = send(sockw,szBuffer+uwrote,uread-uwrote,0);
if(!VALID_SOCKET(ret)) goto __quit;
uwrote += ret;
}
}

FD_ZERO(&fd);
FD_SET(sres,&fd);
FD_SET(sdest,&fd);
if(select(0,NULL,NULL,&fd,&tv)>0) break;
} while(1);

__quit:
return(true);
}

That's all for now, other minor procedures and functions can be studied from our repositories,
however, all the above represent the necessary knowledge in order to work with sockets on system
level in C++ programming language.

Points of Interest
Thus, we have learned how to adopt sockets layer model for particular network tasks for better
performance and more deep functionality and assessment.

You might also like