|
|
@ -4,12 +4,19 @@ |
|
|
|
* Kontrustruktor varijable tipa server, prima port i limit za ograničenje liste klijenata na čekanju |
|
|
|
* Kontrustruktor varijable tipa server, prima port i limit za ograničenje liste klijenata na čekanju |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
server::server (const ushort port, const uint limit) { |
|
|
|
server::server (const ushort port, const uint queue, SSL_CTX* _securefds) { |
|
|
|
|
|
|
|
securefds = _securefds;
|
|
|
|
|
|
|
|
|
|
|
|
addr.sin_family = AF_INET; |
|
|
|
addr.sin_family = AF_INET; |
|
|
|
addr.sin_addr.s_addr = INADDR_ANY; |
|
|
|
addr.sin_addr.s_addr = INADDR_ANY; |
|
|
|
addr.sin_port = htons(port); |
|
|
|
addr.sin_port = htons(port); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if _WIN32 |
|
|
|
|
|
|
|
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0) { |
|
|
|
|
|
|
|
throw string("[ERROR] WSA Startup. Detail: " + to_string(WSAGetLastError())); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
if (sock <= 0) {
|
|
|
|
if (sock <= 0) {
|
|
|
|
throw string("[ERROR] Unable to open TCP socket "); |
|
|
|
throw string("[ERROR] Unable to open TCP socket "); |
|
|
@ -17,20 +24,126 @@ server::server (const ushort port, const uint limit) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int opt=1; |
|
|
|
int opt=1; |
|
|
|
|
|
|
|
#if __linux__ |
|
|
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { |
|
|
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { |
|
|
|
throw string("[ERROR] Unable to set REUSEADDR or REUSEPORT on socket "); |
|
|
|
throw string("[ERROR] Unable to set REUSEADDR or REUSEPORT on socket "); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#elif _WIN32 |
|
|
|
|
|
|
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt))) { |
|
|
|
|
|
|
|
throw string("[ERROR] Unable to set REUSEADDR or REUSEPORT on socket "); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { |
|
|
|
if (bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { |
|
|
|
throw string("[ERROR] Unable to bind socket "); |
|
|
|
throw string("[ERROR] Unable to bind socket "); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (listen(sock, limit) < 0) { |
|
|
|
if (listen(sock, queue) < 0) { |
|
|
|
throw string("[ERROR] It is not possible to set the allowed number of waiting clients "); |
|
|
|
throw string("[ERROR] It is not possible to set the allowed number of waiting clients "); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Metoda za sinkroni rad s klijentima, prima pokazivač na funkciju i timeout; |
|
|
|
|
|
|
|
* Funkcija handlecli prima referencu tipa client - važno za definiranje funkcija koje se šalju; |
|
|
|
|
|
|
|
* Nije moguće proslijediti druge parametre; |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void server::sync(void (*handlecli)(client&), const uint timeout) { |
|
|
|
|
|
|
|
do { |
|
|
|
|
|
|
|
client cli(this, timeout, securefds); |
|
|
|
|
|
|
|
handlecli(cli); |
|
|
|
|
|
|
|
} while (true); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Metoda za asinkdorni rad s klijentima, prima limit, pokazivač na funkciju i timeout; |
|
|
|
|
|
|
|
* Funkcija handlecli prima referencu tipa client - važno za definiranje funkcija koje se šalju; |
|
|
|
|
|
|
|
* Nije moguće proslijediti druge parametre; |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void server::async(const uint limit, void (*handlecli)(client&, mutex&), const uint timeout) { |
|
|
|
|
|
|
|
mutex io; |
|
|
|
|
|
|
|
// do {
|
|
|
|
|
|
|
|
for (uint i=0; i<limit; i++) { |
|
|
|
|
|
|
|
thr.push_back(thread([&](){ |
|
|
|
|
|
|
|
client *cli = new client(this, timeout, securefds); |
|
|
|
|
|
|
|
while (true) { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
handlecli(*cli, io); |
|
|
|
|
|
|
|
} catch (const string err) { |
|
|
|
|
|
|
|
cout << err << endl; |
|
|
|
|
|
|
|
cli->~client(); |
|
|
|
|
|
|
|
cli = new client(this, timeout, securefds); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
})); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (uint i=0; i<limit; i++) { |
|
|
|
|
|
|
|
thr[i].join(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// thr.clear();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// } while (true);
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Metoda za sinkroni rad s klijentima, prima pokazivač na funkciju i timeout; |
|
|
|
|
|
|
|
* Funkcija handlecli prima referencu tipa client - važno za definiranje funkcija koje se šalju; |
|
|
|
|
|
|
|
* Nije moguće proslijediti druge parametre; |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// void server::syncPool(void (*handlecli)(client&), const uint timeout) {
|
|
|
|
|
|
|
|
// do {
|
|
|
|
|
|
|
|
// client cli(this, timeout, securefds);
|
|
|
|
|
|
|
|
// handlecli(cli);
|
|
|
|
|
|
|
|
// } while (true);
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Metoda za asinkdorni rad s klijentima, prima limit, pokazivač na funkciju i timeout; |
|
|
|
|
|
|
|
* Funkcija handlecli prima referencu tipa client - važno za definiranje funkcija koje se šalju; |
|
|
|
|
|
|
|
* Nije moguće proslijediti druge parametre; |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void server::asyncPool(const uint limit, void (*handlecli)(client&), const uint timeout) { |
|
|
|
|
|
|
|
clientPool clipool(this, limit, timeout, securefds); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (uint i=0; i<limit; i++) { |
|
|
|
|
|
|
|
thr.push_back(thread( [&]() { |
|
|
|
|
|
|
|
pair<mutex*, client*>* cli = clipool.pickup(); |
|
|
|
|
|
|
|
while (true) { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
handlecli(*(cli->second));
|
|
|
|
|
|
|
|
} catch (const string err) { |
|
|
|
|
|
|
|
cout << err << endl; |
|
|
|
|
|
|
|
cli->second->~client(); |
|
|
|
|
|
|
|
cli->second = new client(this, timeout, securefds); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
clipool.release(cli); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
})); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (uint i=0; i<limit; i++) { |
|
|
|
|
|
|
|
thr[i].join(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
thr.clear(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Destruktor varijable tipa server |
|
|
|
* Destruktor varijable tipa server |
|
|
|
*/ |
|
|
|
*/ |
|
|
@ -42,10 +155,21 @@ server::~server () { |
|
|
|
throw string("[ERROR] The socket is already closed ");
|
|
|
|
throw string("[ERROR] The socket is already closed ");
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
else if (close(sock) != 0) { |
|
|
|
else { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if __linux__ |
|
|
|
|
|
|
|
if (close(sock) != 0) { |
|
|
|
|
|
|
|
throw string("[ERROR] Unable to close socket "); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#elif _WIN32 |
|
|
|
|
|
|
|
if (closesocket(sock) != 0) { |
|
|
|
throw string("[ERROR] Unable to close socket "); |
|
|
|
throw string("[ERROR] Unable to close socket "); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
WSACleanup(); |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -110,8 +234,14 @@ secure::~secure () { |
|
|
|
|
|
|
|
|
|
|
|
client::client(const string address, const ushort port, const uint timeout, SSL_CTX* securefds) { |
|
|
|
client::client(const string address, const ushort port, const uint timeout, SSL_CTX* securefds) { |
|
|
|
|
|
|
|
|
|
|
|
sock = socket(AF_INET, SOCK_STREAM, 0); |
|
|
|
#if _WIN32 |
|
|
|
if (sock < 0) { |
|
|
|
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0) { |
|
|
|
|
|
|
|
throw string("[ERROR] Unable to set WinSock " + to_string(WSAGetLastError())); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
conn = socket(AF_INET, SOCK_STREAM, 0); |
|
|
|
|
|
|
|
if (conn < 0) { |
|
|
|
throw string("[ERROR] Unable to open TCP socket "); |
|
|
|
throw string("[ERROR] Unable to open TCP socket "); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -121,24 +251,31 @@ client::client(const string address, const ushort port, const uint timeout, SSL_ |
|
|
|
addr.sin_addr.s_addr = inet_addr(_address.c_str()); |
|
|
|
addr.sin_addr.s_addr = inet_addr(_address.c_str()); |
|
|
|
addr.sin_port = htons(port); |
|
|
|
addr.sin_port = htons(port); |
|
|
|
|
|
|
|
|
|
|
|
if (connect(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) != 0) { |
|
|
|
if (connect(conn, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) != 0) { |
|
|
|
throw string("Unable to connect to server "); |
|
|
|
throw string("Unable to connect to server "); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if __linux__ |
|
|
|
struct timeval tv; |
|
|
|
struct timeval tv; |
|
|
|
tv.tv_sec = timeout/1000; |
|
|
|
tv.tv_sec = timeout/1000; |
|
|
|
tv.tv_usec = (timeout%1000)*1000; |
|
|
|
tv.tv_usec = (timeout%1000)*1000; |
|
|
|
|
|
|
|
|
|
|
|
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval))) { |
|
|
|
if (setsockopt(conn, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval))) { |
|
|
|
throw string("[ERROR] Unable to set timeout "); |
|
|
|
throw string("[ERROR] Unable to set timeout "); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#elif _WIN32 |
|
|
|
|
|
|
|
DWORD tv = timeout; |
|
|
|
|
|
|
|
if (setsockopt(conn, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv))) { |
|
|
|
|
|
|
|
throw string("[ERROR] Unable to set timeout "); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
if (securefds) { |
|
|
|
if (securefds) { |
|
|
|
ssl = SSL_new(securefds); |
|
|
|
ssl = SSL_new(securefds); |
|
|
|
if (!ssl) { |
|
|
|
if (!ssl) { |
|
|
|
throw string("[ERROR] Creating SSL object "); |
|
|
|
throw string("[ERROR] Creating SSL object "); |
|
|
|
} |
|
|
|
} |
|
|
|
SSL_set_fd(ssl, sock); |
|
|
|
SSL_set_fd(ssl, conn); |
|
|
|
|
|
|
|
|
|
|
|
// Perform the SSL handshake
|
|
|
|
// Perform the SSL handshake
|
|
|
|
if (SSL_connect(ssl) <= 0) { |
|
|
|
if (SSL_connect(ssl) <= 0) { |
|
|
@ -148,6 +285,66 @@ client::client(const string address, const ushort port, const uint timeout, SSL_ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Konstruktor varijable tipa commint |
|
|
|
|
|
|
|
* Prima pokazivač na inicijaliziranu varijablu tipa, port,
|
|
|
|
|
|
|
|
* i opcijonalno dozvoljeno vrijeme čekanja servera i deskriptor datoteke |
|
|
|
|
|
|
|
* SSL certifikat za sigurne komunikacije |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
client::client(const server *_srv, const uint timeout, SSL_CTX* securefds) { |
|
|
|
|
|
|
|
srv = _srv; |
|
|
|
|
|
|
|
socklen_t len = sizeof(struct sockaddr_in); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ((conn = accept(srv->sock, (struct sockaddr *)&(srv->addr), (socklen_t*)&len)) < 0) { |
|
|
|
|
|
|
|
throw string("[ERROR] Unable to accept client connection "); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if __linux__ |
|
|
|
|
|
|
|
struct timeval tv; |
|
|
|
|
|
|
|
tv.tv_sec = timeout/1000; |
|
|
|
|
|
|
|
tv.tv_usec = (timeout%1000)*1000; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (setsockopt(conn, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval))) { |
|
|
|
|
|
|
|
throw string("[ERROR] Unable to set timeout "); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#elif _WIN32 |
|
|
|
|
|
|
|
DWORD tv = timeout; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (setsockopt(conn, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv))) { |
|
|
|
|
|
|
|
throw string("[ERROR] Unable to set timeout "); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (securefds) { |
|
|
|
|
|
|
|
ssl = SSL_new(securefds); |
|
|
|
|
|
|
|
if (!ssl) { |
|
|
|
|
|
|
|
throw string("[ERROR] Creating SSL object "); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
SSL_set_fd(ssl, conn); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Perform SSL handshake
|
|
|
|
|
|
|
|
if (SSL_accept(ssl) <= 0) { |
|
|
|
|
|
|
|
SSL_free(ssl); |
|
|
|
|
|
|
|
throw string("[ERROR] Performing SSL handshake "); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char ipv4_buff[INET_ADDRSTRLEN]; |
|
|
|
|
|
|
|
char ipv6_buff[INET6_ADDRSTRLEN]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inet_ntop(AF_INET, &(srv->addr.sin_addr), ipv4_buff, INET_ADDRSTRLEN); |
|
|
|
|
|
|
|
ipv4 = ipv4_buff; |
|
|
|
|
|
|
|
inet_ntop(AF_INET6, &(srv->addr.sin_addr), ipv6_buff, INET6_ADDRSTRLEN); |
|
|
|
|
|
|
|
ipv6 = ipv6_buff; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -162,13 +359,22 @@ client::~client () { |
|
|
|
SSL_free(ssl); |
|
|
|
SSL_free(ssl); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (sock <= 0) { |
|
|
|
if (conn <= 0) { |
|
|
|
throw string("[ERROR] The socket is already closed ");
|
|
|
|
throw string("[ERROR] The socket is already closed ");
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
else if (close(sock) != 0) { |
|
|
|
else { |
|
|
|
|
|
|
|
#if __linux__ |
|
|
|
|
|
|
|
if (close(conn) != 0) { |
|
|
|
|
|
|
|
throw string("[ERROR] Unable to close socket "); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#elif _WIN32 |
|
|
|
|
|
|
|
if (closesocket(conn) != 0) { |
|
|
|
throw string("[ERROR] Unable to close socket "); |
|
|
|
throw string("[ERROR] Unable to close socket "); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//WSACleanup();
|
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -179,15 +385,28 @@ client::~client () { |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool client::tell (const string msg) { |
|
|
|
bool client::push(const string msg) { |
|
|
|
size_t sended = 0; |
|
|
|
size_t total_sent = 0; |
|
|
|
|
|
|
|
size_t msg_length = msg.length(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (total_sent < msg_length) { |
|
|
|
|
|
|
|
size_t sent = 0; |
|
|
|
|
|
|
|
|
|
|
|
if (ssl) { |
|
|
|
if (ssl) { |
|
|
|
sended = SSL_write(ssl, msg.c_str(), msg.length()); |
|
|
|
sent = SSL_write(ssl, msg.c_str() + total_sent, msg_length - total_sent); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
sent = send(conn, msg.c_str() + total_sent, msg_length - total_sent, 0); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
|
|
|
|
sended = write(sock, msg.c_str(), msg.length()); |
|
|
|
if (sent == -1) { |
|
|
|
|
|
|
|
// Greška pri slanju poruke
|
|
|
|
|
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
return sended == msg.length(); |
|
|
|
|
|
|
|
|
|
|
|
total_sent += sent; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -196,46 +415,67 @@ bool client::tell (const string msg) { |
|
|
|
* Vraća string primljene poruke |
|
|
|
* Vraća string primljene poruke |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
string client::obey (size_t byte_limit) { |
|
|
|
string client::pull(size_t byte_limit) { |
|
|
|
char res[byte_limit] = {0}; |
|
|
|
char res[byte_limit] = {0}; |
|
|
|
|
|
|
|
size_t total_received = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (total_received < byte_limit) { |
|
|
|
|
|
|
|
ssize_t received = 0; |
|
|
|
|
|
|
|
|
|
|
|
if (ssl) { |
|
|
|
if (ssl) { |
|
|
|
SSL_read(ssl, res, byte_limit); |
|
|
|
received = SSL_read(ssl, res + total_received, byte_limit - total_received); |
|
|
|
} |
|
|
|
} else { |
|
|
|
else { |
|
|
|
received = recv(conn, res + total_received, byte_limit - total_received, 0); |
|
|
|
read(sock , res, byte_limit); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return string(res); |
|
|
|
if (received == -1) { |
|
|
|
|
|
|
|
// Greška pri primanju poruke
|
|
|
|
|
|
|
|
cout << "Da vidim jel ovdje kad nije poslo " << endl; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} else if (received == 0) { |
|
|
|
|
|
|
|
// Veza je prekinuta - treba pozvati destruktor
|
|
|
|
|
|
|
|
// cout << "Destruktor " << endl;
|
|
|
|
|
|
|
|
// this->~client();
|
|
|
|
|
|
|
|
throw string("[WARNING] Socket closed remotely"); |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
total_received += received; |
|
|
|
* Konstruktor varijable tipa commint |
|
|
|
} |
|
|
|
* Prima pokazivač na inicijaliziranu varijablu tipa, port,
|
|
|
|
|
|
|
|
* i opcijonalno dozvoljeno vrijeme čekanja servera i deskriptor datoteke |
|
|
|
|
|
|
|
* SSL certifikat za sigurne komunikacije |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return string(res); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
comming::comming(const server *_srv, const uint timeout, SSL_CTX* securefds) { |
|
|
|
bool client::reconnect() { |
|
|
|
srv = _srv; |
|
|
|
if (_address.empty() && srv != NULL) { |
|
|
|
|
|
|
|
// srv = _srv;
|
|
|
|
socklen_t len = sizeof(struct sockaddr_in); |
|
|
|
socklen_t len = sizeof(struct sockaddr_in); |
|
|
|
|
|
|
|
|
|
|
|
if ((conn = accept(srv->sock, (struct sockaddr *)&(srv->addr), (socklen_t*)&len)) < 0) { |
|
|
|
if ((conn = accept(srv->sock, (struct sockaddr *)&(srv->addr), (socklen_t*)&len)) < 0) { |
|
|
|
throw string("[ERROR] Unable to accept client connection "); |
|
|
|
throw string("[ERROR] Unable to accept client connection "); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if __linux__ |
|
|
|
struct timeval tv; |
|
|
|
struct timeval tv; |
|
|
|
tv.tv_sec = timeout/1000; |
|
|
|
tv.tv_sec = _timeout/1000; |
|
|
|
tv.tv_usec = (timeout%1000)*1000; |
|
|
|
tv.tv_usec = (_timeout%1000)*1000; |
|
|
|
|
|
|
|
|
|
|
|
if (setsockopt(conn, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval))) { |
|
|
|
if (setsockopt(conn, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval))) { |
|
|
|
throw string("[ERROR] Unable to set timeout "); |
|
|
|
throw string("[ERROR] Unable to set timeout "); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#elif _WIN32 |
|
|
|
|
|
|
|
DWORD tv = timeout; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (setsockopt(conn, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv))) { |
|
|
|
|
|
|
|
throw string("[ERROR] Unable to set timeout "); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (securefds) { |
|
|
|
|
|
|
|
ssl = SSL_new(securefds); |
|
|
|
|
|
|
|
|
|
|
|
if (_securefds) { |
|
|
|
|
|
|
|
ssl = SSL_new(_securefds); |
|
|
|
if (!ssl) { |
|
|
|
if (!ssl) { |
|
|
|
throw string("[ERROR] Creating SSL object "); |
|
|
|
throw string("[ERROR] Creating SSL object "); |
|
|
|
} |
|
|
|
} |
|
|
@ -255,63 +495,114 @@ comming::comming(const server *_srv, const uint timeout, SSL_CTX* securefds) { |
|
|
|
ipv4 = ipv4_buff; |
|
|
|
ipv4 = ipv4_buff; |
|
|
|
inet_ntop(AF_INET6, &(srv->addr.sin_addr), ipv6_buff, INET6_ADDRSTRLEN); |
|
|
|
inet_ntop(AF_INET6, &(srv->addr.sin_addr), ipv6_buff, INET6_ADDRSTRLEN); |
|
|
|
ipv6 = ipv6_buff; |
|
|
|
ipv6 = ipv6_buff; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if _WIN32 |
|
|
|
|
|
|
|
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0) { |
|
|
|
|
|
|
|
throw string("[ERROR] Unable to set WinSock " + to_string(WSAGetLastError())); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
conn = socket(AF_INET, SOCK_STREAM, 0); |
|
|
|
|
|
|
|
if (conn < 0) { |
|
|
|
|
|
|
|
throw string("[ERROR] Unable to open TCP socket "); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
const string _address = isIPAddress(_address) ? _address : ipFromDomain(_address); |
|
|
|
* Destruktor varijable tipa comming |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
comming::~comming() { |
|
|
|
addr.sin_family = AF_INET; |
|
|
|
|
|
|
|
addr.sin_addr.s_addr = inet_addr(_address.c_str()); |
|
|
|
|
|
|
|
addr.sin_port = htons(_port); |
|
|
|
|
|
|
|
|
|
|
|
if (ssl) { |
|
|
|
if (connect(conn, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) != 0) { |
|
|
|
SSL_shutdown(ssl); |
|
|
|
throw string("Unable to connect to server "); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if __linux__ |
|
|
|
|
|
|
|
struct timeval tv; |
|
|
|
|
|
|
|
tv.tv_sec = _timeout/1000; |
|
|
|
|
|
|
|
tv.tv_usec = (_timeout%1000)*1000; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (setsockopt(conn, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval))) { |
|
|
|
|
|
|
|
throw string("[ERROR] Unable to set timeout "); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#elif _WIN32 |
|
|
|
|
|
|
|
DWORD tv = timeout; |
|
|
|
|
|
|
|
if (setsockopt(conn, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv))) { |
|
|
|
|
|
|
|
throw string("[ERROR] Unable to set timeout "); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (_securefds) { |
|
|
|
|
|
|
|
ssl = SSL_new(_securefds); |
|
|
|
|
|
|
|
if (!ssl) { |
|
|
|
|
|
|
|
throw string("[ERROR] Creating SSL object "); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
SSL_set_fd(ssl, conn); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Perform the SSL handshake
|
|
|
|
|
|
|
|
if (SSL_connect(ssl) <= 0) { |
|
|
|
SSL_free(ssl); |
|
|
|
SSL_free(ssl); |
|
|
|
|
|
|
|
throw string("[ERROR] Performing SSL handshake "); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (conn <= 0) { |
|
|
|
clientPool::clientPool(const uint _numcli, const string address, const ushort port, const uint timeout, SSL_CTX* securefds) { |
|
|
|
throw string("[ERROR] The socket is already closed ");
|
|
|
|
if (_numcli > 1 ) { |
|
|
|
|
|
|
|
numcli = _numcli; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
throw string("[ERROR] Invalid number of instances in pool "); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
else if (close(conn) != 0) { |
|
|
|
for (uint i=0; i<numcli; i++) { |
|
|
|
throw string("[ERROR] Unable to close socket "); |
|
|
|
drops.push_back(make_pair(new mutex, new client(address, port, timeout, securefds))); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Metoda klase comming za slanje podataka preko soketa |
|
|
|
|
|
|
|
* Prima string koji će biti poslan |
|
|
|
|
|
|
|
* Vraća logički statu poređenja psolanih karaktera i karaktera u stringu |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool comming::tell (const string msg) { |
|
|
|
clientPool::clientPool(const server *_srv, const uint _numcli, const uint timeout, SSL_CTX* securefds) { |
|
|
|
ssize_t sended = 0; |
|
|
|
if (_numcli > 1 ) { |
|
|
|
if (ssl) { |
|
|
|
numcli = _numcli; |
|
|
|
sended = SSL_write(ssl, msg.c_str(), msg.length()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
sended = write(conn, msg.c_str(), msg.length()); |
|
|
|
throw string("[ERROR] Invalid number of instances in pool "); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (uint i=0; i<numcli; i++) { |
|
|
|
|
|
|
|
cout << "init clients " << i << endl; |
|
|
|
|
|
|
|
drops.push_back(make_pair(new mutex, new client(_srv, timeout, securefds))); |
|
|
|
} |
|
|
|
} |
|
|
|
return sended == msg.length(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
pair<mutex*, client*>* clientPool::pickup() { |
|
|
|
* Metoda klase comming za primanje poruke preko soketa |
|
|
|
cout << "Uzimam clienta " << endl; |
|
|
|
* Prima dozvoljeni broj karaktera koji će primiti |
|
|
|
lock_guard<mutex> master(io); |
|
|
|
* Vraća string primljene poruke |
|
|
|
while (true) { |
|
|
|
*/ |
|
|
|
for (uint i=0; i<drops.size(); i++) { |
|
|
|
|
|
|
|
cout << "Pokušavam s " << i << endl; |
|
|
|
|
|
|
|
|
|
|
|
string comming::obey (size_t byte_limit) { |
|
|
|
if (drops[i].first->try_lock()) { |
|
|
|
char res[byte_limit] = {0}; |
|
|
|
cout << "Odabrao sam " << i << endl; |
|
|
|
|
|
|
|
|
|
|
|
if (ssl) { |
|
|
|
return &drops[i]; |
|
|
|
SSL_read(ssl, res, byte_limit); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
|
|
|
|
read(conn , res, byte_limit); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return string(res); |
|
|
|
void clientPool::release(pair<mutex*, client*>* drop) { |
|
|
|
|
|
|
|
drop->first->unlock(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
clientPool::~clientPool() { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
numcli = 0; |
|
|
|
|
|
|
|
drops.clear(); |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |