Skip to content

Commit bdde239

Browse files
committed
First commit.
0 parents  commit bdde239

30 files changed

+8059
-0
lines changed

Socket/Socket.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/**
2+
* @file Socket.cpp
3+
* @brief implementation of the Socket class
4+
* @author Mohamed Amine Mzoughi <[email protected]>
5+
*/
6+
7+
#include "Socket.h"
8+
9+
// Static members initialization
10+
volatile int ASocket::s_iSocketCount = 0;
11+
std::mutex ASocket::s_mtxCount;
12+
WSADATA ASocket::s_wsaData;
13+
14+
/**
15+
* @brief constructor of the Socket
16+
*
17+
* @param Logger - a callabck to a logger function void(const std::string&)
18+
*
19+
*/
20+
ASocket::ASocket(LogFnCallback oLogger) :
21+
m_oLog(oLogger)
22+
{
23+
s_mtxCount.lock();
24+
if (s_iSocketCount++ == 0)
25+
{
26+
#ifdef WINDOWS
27+
/* In windows, this will init the winsock stuff */
28+
int iWinSockInitResult = WSAStartup(MAKEWORD(2, 2), &s_wsaData);
29+
30+
// MAKEWORD(2,2) version 2.2 of Winsock
31+
if (iWinSockInitResult != 0)
32+
{
33+
m_oLog(StringFormat("[TCPClient][Error] WSAStartup failed : %d", iWinSockInitResult));
34+
}
35+
#endif
36+
}
37+
s_mtxCount.unlock();
38+
}
39+
40+
/**
41+
* @brief destructor of the socket object
42+
* It's a pure virtual destructor but an implementation is provided below.
43+
* this to avoid creating a dummy pure virtual method to transform the class
44+
* to an abstract one.
45+
*/
46+
ASocket::~ASocket()
47+
{
48+
s_mtxCount.lock();
49+
if (--s_iSocketCount <= 0)
50+
{
51+
#ifdef WINDOWS
52+
/* call WSACleanup when done using the Winsock dll */
53+
WSACleanup();
54+
#endif
55+
}
56+
s_mtxCount.unlock();
57+
}
58+
59+
/**
60+
* @brief returns a formatted string
61+
*
62+
* @param [in] strFormat string with one or many format specifiers
63+
* @param [in] parameters to be placed in the format specifiers of strFormat
64+
*
65+
* @retval string formatted string
66+
*/
67+
std::string ASocket::StringFormat(const std::string strFormat, ...)
68+
{
69+
int n = (static_cast<int>(strFormat.size())) * 2; // Reserve two times as much as the length of the strFormat
70+
71+
std::unique_ptr<char[]> pFormatted;
72+
73+
va_list ap;
74+
75+
while (true)
76+
{
77+
pFormatted.reset(new char[n]); // Wrap the plain char array into the unique_ptr
78+
strcpy(&pFormatted[0], strFormat.c_str());
79+
80+
va_start(ap, strFormat);
81+
int iFinaln = vsnprintf(&pFormatted[0], n, strFormat.c_str(), ap);
82+
va_end(ap);
83+
84+
if (iFinaln < 0 || iFinaln >= n)
85+
{
86+
n += abs(iFinaln - n + 1);
87+
}
88+
else
89+
{
90+
break;
91+
}
92+
}
93+
94+
return std::string(pFormatted.get());
95+
}

Socket/Socket.h

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* @file Socket.h
3+
* @brief Abstract class to perform API global operations
4+
*
5+
* @author Mohamed Amine Mzoughi <[email protected]>
6+
* @date 2017-02-10
7+
*/
8+
9+
#ifndef INCLUDE_ASOCKET_H_
10+
#define INCLUDE_ASOCKET_H_
11+
12+
#include <cstdio> // snprintf
13+
#include <exception>
14+
#include <functional>
15+
#include <mutex>
16+
#include <stdarg.h> // va_start, etc.
17+
#include <stdexcept>
18+
19+
#ifdef WINDOWS
20+
#include <winsock2.h>
21+
#include <ws2tcpip.h>
22+
23+
// Need to link with Ws2_32.lib
24+
#pragma comment(lib,"WS2_32.lib")
25+
#endif
26+
27+
class ASocket
28+
{
29+
public:
30+
// Public definitions
31+
//typedef std::function<int(void*, double, double, double, double)> ProgressFnCallback;
32+
typedef std::function<void(const std::string&)> LogFnCallback;
33+
34+
// socket file descriptor id
35+
#ifdef WINDOWS
36+
typedef SOCKET Socket;
37+
#else
38+
39+
#endif
40+
41+
enum SettingsFlag
42+
{
43+
NO_FLAGS = 0x00,
44+
ENABLE_LOG = 0x01,
45+
// ENABLE_SSL = 0x02, // OpenSSL
46+
ALL_FLAGS = 0xFF
47+
};
48+
49+
/* Please provide your logger thread-safe routine, otherwise, you can turn off
50+
* error log messages printing by not using the flag ALL_FLAGS or ENABLE_LOG */
51+
explicit ASocket(LogFnCallback oLogger);
52+
virtual ~ASocket() = 0;
53+
54+
inline static int GetSocketCount() { return s_iSocketCount; }
55+
56+
protected:
57+
// String Helpers
58+
static std::string StringFormat(const std::string strFormat, ...);
59+
60+
// Log printer callback
61+
/*mutable*/ LogFnCallback m_oLog;
62+
63+
volatile static int s_iSocketCount; // Count of the actual socket sessions
64+
static std::mutex s_mtxCount; // mutex used to sync API global operations
65+
66+
#ifdef WINDOWS
67+
static WSADATA s_wsaData;
68+
#endif
69+
70+
};
71+
72+
class EResolveError : public std::logic_error
73+
{
74+
public:
75+
explicit EResolveError(const std::string &strMsg) : std::logic_error(strMsg) {}
76+
};
77+
78+
#endif

Socket/TCPClient.cpp

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
/**
2+
* @file TCPClient.cpp
3+
* @brief implementation of the TCP client class
4+
* @author Mohamed Amine Mzoughi <[email protected]>
5+
*/
6+
7+
#include "TCPClient.h"
8+
9+
CTCPClient::CTCPClient(LogFnCallback oLogger) :
10+
ASocket(oLogger),
11+
m_eStatus(DISCONNECTED),
12+
m_ConnectSocket(INVALID_SOCKET),
13+
m_pResultAddrInfo(nullptr)
14+
//m_uRetryCount(0),
15+
//m_uRetryPeriod(0)
16+
{
17+
18+
}
19+
20+
// Connexion au serveur
21+
bool CTCPClient::Connect(const std::string& strServer, const std::string& strPort)
22+
{
23+
if (m_eStatus == CONNECTED)
24+
{
25+
Disconnect();
26+
m_oLog("[TCPClient][Warning] Opening a new connexion. The last one was automatically closed.");
27+
}
28+
29+
ZeroMemory(&m_HintsAddrInfo, sizeof(m_HintsAddrInfo));
30+
/* AF_INET is used to specify the IPv4 address family. */
31+
m_HintsAddrInfo.ai_family = AF_INET;
32+
/* SOCK_STREAM is used to specify a stream socket. */
33+
m_HintsAddrInfo.ai_socktype = SOCK_STREAM;
34+
/* IPPROTO_TCP is used to specify the TCP protocol. */
35+
m_HintsAddrInfo.ai_protocol = IPPROTO_TCP;
36+
37+
/* Resolve the server address and port */
38+
int iResult = getaddrinfo(strServer.c_str(), strPort.c_str(), &m_HintsAddrInfo, &m_pResultAddrInfo);
39+
if (iResult != 0)
40+
{
41+
m_oLog(StringFormat("[TCPClient][Error] getaddrinfo failed : %d", iResult));
42+
43+
if (m_pResultAddrInfo != nullptr)
44+
{
45+
freeaddrinfo(m_pResultAddrInfo);
46+
m_pResultAddrInfo = nullptr;
47+
}
48+
49+
return false;
50+
}
51+
52+
// socket creation
53+
m_ConnectSocket = socket(m_pResultAddrInfo->ai_family,
54+
m_pResultAddrInfo->ai_socktype,
55+
m_pResultAddrInfo->ai_protocol);
56+
57+
if (m_ConnectSocket == INVALID_SOCKET)
58+
{
59+
m_oLog(StringFormat("[TCPClient][Error] socket failed : %d", WSAGetLastError()));
60+
freeaddrinfo(m_pResultAddrInfo);
61+
m_pResultAddrInfo = nullptr;
62+
return false;
63+
}
64+
65+
/*
66+
SOCKET ConnectSocket = INVALID_SOCKET;
67+
struct sockaddr_in clientService;
68+
69+
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
70+
if (ConnectSocket == INVALID_SOCKET) {
71+
printf("Error at socket(): %ld\n", WSAGetLastError());
72+
WSACleanup();
73+
return 1;
74+
}
75+
76+
// The sockaddr_in structure specifies the address family,
77+
// IP address, and port of the server to be connected to.
78+
clientService.sin_family = AF_INET;
79+
clientService.sin_addr.s_addr = inet_addr("127.0.0.1");
80+
clientService.sin_port = htons(27015);
81+
*/
82+
83+
// connexion to the server
84+
//unsigned uRetry = 0;
85+
//do
86+
//{
87+
iResult = connect(m_ConnectSocket,
88+
m_pResultAddrInfo->ai_addr,
89+
static_cast<int>(m_pResultAddrInfo->ai_addrlen));
90+
//iResult = connect(m_ConnectSocket, (SOCKADDR*)&clientService, sizeof(clientService));
91+
92+
//if (iResult != SOCKET_ERROR)
93+
//break;
94+
95+
// retry mechanism
96+
//if (uRetry < m_uRetryCount)
97+
//m_oLog(StringFormat("[TCPClient][Error] connect retry %u after %u second(s)", m_uRetryCount + 1, m_uRetryPeriod));
98+
99+
//if (m_uRetryPeriod > 0)
100+
//{
101+
//for (unsigned uSec = 0; uSec < m_uRetryPeriod; uSec++)
102+
//Sleep(1000);
103+
//}
104+
//} while (iResult == SOCKET_ERROR && ++uRetry < m_uRetryCount);
105+
106+
freeaddrinfo(m_pResultAddrInfo);
107+
m_pResultAddrInfo = nullptr;
108+
109+
if (iResult != SOCKET_ERROR)
110+
{
111+
m_eStatus = CONNECTED;
112+
return true;
113+
}
114+
m_oLog(StringFormat("[TCPClient][Error] Unable to connect to server : %d", WSAGetLastError()));
115+
116+
return false;
117+
}
118+
119+
bool CTCPClient::SendData(const char* pData, size_t uSize) const
120+
{
121+
if (m_eStatus != CONNECTED)
122+
{
123+
m_oLog("[TCPClient][Error] send failed : not connected to a server.");
124+
return false;
125+
}
126+
127+
int iResult = send(m_ConnectSocket, pData, uSize, 0);
128+
if (iResult == SOCKET_ERROR)
129+
{
130+
m_oLog(StringFormat("[TCPClient][Error] send failed : %d", WSAGetLastError()));
131+
//Disconnect();
132+
return false;
133+
}
134+
135+
return true;
136+
}
137+
138+
bool CTCPClient::SendData(const std::string& strData) const
139+
{
140+
return SendData(strData.c_str(), strData.length());
141+
}
142+
143+
bool CTCPClient::SendData(const std::vector<char>& Data) const
144+
{
145+
return SendData(Data.data(), Data.size());
146+
}
147+
148+
bool CTCPClient::Disconnect()
149+
{
150+
if (m_eStatus != CONNECTED)
151+
return true;
152+
153+
m_eStatus = DISCONNECTED;
154+
155+
// shutdown the connection since no more data will be sent
156+
int iResult = shutdown(m_ConnectSocket, SD_SEND);
157+
if (iResult == SOCKET_ERROR)
158+
{
159+
m_oLog(StringFormat("[TCPClient][Error] shutdown failed : %d", WSAGetLastError()));
160+
return false;
161+
}
162+
closesocket(m_ConnectSocket);
163+
164+
m_ConnectSocket = INVALID_SOCKET;
165+
166+
if (m_pResultAddrInfo != nullptr)
167+
{
168+
freeaddrinfo(m_pResultAddrInfo);
169+
m_pResultAddrInfo = nullptr;
170+
}
171+
172+
return true;
173+
}
174+
175+
CTCPClient::~CTCPClient()
176+
{
177+
if (m_eStatus == CONNECTED)
178+
Disconnect();
179+
180+
181+
}

0 commit comments

Comments
 (0)