diff --git a/README.md b/README.md index 67759cd..a0ce63e 100644 --- a/README.md +++ b/README.md @@ -163,66 +163,72 @@ You can both set and get GET/POST data through the fr::(HttpRequest/HttpResponse ```c++ #include -//Bind to port -fr::TcpListener listener; -if(listener.listen("8081") != fr::Socket::Success) -{ - std::cout << "Failed to listen to port" << std::endl; - return; -} - -//Create a selector and a container for holding connected clients -fr::SocketSelector selector; -std::vector> clients; - -//Add our connection listener to the selector -selector.add(listener); - -//Infinitely loop, waiting for connections or data -while(selector.wait())) -{ - //If the listener is ready, that means we've got a new connection - if(selector.is_ready(listener)) + //Bind to port + fr::TcpListener listener; + if(listener.listen("8080") != fr::Socket::Success) { - //Accept the new connection - std::unique_ptr new_client = std::unique_ptr(new fr::TcpSocket()); - if(listener.accept(*new_client) == fr::Socket::Success) - { - //Add them to the selector, and our socket list - selector.add(*new_client); - clients.emplace_back(std::move(new_client)); - } + //Error } - else + + //Create socket selector and add listener + fr::SocketSelector selector; + selector.add(listener); + + //Create vector to store open connections + std::vector> connections; + + //Infinitely loop. No timeout is specified so it will not return false. + while(selector.wait()) { - //Iterate over our clients to find which one has sent data - for(auto iter = clients.begin(); iter != clients.end();) + //Check if it was the selector who sent data + if(selector.is_ready(listener)) { - fr::TcpSocket &socket = **iter; - if(selector.is_ready(socket)) + std::unique_ptr> socket(new fr::HttpSocket); + if(listener.accept(*socket) == fr::Socket::Success) { - fr::Packet packet; - if(socket.receive(packet) == fr::Socket::Success) + selector.add(*socket); + connections.emplace_back(std::move(socket)); + } + } + + //Else it must have been one of the clients + else + { + //Find which client send the data + for(auto iter = connections.begin(); iter != connections.end();) + { + //Eww + fr::HttpSocket &client = (fr::HttpSocket&)**iter; + + //Check if it's this client + if(selector.is_ready(client)) { - //Do something with packet - //... - - iter++; + //It is, so receive their HTTP request + fr::HttpRequest request; + if(client.receive(request) == fr::Socket::Success) + { + //Send back a HTTP response containing 'Hello, World!' + fr::HttpResponse response; + response.set_body("

Hello, World!

"); + client.send(response); + + //Remove them from the selector and close the connection + selector.remove(client); + client.close(); + iter = connections.erase(iter); + } + else + { + iter++; + } } else { - //Client has disconnected. Remove them. - selector.remove(socket); - iter = clients.erase(iter); + iter++; } } - else - { - iter++; - } } } -} ``` fr::SocketSelector can be used to monitor lots of blocking sockets at once (both fr::TcpSocket's and fr::HttpSocket's), without polling, to see when data is being received or a connection has closed. To add a socket, just call fr::SocketSelector::add, and to remove a socket, which must be done before the socket object is destroyed, call fr::SocketSelector::remove. You can add as many fr::Socket's as you want.It is also important to add your fr::TcpListener to the selector, otherwise you wont be able to accept new connections whilst blocking. diff --git a/include/TcpListener.h b/include/TcpListener.h index 4711d3f..5378661 100644 --- a/include/TcpListener.h +++ b/include/TcpListener.h @@ -42,6 +42,10 @@ private: //Stubs virtual void close(){} virtual Socket::Status connect(const std::string &address, const std::string &port){return Socket::Error;} + virtual void set_blocking(bool val){} + virtual fr::Socket::Status send_raw(const char*, size_t){return Socket::Error;} + virtual fr::Socket::Status receive_raw(void*, size_t, size_t&){return Socket::Error;} + virtual int32_t get_socket_descriptor() const {return socket_descriptor;} }; } diff --git a/main.cpp b/main.cpp index 019fc0c..5ef16c6 100644 --- a/main.cpp +++ b/main.cpp @@ -11,55 +11,6 @@ int main() { - fr::SSLListener listener; - if(listener.listen("9091") != fr::Socket::Success) - { - std::cout << "Failed to bind to port" << std::endl; - return 1; - } - - while(true) - { - fr::HttpSocket http_socket; - if(listener.accept(http_socket) != fr::Socket::Success) - { - std::cout << "Failed to accept client" << std::endl; - continue; - } - - fr::HttpRequest request; - if(http_socket.receive(request) != fr::Socket::Success) - { - std::cout << "Failed to receive data" << std::endl; - continue; - } - else - { - std::cout << "Read successfully" << std::endl; - } - - std::cout << "Got: " << request.get_body() << std::endl; - - fr::HttpResponse response; - response.set_body("

Hello, SSL World!

"); - http_socket.send(response); - http_socket.close(); - } - - -// fr::SSLSocket socket; -// if(socket.connect("lloydsenpai.xyz", "443") != fr::Socket::Success) -// return 1; -// -// std::string request = "GET / HTTP/1.1\r\nhost: www.lloydsenpai.xyz\r\n\r\n"; -// socket.send_raw(request.c_str(), request.size()); -// -// char *data = new char[1024]; -// size_t received; -// if(socket.receive_raw(data, 1024, received) != fr::Socket::Success) -// return 2; -// -// std::cout << "Got: " << std::string(data, received) << std::endl; return 0; } \ No newline at end of file diff --git a/src/SocketSelector.cpp b/src/SocketSelector.cpp index 2925b94..afd8d1f 100644 --- a/src/SocketSelector.cpp +++ b/src/SocketSelector.cpp @@ -37,7 +37,7 @@ namespace fr if(select_result == 0) //If it's timed out return false; else if(select_result == SOCKET_ERROR) //Else if error - throw std::logic_error("select() returned -1"); + throw std::logic_error("select() returned -1. Errno: " + std::to_string(errno)); return true; } diff --git a/src/TcpSocket.cpp b/src/TcpSocket.cpp index 09063bb..ce8ab37 100644 --- a/src/TcpSocket.cpp +++ b/src/TcpSocket.cpp @@ -143,7 +143,6 @@ namespace fr freeaddrinfo(info); is_connected = true; - return Socket::Status::Success; }