Skip to content

Socket / SSLSocket library for Windows/Linux (32/64)

License

Notifications You must be signed in to change notification settings

Tomenz/SocketLib

Repository files navigation

Codacy Badge Build Status Build status CMake C/C++ CI CodeQL

SocketLib

Socket library written in c++11/14 for Windows/Linux (32/64)

  • IPv4 and IPv6 support
  • TCP and UDP support (both with SSL/TLS)
  • multi-cast support for IPv4 and IPv6
  • Enum all IP's on the host
  • notify if host ip comes up / changes / is removed
  • TLS 1.3 if openssl 1.1.1 or newer is used
  • Multi-threading, none blocking. All callback function executed in own thread

Examples: https://github.com/Tomenz/Examples-SocketLib

In the Windows project files "OpenSSL_HOME" is stored for the "include" and "library" directories of openssl. You should create the enviroment variable, or change the include and library directories in the Visual Studio project files. In Linux, libssl-dev must be installed (Or the source code of openssl must be compiled and installed).

Meanwhile a short client / server example using the "SocketLib" library
*** The "SocketLib" library in this example should by compiled with WITHOUT_OPENSSL defined, so we don't need the opensll library
*** If you need SSL, you have to fix the path for the openssl headers and lib's when compiling the library

#include <thread>
#include <conio.h>
#include <sstream>
#include <iomanip>
#include <iostream>

#include "SocketLib.h"

using namespace std;

#ifdef _DEBUG
#ifdef _WIN64
#pragma comment(lib, "x64/Debug/socketlib64d")
#else
#pragma comment(lib, "Debug/socketlib32d")
#endif
#else
#ifdef _WIN64
#pragma comment(lib, "x64/Release/socketlib64")
#else
#pragma comment(lib, "Release/socketlib32")
#endif
#endif

void ServerThread(bool* bStop)
{
    TcpServer sock;

    sock.BindErrorFunction([&](BaseSocket* pSock) { cout << "Server: socket error" << endl; pSock->Close(); }); // Must call Close function
    sock.BindCloseFunction([&](BaseSocket*) { cout << "Server: socket closing" << endl; });

    // This Callback is called if a new client connects to the server.
    sock.BindNewConnection([&](const vector<TcpSocket*>& lstSockets)
        {
            for (auto& pSocket : lstSockets)
            {
                if (pSocket != nullptr)
                {
                    pSocket->BindFuncBytesReceived([&](TcpSocket* pTcpSocket)
                        {
                            size_t nAvailable = pTcpSocket->GetBytesAvailible();

                            auto spBuffer = make_unique<unsigned char[]>(nAvailable + 1);

                            size_t nRead = pTcpSocket->Read(&spBuffer[0], nAvailable);

                            if (nRead > 0)
                            {
                                string strRec(nRead, 0);
                                copy(&spBuffer[0], &spBuffer[nRead], &strRec[0]);

                                stringstream strOutput;
                                strOutput << pTcpSocket->GetClientAddr() << " - Server received: "
                                          << nRead << " Bytes, \"" << strRec << "\"" << endl;

                                cout << strOutput.str();

                                strRec = "Server echo: " + strRec;
                                pTcpSocket->Write(&strRec[0], strRec.size());

                                pTcpSocket->Close();
                            }
                        });
                    pSocket->BindErrorFunction([&](BaseSocket*) { cout << "Server: socket error" << endl; });
                    pSocket->BindCloseFunction([&](BaseSocket* pSock)
                        {
                            cout << "Server: socket closing" << endl;
                        });
                    pSocket->StartReceiving();
                }
            }
        });


    bool bCreated = sock.Start("0.0.0.0", 3461);  // or "::" for IPv6

    while (*bStop == false)
    {
        this_thread::sleep_for(chrono::milliseconds(10));
    }

    // Closing the server socket will not call the close callback
    sock.Close();
}

void ClientThread(bool* bStop)
{
    TcpSocket sock;

    sock.BindErrorFunction([&](BaseSocket* pSock) { cout << "Client: socket error" << endl; pSock->Close(); }); // Must call Close function
    sock.BindCloseFunction([&](BaseSocket*) { cout << "Client: socket closing" << endl; });
    sock.BindFuncBytesReceived([&](TcpSocket* pTcpSocket)
        {
            size_t nAvailable = pTcpSocket->GetBytesAvailible();

            auto spBuffer = make_unique<unsigned char[]>(nAvailable + 1);

            size_t nRead = pTcpSocket->Read(&spBuffer[0], nAvailable);

            if (nRead > 0)
            {
                string strRec(nRead, 0);
                copy(&spBuffer[0], &spBuffer[nRead], &strRec[0]);

                stringstream strOutput;
                strOutput << pTcpSocket->GetClientAddr() << " - Client received: "
                          << nRead << " Bytes, \"" << strRec << "\"" << endl;

                cout << strOutput.str();
            }
        });

    sock.BindFuncConEstablished([&](TcpSocket* pTcpSocket)
        {
            pTcpSocket->Write("Hallo World", 11);
        });

    bool bConnected = sock.Connect("127.0.0.1", 3461); // or "::1" for IPv6
    if (bConnected == false)
        cout << "error creating client socket" << endl;

    while (*bStop == false)
    {
        this_thread::sleep_for(chrono::milliseconds(10));
    }

    // The Close call will call the Callback function above
    // but if we leave the thread, the Instance is destroyed
    // and we crash. So we disable the Callback by setting a nullptr
    sock.BindCloseFunction(static_cast<function<void(BaseSocket*)>>(nullptr)));
    sock.Close();
}

int main(int argc, const char* argv[])
{
#if defined(_WIN32) || defined(_WIN64)
    // Detect Memory Leaks
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG));
#endif

    bool bStop = false;
    thread thServer = thread(bind(ServerThread, &bStop));
    this_thread::sleep_for(chrono::milliseconds(1000));
    thread thClient = thread(bind(ClientThread, &bStop));

    _getch();

    bStop = true;

    thServer.join();
    thClient.join();

    return 0;
}