Skip to content

Commit

Permalink
MAJOR: Transform to Header-only library.
Browse files Browse the repository at this point in the history
  • Loading branch information
eminfedar committed Sep 9, 2021
1 parent e261b5c commit ac946e4
Show file tree
Hide file tree
Showing 30 changed files with 569 additions and 870 deletions.
44 changes: 0 additions & 44 deletions CMakeLists.txt

This file was deleted.

55 changes: 0 additions & 55 deletions MakeHelper

This file was deleted.

10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Asynchronous Sockets for C++
Simple, thread-based, non-blocking asynchronous Client-Server classes in C++ for TCP & UDP.
Simple, multithread-based(not thread safe), non-blocking asynchronous Client-Server classes in C++ for TCP & UDP.
Creates a thread for every connection. Use `mutex`es or `atomic` variables to provide thread-safe functions.

```cpp
// Initialize a tcp socket.
Expand Down Expand Up @@ -27,6 +28,7 @@ You can compile all the examples by just going in the `examples/` directory and
- [examples/tcp-server.cpp](https://github.com/eminfedar/async-sockets-cpp/blob/master/examples/tcp-server.cpp)
- [examples/udp-client.cpp](https://github.com/eminfedar/async-sockets-cpp/blob/master/examples/udp-client.cpp)
- [examples/udp-server.cpp](https://github.com/eminfedar/async-sockets-cpp/blob/master/examples/udp-server.cpp)

## Future TO-DOs:
- Add Windows support (the library is only for *nix based systems like Linux & MacOS.)

## Supported Platforms:
- Linux
- MacOS (not tested)
70 changes: 70 additions & 0 deletions async-sockets/include/basesocket.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#pragma once

#if defined(__linux__) || defined(__APPLE__)
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <netdb.h>
#elif _WIN32
#include <winsock32.h>
#endif

#include <string>
#include <functional>
#include <cerrno>

#define FDR_UNUSED(expr){ (void)(expr); }
#define FDR_ON_ERROR std::function<void(int, std::string)> onError = [](int errorCode, std::string errorMessage){FDR_UNUSED(errorCode); FDR_UNUSED(errorMessage)}

class BaseSocket
{
// Definitions
public:
enum SocketType
{
TCP = SOCK_STREAM,
UDP = SOCK_DGRAM
};
const uint16_t BUFFER_SIZE = 0xFFFF;
sockaddr_in address;
bool isClosed = false;

protected:
int sock = 0;
static std::string ipToString(sockaddr_in addr)
{
char ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(addr.sin_addr), ip, INET_ADDRSTRLEN);

return std::string(ip);
}

BaseSocket(FDR_ON_ERROR, SocketType sockType = TCP, int socketId = -1)
{
if (socketId < 0)
{
if ((this->sock = socket(AF_INET, sockType, 0)) < 0)
{
onError(errno, "Socket creating error.");
}
}
else
{
this->sock = socketId;
}
}

// Methods
public:
virtual void Close() {
if(isClosed) return;

isClosed = true;
close(this->sock);
}

std::string remoteAddress() {return ipToString(this->address);}
int remotePort() {return ntohs(this->address.sin_port);}
int fileDescriptor() const { return this->sock; }
};
87 changes: 87 additions & 0 deletions async-sockets/include/tcpserver.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#pragma once

#include "tcpsocket.hpp"
#include <thread>

class TCPServer : public BaseSocket
{
public:
// Event Listeners:
std::function<void(TCPSocket *)> onNewConnection = [](TCPSocket* sock){FDR_UNUSED(sock)};

explicit TCPServer(FDR_ON_ERROR): BaseSocket(onError, SocketType::TCP)
{
int opt = 1;
setsockopt(this->sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(int));
setsockopt(this->sock,SOL_SOCKET,SO_REUSEPORT,&opt,sizeof(int));
}

// Binding the server.
void Bind(const char *address, uint16_t port, FDR_ON_ERROR)
{
if (inet_pton(AF_INET, address, &this->address.sin_addr) <= 0)
{
onError(errno, "Invalid address. Address type not supported.");
return;
}

this->address.sin_family = AF_INET;
this->address.sin_port = htons(port);

if (bind(this->sock, (const sockaddr *)&this->address, sizeof(this->address)) < 0)
{
onError(errno, "Cannot bind the socket.");
return;
}
}
void Bind(int port, FDR_ON_ERROR) { this->Bind("0.0.0.0", port, onError); }

// Start listening the server.
void Listen(FDR_ON_ERROR)
{
if (listen(this->sock, 20) < 0)
{
onError(errno, "Error: Server can't listen the socket.");
return;
}

std::thread t(Accept, this, onError);
t.detach();
}

// Overriding Close to add shutdown():
void Close()
{
shutdown(this->sock, SHUT_RDWR);

BaseSocket::Close();
}

private:
static void Accept(TCPServer *server, FDR_ON_ERROR)
{
sockaddr_in newSocketInfo;
socklen_t newSocketInfoLength = sizeof(newSocketInfo);

int newSock;
while (!server->isClosed)
{
while ((newSock = accept(server->sock, (sockaddr *)&newSocketInfo, &newSocketInfoLength)) < 0)
{
if (errno == EBADF || errno == EINVAL) return;

onError(errno, "Error while accepting a new connection.");
return;
}

if (!server->isClosed && newSock >= 0)
{
TCPSocket *newSocket = new TCPSocket(onError, newSock);
newSocket->setAddressStruct(newSocketInfo);

server->onNewConnection(newSocket);
newSocket->Listen();
}
}
}
};
Loading

0 comments on commit ac946e4

Please sign in to comment.