diff --git a/README.md b/README.md new file mode 100644 index 0000000..4b1f9d5 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ + +# A simple TCP socket library for C++ + + +Object-oriented implemented library for easy creation and management of TCP sockets. + +## Features + +- Client aplication +- Server aplication +- Timeout connection +- SSL certificate + diff --git a/lib/tcp_socket.hpp b/lib/tcp_socket.hpp index f2d25af..c732f4b 100644 --- a/lib/tcp_socket.hpp +++ b/lib/tcp_socket.hpp @@ -14,6 +14,11 @@ using namespace std; +/** + * Server klasa za TCP/IP soket + * Instanca se incijalizira kada pokrećemo server +*/ + class server { public: int sock; @@ -24,6 +29,11 @@ class server { }; +/** + * Klasa za konstrukciju i destrukciju SSL certifikata + * Pokreće se za server i client - (različiti konstruktori) +*/ + class secure { public: SSL_CTX* fds; @@ -34,6 +44,11 @@ class secure { }; + +/** + * Klasa za definiranje TCP soketa kod klijentskih aplikacija +*/ + class client { public: int sock; @@ -47,6 +62,11 @@ class client { }; +/** + * Klasa za inicijalizaciju dolaznih veza + * Definira se na serverskom tipu aplikacija i predstavlja identifikator klijenta +*/ + class comming { public: const server *srv; diff --git a/src/tcp_socket.cpp b/src/tcp_socket.cpp index 7f6ae7e..653aba8 100644 --- a/src/tcp_socket.cpp +++ b/src/tcp_socket.cpp @@ -1,5 +1,9 @@ #include "../lib/tcp_socket.hpp" +/** + * Kontrustruktor varijable tipa server, prima port i limit za ograničenje liste klijenata na čekanju +*/ + server::server (const ushort port, const uint limit) { addr.sin_family = AF_INET; @@ -8,47 +12,59 @@ server::server (const ushort port, const uint limit) { sock = socket(AF_INET, SOCK_STREAM, 0); if (sock <= 0) { - printf("[ERROR] Ne mogu otvoriti defenirani TCP/IP socket!"); + throw "[ERROR] Unable to open TCP socket "; + } int opt=1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { - printf("[ERROR] Ne mogu otvoriti defenirani TCP/IP socket!"); + throw "[ERROR] Unable to set REUSEADDR or REUSEPORT on socket "; } if (bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { - printf("[ERROR] Ne mogu bindati defenirani TCP/IP socket!"); + throw "[ERROR] Unable to bind socket "; } if (listen(sock, limit) < 0) { - printf("[ERROR] Ne mogu defenirani listen za TCP/IP socket!"); + throw "[ERROR] It is not possible to set the allowed number of waiting clients "; } } +/** + * Destruktor varijable tipa server +*/ + server::~server () { if (sock<=0) { - printf ("[ERROR] Soket destruktor: već zatvoren soket!"); + throw "[ERROR] The socket is already closed "; } else if (close(sock) != 0) { - printf ("[ERROR] Soket destruktor nije mogao zatvoriti soket!"); + throw "[ERROR] Unable to close socket "; } } +/** + * Konstruktor varijable tipa secure za klijentske implementacije +*/ secure::secure() { fds = SSL_CTX_new(SSLv23_client_method()); if (!fds) { - //throw "[ERROR] Creating SSL context "; - cout << endl << "[ERROR] Creating SSL context "; + throw "[ERROR] Creating SSL context "; } } + +/** + * Konstruktor varijable tipa secure za serverske implementacije +*/ + secure::secure(const string cert, const string priv) { SSL_library_init(); @@ -58,33 +74,40 @@ secure::secure(const string cert, const string priv) { // Create an SSL context fds = SSL_CTX_new(SSLv23_server_method()); if (!fds) { - // throw "[ERROR] Creating SSL context "; - cout << endl << "[ERROR] Creating SSL context "; + throw "[ERROR] Creating SSL context "; } // Load the server's certificate and private key files if (SSL_CTX_use_certificate_file(fds, cert.c_str(), SSL_FILETYPE_PEM) <= 0) { - // throw "[ERROR] Loading certificate file."; - cout << endl << "[ERROR] Loading certificate file."; + throw "[ERROR] Loading certificate file "; } if (SSL_CTX_use_PrivateKey_file(fds, priv.c_str(), SSL_FILETYPE_PEM) <= 0) { - //throw "[ERROR] Loading private key file."; - cout << endl << "[ERROR] Loading private key file."; + throw "[ERROR] Loading private key file "; } } +/** + * Destruktor varijable tipa secure +*/ + + secure::~secure () { SSL_CTX_free(fds); } +/** + * Konstruktor varijable tipa client + * Prima adresu, port, i opcijonalno dozvoljeno vrijeme čekanja servera + * i deskriptor datoteke SSL certifikat za sigurne komunikacije +*/ client::client(const string address, const ushort port, const uint timeout, SSL_CTX* securefds) { sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { - printf("[ERROR] Ne mogu otvoriti TCP/IP socket!"); + throw "[ERROR] Unable to open TCP socket "; } const string _address = isIPAddress(address) ? address : ipFromDomain(address); @@ -94,23 +117,21 @@ client::client(const string address, const ushort port, const uint timeout, SSL_ addr.sin_port = htons(port); if (connect(sock, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) != 0) { - printf("[EROR] Ne mogu se povezati s poslužiteljem!"); + throw "Unable to connect to server "; } struct timeval tv; - tv.tv_sec = 0; // za sad 2 sekunde timeout, harkodirano + tv.tv_sec = 0; tv.tv_usec = timeout*1000; if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval))) { - printf ("[ERROR] 503 Ne mogu postaviti timeout!"); - sock = -1; + throw "[ERROR] Unable to set timeout "; } if (securefds) { ssl = SSL_new(securefds); if (!ssl) { - //throw "[ERROR] Creating SSL object."; - cout << endl << "[ERROR] Creating SSL object."; + throw "[ERROR] Creating SSL object "; } SSL_set_fd(ssl, sock); @@ -118,13 +139,16 @@ client::client(const string address, const ushort port, const uint timeout, SSL_ // Perform the SSL handshake if (SSL_connect(ssl) <= 0) { SSL_free(ssl); - // throw "[ERROR] Performing SSL handshake."; - cout << endl << "[ERROR] Performing SSL handshake."; + throw "[ERROR] Performing SSL handshake "; } } +/** + * Destruktor varijable tipa client +*/ + client::~client () { if (ssl) { @@ -133,15 +157,21 @@ client::~client () { } if (sock <= 0) { - printf ("[ERROR] Soket destruktor: već zatvoren soket!"); + throw "[ERROR] The socket is already closed "; } else if (close(sock) != 0) { - printf ("[ERROR] Soket destruktor nije mogao zatvoriti soket!"); + throw "[ERROR] Unable to close socket "; } } +/** + * Metoda klase client 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 client::tell (const string msg) { size_t sended = 0; @@ -154,6 +184,12 @@ bool client::tell (const string msg) { return sended == msg.length(); } +/** + * Metoda klase client za primanje poruke preko soketa + * Prima dozvoljeni broj karaktera koji će primiti + * Vraća string primljene poruke +*/ + string client::obey (size_t byte_limit) { char res[byte_limit] = {0}; @@ -167,6 +203,12 @@ string client::obey (size_t byte_limit) { return (string) res; } +/** + * 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 +*/ comming::comming(const server *_srv, const uint timeout, SSL_CTX* securefds) { @@ -174,7 +216,7 @@ comming::comming(const server *_srv, const uint timeout, SSL_CTX* securefds) { socklen_t len = sizeof(struct sockaddr_in); if ((conn = accept(srv->sock, (struct sockaddr *)&(srv->addr), (socklen_t*)&len)) < 0) { - printf("[ERROR] Ne mogu preuzeti vezu klijenta!"); + throw "[ERROR] Unable to accept client connection "; } struct timeval tv; @@ -182,23 +224,20 @@ comming::comming(const server *_srv, const uint timeout, SSL_CTX* securefds) { tv.tv_usec = 0; if (setsockopt(conn, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval))) { - printf("[ERROR] 503 Ne mogu postaviti timeout!"); - conn = -1; + throw "[ERROR] Unable to set timeout "; } if (securefds) { ssl = SSL_new(securefds); if (!ssl) { - // throw "[ERROR] Creating SSL object."; - cout << endl << "[ERROR] Creating SSL object."; + throw "[ERROR] Creating SSL object "; } SSL_set_fd(ssl, conn); // Perform SSL handshake if (SSL_accept(ssl) <= 0) { SSL_free(ssl); - // throw "[ERROR] Performing SSL handshake."; - cout << endl << "[ERROR] Performing SSL handshake."; + throw "[ERROR] Performing SSL handshake "; } } @@ -213,6 +252,10 @@ comming::comming(const server *_srv, const uint timeout, SSL_CTX* securefds) { } +/** + * Destruktor varijable tipa comming +*/ + comming::~comming() { if (ssl) { @@ -221,14 +264,20 @@ comming::~comming() { } if (conn <= 0) { - printf ("[ERROR] Comming destruktor: već zatvoren soket!"); + throw "[ERROR] The socket is already closed "; } else if (close(conn) != 0) { - printf ("[ERROR] Comming destruktor nije mogao zatvoriti soket!"); + throw "[ERROR] Unable to close socket "; } } +/** + * 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) { ssize_t sended = 0; if (ssl) { @@ -240,6 +289,13 @@ bool comming::tell (const string msg) { return sended == msg.length(); } + +/** + * Metoda klase comming za primanje poruke preko soketa + * Prima dozvoljeni broj karaktera koji će primiti + * Vraća string primljene poruke +*/ + string comming::obey (size_t byte_limit) { char res[byte_limit] = {0}; diff --git a/test/client.cpp b/test/client.cpp index ca4a890..6584194 100644 --- a/test/client.cpp +++ b/test/client.cpp @@ -6,12 +6,18 @@ using namespace std; int main() { + try { + secure crypto; client myserver("localhost", 5000, 500, crypto.fds); string sends = "Hello world!"; cout << myserver.tell(sends) << " " << sends.length() << endl; cout << myserver.obey(); + } + catch (const string err) { + cout << err << endl; + } return 0; } \ No newline at end of file diff --git a/test/client.o b/test/client.o index 012ee4c..526ad20 100755 Binary files a/test/client.o and b/test/client.o differ diff --git a/test/server.cpp b/test/server.cpp index be48d89..32582e2 100644 --- a/test/server.cpp +++ b/test/server.cpp @@ -5,7 +5,7 @@ using namespace std; int main() { - +try{ cout << "init server " << endl; server myserver(5000, 10); cout << "init cert " << endl; @@ -31,7 +31,9 @@ int main() { // } // sleep(80); - - +} +catch(const string err) { + cout << err << endl; +} return 0; } \ No newline at end of file