// sos.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "sos.h"
#include "string.h"
#include "winsock2.h"
#include "process.h"
#include <sys/types.h>
#include <sys/timeb.h>
#include <io.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include "signal.h"
/********************************************************************
* *
* Echo Server (Gennaio 2001) *
* *
* Port 3123 TCP/IP protocol *
* *
* Il client invia un messaggio formato da un numero *
* intero (4 byte) seguito dai byte di cui si vuole avere l'echo. *
* Il server risponde allo stesso modo. *
* *
* Il progetto va fatto come "applicazione da console" *
* Linkare con ws2_32.lib *
* *
* ATTENZIONE: ci sono due problemi: *
* non funziona la free di una variabile dinamica *
* (controllare il manuale della libreria MS *
* il time out sul close socket (aspetta finche' non e' stato *
* spedito tutto il contenuto del buffer) funziona su *
* WindowsNT ma non su Windows98. *
* Lasciare lo Sleep di 1 sec. *
* *
*********************************************************************/
// CWinApp theApp; // trick to use C++ classes
using namespace std;
void main(int argc, TCHAR* argv[], TCHAR* envp[])
{
SOCKADDR_IN accept_sin; // Receives the address of the
// connecting entity
int accept_sin_len; // Length of accept_sin
// initialize MFC and print an error on failure
if (!AfxWinInit(::GetModuleHandle(NULL), NULL,
::GetCommandLine(), 0))
{
ErrF1 (SMFC, 0);
exit(1);
}
clog << "Start echo server" << endl;
clog << endl;
signal(SIGINT, intr_ctrC); // catch ^C
startConn(); // starts TCP/IP connection
accept_sin_len = sizeof (accept_sin);
for (;;)
{
// Accept an incoming connection attempt on WinSocket.
tmpSock=accept (WinSocket,
(struct sockaddr *) &accept_sin,(int *) &accept_sin_len);
// Stop listening for connections from clients.
if (tmpSock == INVALID_SOCKET)
{
ErrF1(Sacc, WSAGetLastError());
continue;
}
flag=1;
errorThread=_beginthread(parse, 0, NULL);
if (errorThread < 0)
{
flag=0;
ErrF1(Sthread, errno);
closesocket(tmpSock);
continue;
}
while (flag) ; // tmpSock and endthread can be reassigned
} // end for
}
// thread function
void parse (void *dummy)
{
SOCKET ClientSock = INVALID_SOCKET; // Socket for connection
unsigned long IdThread; // thread identifier
char * msg=NULL;
int len;
ClientSock=tmpSock;
IdThread = errorThread;
flag=0; // =1 until the socket and thread id have been copied
clog << "begin thread " << IdThread << endl;
options(ClientSock, IdThread); // set socket options
if ((recvS (ClientSock, IdThread, (char *)&len, 4))<0) goto exitT;
if ((len <= 0))
ErrF2(ClientSock, IdThread, Ssize, 0);
msg=Alloc(ClientSock, IdThread, len);
if ((recvS (ClientSock, IdThread, msg, len))<0) goto exitT;
if ((sendS(ClientSock, IdThread, (char *)&len, 4))<0) goto exitT;
if ((sendS(ClientSock, IdThread, msg, len))<0) goto exitT;
Sleep (1000);
exitT:
// if (msg != NULL) free((void *)msg); non funziona!!!
closesocket(ClientSock);
clog << "end Thread " << IdThread << endl;
_endthread();
}
/************************************************
************************************************
******* ********
******* Auxiliary Routines ********
******* ********
************************************************
************************************************/
/* create WinSocket, the primary socket, and get socket options */
void startConn()
{
WSADATA WSAData; // Contains details of the Windows
SOCKADDR_IN local_sin; // Local socket address
int len, ret;
// Initiate Windows Sockets (WinSock Version 1.1)
if (WSAStartup (MAKEWORD(1,1), &WSAData) != 0)
{
ErrF1(SWSA, WSAGetLastError());
WSACleanup();
exit(1);
}
// Create a TCP/IP socket, WinSocket.
if ((WinSocket = socket (AF_INET, SOCK_STREAM,
IPPROTO_TCP)) == INVALID_SOCKET)
{
ErrF1(Salloc, WSAGetLastError());
WSACleanup();
exit(1);
}
len=4; // get the send buffer length
ret=getsockopt(WinSocket, SOL_SOCKET, SO_SNDBUF,
(char *)&sendBuf, &len);
if (ret==SOCKET_ERROR)
ErrF0(WinSocket, SsendT, WSAGetLastError());
clog << "send buffer length = " << sendBuf << endl;
len=4; // get the recv buffer length
ret=getsockopt(WinSocket, SOL_SOCKET, SO_RCVBUF,
(char *)&recvBuf, &len);
if (ret==SOCKET_ERROR)
ErrF0(WinSocket, Sopt, WSAGetLastError());
clog << "recv buffer length = " << recvBuf << endl;
// Fill out the local socket's address information.
local_sin.sin_family = AF_INET;
local_sin.sin_port = htons (PORT);
local_sin.sin_addr.s_addr = htonl (INADDR_ANY);
// Associate the local address with WinSocket.
if (bind (WinSocket, (struct sockaddr *) &local_sin,
sizeof (local_sin)) == SOCKET_ERROR)
ErrF0(WinSocket, Sbind, WSAGetLastError());
// Establish a socket to listen for incoming connections.
if (listen (WinSocket, BACKLOG) == SOCKET_ERROR)
ErrF0(WinSocket, Slisten, WSAGetLastError());
}
/* set winsock options */
void options(SOCKET LocalSock, unsigned long IdThread)
{
int optval, ret;
optval=0; // consider time out on close
ret=setsockopt(LocalSock, SOL_SOCKET, SO_DONTLINGER,
(char *)&optval, 4);
if (ret==SOCKET_ERROR)
ErrF2(LocalSock, IdThread, Sdont, WSAGetLastError());
optval=CLOSE_TIMEOUT; // set the timeout value on close socket
ret=setsockopt(LocalSock, SOL_SOCKET, SO_LINGER,
(char *)&optval, 4);
if (ret==SOCKET_ERROR)
ErrF2(LocalSock, IdThread, Slinger, WSAGetLastError());
clog << "closesocket time out = " << CLOSE_TIMEOUT << endl;
optval=RCV_TIMEOUT; // time out on recv
ret=setsockopt(LocalSock, SOL_SOCKET, SO_RCVTIMEO,
(char *)&optval, 4);
if (ret==SOCKET_ERROR)
ErrF2(LocalSock, IdThread, SrecvT, WSAGetLastError());
clog << "recv time out = " << RCV_TIMEOUT << endl;
optval=SND_TIMEOUT; // time out on send
ret=setsockopt(LocalSock, SOL_SOCKET, SO_SNDTIMEO,
(char *)&optval, 4);
if (ret==SOCKET_ERROR)
ErrF2(LocalSock, IdThread, SsendT, WSAGetLastError());
clog << "send time out = " << SND_TIMEOUT << endl;
}
/* Error procedures */
void ErrF0(SOCKET LocalSocket, char *strError, int error)
{
ErrF1(strError, error);
closesocket(LocalSocket);
WSACleanup();
exit(1);
}
void ErrF1 (char * strError, int error)
{
char szError[40];
if (error!=0) wsprintf(szError, "%s %d ", strError, error);
else wsprintf(szError, "%s ", strError);
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
}
void ErrF2 (SOCKET LocalSock, unsigned long IdThread,
char * strError, int error)
{
cerr << IdThread << " " << strError << error << endl;
closesocket(LocalSock);
_endthread();
}
/* send exactly nbytes bytes or close the connection */
int sendS (SOCKET LocalSock, unsigned long IdThread,
char *ptr, int nbytes)
{
int nleft, nwritten;
nleft = nbytes;
while (nleft > 0)
{
nwritten = send (LocalSock, ptr, nleft, 0);
if (nwritten == SOCKET_ERROR)
{
cerr << IdThread << " " << Ssend << WSAGetLastError() << endl;
return -1;
}
nleft -= nwritten;
ptr += nwritten;
}
return 0;
}
/* recv a string (ptr_in) sized len or close connection. */
int recvS (SOCKET LocalSock, unsigned long IdThread,
char *ptr_in, int len)
{
int nleft, nrecv;
char * ptr;
ptr=ptr_in;
nleft=len;
while (nleft > 0)
{
nrecv = recv (LocalSock, ptr, nleft, 0);
if (nrecv == 0) // connection closed by the client
{
cerr << IdThread << " " << Snocon << endl;
return -1;
}
if (nrecv == SOCKET_ERROR)
{
cerr << IdThread << " " << Srecv << WSAGetLastError() << endl;
return -1;
}
nleft -= nrecv;
ptr += nrecv;
}
ptr_in[len]='\0';
return 0;
}
void intr_ctrC(int sig) // cattura ^C e termina su richiesta
{
char ch[2];
signal(SIGINT, intr_ctrC); // catch ^C
printf("Do you really want to abort? (y) > ");
scanf("%s", ch);
if ('y'==ch[0]) exit(1);
return;
}
/* This function allocates len characters */
char * Alloc(SOCKET LocalSock, unsigned long IdThread, int len)
{
char * String;
String = (char *) malloc(len);
if( String == NULL )
{
cerr << IdThread << " " << _T("Insufficient memory available ") << endl;
closesocket(LocalSock);
WSACleanup ();
exit(1);
}
return String;
}
File header
// sos.h
//////////////////////////////////////////////////////////
#include "string.h"
#include "winsock2.h"
#include "process.h"
#include <sys/types.h>
#include <sys/timeb.h>
const int PORT=3123; // server port number
const int BACKLOG=4; // max. connection in listen state
// socket options
const int SND_TIMEOUT=100000;
const int RCV_TIMEOUT=100000;
const int CLOSE_TIMEOUT=40000; // SO_LINGER option
#define SMFC "Fatal Error: MFC initialization failed. "
#define SWSA "WSAStartup failed. Error: "
#define Salloc "Allocating socket failed. Error: "
#define Sbind "Binding socket failed. Error: "
#define Slisten "Listening to the client failed. Error: "
#define Sacc "Accepting connection with client failed. Error "
#define Sopt "Socket option Error: "
#define Sdont "SO_DONTLINGER option not accepted. Error: "
#define Slinger "SO_LINGER option not accepted. Error: "
#define SrecvT "SO_RCVTIMEO option not accepted. Error: "
#define SsendT "SO_SNDTIMEO option not accepted. Error: "
#define Sthread "Thread cannot be started. Error: " // threadErr
#define Ssend "Sending data to client failed. Error: "
#define Srecv "Recv failed. Error: "
#define Snocon "Connection closed by the client "
#define Ssize "Error: Wrong recv string size "
//int recvI (SOCKET LocalSock, unsigned long IdThread, int *val);
int recvS (SOCKET LocalSock, unsigned long IdThread,
char *ptr_in, int len);
//int sendI (SOCKET LocalSock, unsigned long IdThread, int *val);
int sendS (SOCKET LocalSock, unsigned long IdThread,
char *ptr, int nbytes);
void startConn(); // start TCP/IP connection
void options(SOCKET LocalSock, unsigned long IdThread);
// set winsock options
char * Alloc(SOCKET LocalSock, unsigned long IdThread, int len);
void ErrF0(SOCKET LocalSocket, char *strError, int error);
void ErrF1 (char * strError, int error);
void ErrF2 (SOCKET LocalSock, unsigned long IdThread,
char * strError, int error);
void parse (void *dummy); // thread function
void intr_ctrC(int sig); // cattura ^C e termina su richiesta
SOCKET WinSocket = INVALID_SOCKET, // Window socket
tmpSock = INVALID_SOCKET; // Socket for connection
unsigned long errorThread; // thread identifier
int flag; // synchronization with thread
int sendBuf; // send buffer length
int recvBuf; // recv buffer lenght