168 lines
3.9 KiB
C++
168 lines
3.9 KiB
C++
#include "TcpSocket.hpp"
|
|
|
|
#include <arpa/inet.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <netdb.h>
|
|
|
|
#include <string>
|
|
#include <functional>
|
|
#include <cerrno>
|
|
#include <cstring>
|
|
#include <thread>
|
|
|
|
namespace TcpSocket
|
|
{
|
|
|
|
void setTimeout(int seconds, int sock)
|
|
{
|
|
struct timeval tv;
|
|
tv.tv_sec = seconds;
|
|
tv.tv_usec = 0;
|
|
|
|
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
|
|
setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv));
|
|
}
|
|
|
|
ssize_t sendt(int sock, const void *bytes, size_t byteslength) { return send(sock, bytes, byteslength, 0); }
|
|
|
|
ssize_t recvt(int sock, void *bytes, size_t byteslength) { return recv(sock, bytes, byteslength, 0); }
|
|
|
|
void closet(int sock)
|
|
{
|
|
shutdown(sock, SHUT_RDWR);
|
|
close(sock);
|
|
}
|
|
|
|
std::string remoteAddress(sockaddr_in &address)
|
|
{
|
|
char ip[INET_ADDRSTRLEN];
|
|
inet_ntop(AF_INET, &(address.sin_addr), ip, INET_ADDRSTRLEN);
|
|
|
|
return std::string(ip);
|
|
}
|
|
|
|
int remotePort(sockaddr_in &address) { return ntohs(address.sin_port); }
|
|
|
|
int connectt(const char *host, uint16_t port)
|
|
{
|
|
struct addrinfo hints, *res, *it;
|
|
memset(&hints, 0, sizeof(hints));
|
|
hints.ai_family = AF_INET;
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
// Get address info from DNS
|
|
int status = getaddrinfo(host, NULL, &hints, &res);
|
|
if (status != 0)
|
|
{
|
|
// onError(errno, "Invalid address." + std::string(gai_strerror(status)));
|
|
return -1;
|
|
}
|
|
|
|
sockaddr_in address;
|
|
for (it = res; it != NULL; it = it->ai_next)
|
|
{
|
|
if (it->ai_family == AF_INET)
|
|
{ // IPv4
|
|
memcpy((void *)(&address), (void *)it->ai_addr, sizeof(sockaddr_in));
|
|
break; // for now, just get the first ip (ipv4).
|
|
}
|
|
}
|
|
|
|
freeaddrinfo(res);
|
|
|
|
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
if (sock == -1)
|
|
{
|
|
// onError(errno, "Socket creating error.");
|
|
return -2;
|
|
}
|
|
|
|
address.sin_family = AF_INET;
|
|
address.sin_port = htons(port);
|
|
|
|
// setTimeout(5, sock);
|
|
|
|
// Try to connect.
|
|
status = connect(sock, (const sockaddr *)&address, sizeof(sockaddr_in));
|
|
if (status == -1)
|
|
{
|
|
// onError(errno, "Connection failed to the host.");
|
|
close(sock);
|
|
return -3;
|
|
}
|
|
return sock;
|
|
}
|
|
|
|
int listent(const char *host, uint16_t port, OnNewConnectionCallBack callback)
|
|
{
|
|
sockaddr_in address;
|
|
|
|
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
if (sock == -1)
|
|
{
|
|
// onError(errno, "Socket creating error.");
|
|
return -1;
|
|
}
|
|
|
|
int opt = 1;
|
|
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));
|
|
setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(int));
|
|
|
|
int status = inet_pton(AF_INET, host, &address.sin_addr);
|
|
switch (status)
|
|
{
|
|
case -1:
|
|
close(sock);
|
|
// onError(errno, "Invalid address. Address type not supported.");
|
|
return -2;
|
|
case 0:
|
|
close(sock);
|
|
// onError(errno, "AF_INET is not supported. Please send message to developer.");
|
|
return -3;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
address.sin_family = AF_INET;
|
|
address.sin_port = htons(port);
|
|
|
|
if (bind(sock, (const sockaddr *)&address, sizeof(address)) == -1)
|
|
{
|
|
// onError(errno, "Cannot bind the socket.");
|
|
close(sock);
|
|
return -4;
|
|
}
|
|
if (listen(sock, 20) == -1)
|
|
{
|
|
// onError(errno, "Error: Server can't listen the socket.");
|
|
close(sock);
|
|
return -5;
|
|
}
|
|
|
|
sockaddr_in newSocketInfo;
|
|
socklen_t newSocketInfoLength = sizeof(newSocketInfo);
|
|
|
|
int newSocketFileDescriptor = -1;
|
|
while (true)
|
|
{
|
|
newSocketFileDescriptor = accept(sock, (sockaddr *)&newSocketInfo, &newSocketInfoLength);
|
|
if (newSocketFileDescriptor == -1)
|
|
{
|
|
if (errno == EBADF || errno == EINVAL)
|
|
return -6;
|
|
|
|
return -7;
|
|
}
|
|
|
|
std::thread t(callback, newSocketFileDescriptor, newSocketInfo);
|
|
t.detach();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
} |