1
\$\begingroup\$

I've decided to make a socket library in C++. To be honest i found it a bit tiring using winsock2 - I'd say it's a bit complex, comparing to for instance Python socket lib. My code, header file:

#pragma once
#pragma comment(lib,"WS2_32.lib")
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <windows.h>
#include <string>
#include <iostream>

enum flags{
    TCPType = 0,
    UDPType = 1
};

inline flags operator|(const flags& x, const flags& y){
    return static_cast<flags>(static_cast<int>(x)|static_cast<int>(y));
}

class Socket
{
private:
    std::string ip;
    std::string port;

    SOCKET* currentSocket = nullptr;

    bool isTcp;

public:
    Socket(flags f = TCPType);
    ~Socket();

    bool Connect(const std::string& address, const std::string& port);
    bool BindToPort(int p);
    bool Listen();
    bool isTcpType();

    int ReceiveAll(void* buffer, int size);
    int Receive(void* buffer, int size);
    int Sendall(void* buffer, int size);
    int Send(void* buffer, int size);

    std::string  getAddress() const;
    std::string  getPort() const;

    Socket* AcceptConnection();
    void close();

    static bool InitWinsock();
};

And the source file:

#include "pch.h"
#include "Socket.h"

Socket::Socket(flags f)
{
    isTcp = !f;

    auto connectionType = SOCK_DGRAM;
    auto b = 0;

    if (isTcp) {
        connectionType = SOCK_STREAM;
        b = IPPROTO_TCP;
    }

    SOCKET mainSocket = socket(AF_INET, connectionType, b);
    if (mainSocket == INVALID_SOCKET)
    {
        std::cerr << "Error creating socket: " << WSAGetLastError() << '\n';
        WSACleanup();
    }

    currentSocket = new SOCKET(mainSocket);
}

Socket::~Socket()
{
    if(currentSocket != nullptr)
        delete currentSocket;
}

bool Socket::Connect(const std::string& address, const std::string& port){
    addrinfo hints, *result = nullptr;

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    int iResult = getaddrinfo(address.c_str(), port.c_str(), &hints, &result);
    if (iResult != 0) {
        std::cerr << "getaddrinfo failed with error: " << iResult << '\n';
        WSACleanup();
        return false;
    }

    addrinfo *ptr = result;

    iResult = connect(*currentSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
    if (iResult == SOCKET_ERROR) {
        closesocket(*currentSocket);
        *currentSocket = INVALID_SOCKET;
    }

    return 0;
}

bool Socket::BindToPort(int p){
    if (currentSocket == nullptr)
        return false;

    sockaddr_in service;
    memset(&service, 0, sizeof(service));
    service.sin_family = AF_INET;
    InetPton(AF_INET, (PCWSTR)("127.0.0.1"), &service.sin_addr.s_addr);
    service.sin_port = htons(p);

    if(bind(*currentSocket, (SOCKADDR *)& service, sizeof(sockaddr)) == SOCKET_ERROR)
    {
        std::cerr << "Error during binding socket: " << WSAGetLastError() << '\n';
        closesocket(*currentSocket);
        return false;
    }

    this->port = p;

    return true;
}

bool Socket::Listen() {
    if (currentSocket == nullptr)
        return false;

    if(listen(*currentSocket, 1) == SOCKET_ERROR)
        std::cerr << "Error during trying to listen on socket: " << WSAGetLastError() << '\n';

    ip = "127.0.0.1";

    return true;
}

bool Socket::isTcpType(){
    return isTcp;
}

int Socket::ReceiveAll(void* buffer, int size) {
    int bytesLeft = size, current = 0;

    while (bytesLeft > 0) {
        int bytesRecv = recv(*currentSocket, static_cast<char*>(buffer), size, 0);

        if (bytesRecv < 0)
            return -1;

        bytesLeft -= bytesRecv;
    }

    return size;
}


int Socket::Receive(void* buffer, int size){
    if (currentSocket == nullptr)
        return -1;

    int bytesRecv = SOCKET_ERROR;

    while(bytesRecv == SOCKET_ERROR)
    {
        bytesRecv = recv(*currentSocket, static_cast<char*>(buffer), size, 0);

        if(bytesRecv == WSAECONNRESET)
            break;

        if (bytesRecv < 0)
            return -1;
    }

    return bytesRecv;
}

int Socket::Sendall(void* buffer, int size) {
    if (currentSocket == nullptr)
        return -1;

    int bytesSent = 0, counter = 0;

    while (counter < size) {
        bytesSent = send(*currentSocket, static_cast<const char*>(buffer), size, 0);
        counter += bytesSent;
    }

    return size;
}

int Socket::Send(void* buffer, int size){
    if (currentSocket == nullptr)
        return -1;

    int bytesSent, bytesRecv = SOCKET_ERROR;
    bytesSent = send(*currentSocket, static_cast<const char*>(buffer), size, 0);

    return bytesSent;
}

std::string  Socket::getAddress() const{
    return ip;
}

std::string  Socket::getPort() const{
    return port;
}

Socket* Socket::AcceptConnection(){
    if (currentSocket == nullptr)
        return false;

    SOCKET acceptSocket = SOCKET_ERROR;

    while (acceptSocket == SOCKET_ERROR)
    {
        acceptSocket = accept(*currentSocket, NULL, NULL);
    }

    Socket* result = new Socket(*this);
    result->currentSocket = new SOCKET(acceptSocket);

    return result;
}

void Socket::close() {
    closesocket(*currentSocket);
    delete currentSocket;
    WSACleanup();
}

bool Socket::InitWinsock() {
    WSADATA wsaData;

    int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (result != NO_ERROR) {
        std::cerr << "Error during initializing WinSock: " << WSAGetLastError() << '\n';
        return false;
    }

    return true;
}
\$\endgroup\$
1
  • \$\begingroup\$ Can you add some more context about how you want this code to be reviewed? Why did you choose to do things the way you did, what do you think can be improved? \$\endgroup\$
    – Linny
    May 9 '20 at 0:27
1
\$\begingroup\$

No need for this in modern C++:

Socket* AcceptConnection();

You should not be returning RAW pointers.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.