diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0636427..d6e4384 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,8 +1,10 @@ -add_executable(web_server - ./web_server.cpp -) - add_executable(proxy ./proxy.cpp + ./network.cpp +) + +add_executable(web_server + ./web_server.cpp + ./network.cpp ) diff --git a/src/network.cpp b/src/network.cpp new file mode 100644 index 0000000..cc8ab8f --- /dev/null +++ b/src/network.cpp @@ -0,0 +1,149 @@ +#include "network.hpp" +#include +#include +#include // Needed for exit() +#include +#include + +void TestSockets(int sender_s, int receiver_s) { + char in_buf[BUF_SIZE]; // Input buffer for GET resquest + char out_buf[BUF_SIZE]; // Output buffer for HTML response + ssize_t buf_len; // Buffer length for file reads + // + // Pass GET along from browser to server + std::cout << "Attempting to send data to receiver" << std::endl; + do { + buf_len = recv(sender_s, in_buf, BUF_SIZE, 0); + std::cout << "LOG (info) - pipe packet recv size: " << buf_len << std::endl; + if (buf_len == -1) { + std::cout << "ERROR (info) - recv" << std::endl; + return; + } + if (buf_len == 0) { break; } + buf_len = send(receiver_s, in_buf, buf_len, 0); + std::cout << "LOG (info) - pipe packet send size: " << buf_len << std::endl; + } while (buf_len == BUF_SIZE); + std::cout << "Sent data to receiver" << std::endl; + + // Pass response along from server to browser + std::cout << "Attempting to send to browser" << std::endl; + do { + buf_len = recv(sender_s, out_buf, BUF_SIZE, 0); + std::cout << "LOG (info) - proxy packet recv size: " << buf_len << std::endl; + if (buf_len == -1) { + std::cout << "ERROR (info) - recv" << std::endl; + return; + } + if (buf_len == 0) { break; } + buf_len = send(receiver_s, out_buf, buf_len, 0); + std::cout << "LOG (info) - proxy packet send size: " << buf_len << std::endl; + } while (buf_len == BUF_SIZE); + std::cout << "Sent to browser" << std::endl; + close(sender_s); + close(receiver_s); +} + +void PipeSockets(int sender_s, int receiver_s) { + char in_buf[BUF_SIZE]; // Input buffer for GET resquest + ssize_t buf_len; // Buffer length for file reads + + // Pass GET along from browser to server + std::cout << "Attempting to send data to receiver" << std::endl; + do { + // Receive + buf_len = recv(sender_s, in_buf, BUF_SIZE, 0); + std::cout << "LOG (info) - pipe packet recv size: " << buf_len << '\n'; + if (buf_len == -1) { + std::cout << "ERROR (info) - recv" << std::endl; + close(sender_s); + close(receiver_s); + return; + } + if (buf_len == 0) { continue; } + + // Send + buf_len = send(receiver_s, in_buf, buf_len, 0); + std::cout << "LOG (info) - pipe packet send size: " << buf_len << '\n'; + } while (buf_len == BUF_SIZE); + std::cout << "Sent data to receiver" << std::endl; + +} + +void ProxySockets(int sender_s, int receiver_s) { + char out_buf[BUF_SIZE]; // Output buffer for HTML response + ssize_t buf_len; // Buffer length for file reads + + // Pass response along from server to browser + std::cout << "Attempting to send to browser" << std::endl; + do { + // Receive + buf_len = recv(sender_s, out_buf, BUF_SIZE, 0); + std::cout << "LOG (info) - proxy packet recv size: " << buf_len << '\n'; + if (buf_len == -1) { + std::cout << "ERROR (info) - recv -1" << std::endl; + return; + } + + // Send + buf_len = send(receiver_s, out_buf, buf_len, 0); + if (buf_len == 96) { break; } + std::cout << "LOG (info) - proxy packet send size: " << buf_len << '\n'; + } while ((buf_len == BUF_SIZE) || (buf_len == 40)); + std::cout << "Sent to browser" << std::endl; + close(sender_s); + close(receiver_s); +} + +Client::Client(void) { + addressLength = sizeof(address); + address.sin_family = AF_INET; +} + +bool Client::ConnectFrom(int serverFD) { + socketFD = accept(serverFD, (struct sockaddr *)&address, &addressLength); + if (socketFD == -1) { return 1; } + return 0; +} + +bool Client::ConnectTo(int portNumber) { + std::cout << "Attempting to connect to " << kWebserverIP << " on " << portNumber << std::endl; + address.sin_port = htons(portNumber); + if (inet_pton(address.sin_family, kWebserverIP, &address.sin_addr) <= 0) { + std::cerr << "ERROR (info) - inet_pton" << std::endl; + return 1; + } + socketFD = socket(address.sin_family, SOCK_STREAM, 0); + if (connect(socketFD, (struct sockaddr *)&address, addressLength) == -1) { + std::cerr << "ERROR (info) - connect" << std::endl; + return 1; + } + std::cout << "Connection successful" << std::endl; + return 0; +} + +Server::Server(int portNumber) { + std::cout << "Opening the server" << std::endl; + socketFD = socket(AF_INET, SOCK_STREAM, 0); + if (socketFD == -1) + { + std::cerr << "ERROR - Unable to create socket on server" << std::endl; + exit(1); + } + address.sin_family = AF_INET; + address.sin_port = htons(portNumber); + address.sin_addr.s_addr = htonl(INADDR_ANY); + // Create a socket, fill-in address information, and then bind it + if (bind(socketFD, (struct sockaddr *)&address, sizeof(address)) == -1) + { + std::cerr << "ERROR - Unable to bind socket" << std::endl; + exit(1); + } + // Listen for connections and then accept + listen(socketFD, 100); + std::cout << "Server is now open" << std::endl; +} + +void Server::Close(void) { + std::cout << "Closing the server" << std::endl; + close(socketFD); +} diff --git a/src/network.hpp b/src/network.hpp new file mode 100644 index 0000000..bcab3d9 --- /dev/null +++ b/src/network.hpp @@ -0,0 +1,33 @@ +#ifndef NETWORK_HPP +#define NETWORK_HPP + +#include +#include + +#define BUF_SIZE 4096 // Buffer size (big enough for a GET) + +#define kProxyPort 9080 +#define kWebserverIP "127.0.0.1" +#define kWebserverPort 7080 + +void TestSockets(int sender_s, int receiver_s); +void PipeSockets(int sender_s, int receiver_s); +void ProxySockets(int sender_s, int receiver_s); + +struct Client { + unsigned int socketFD; // Client socket descriptor + sockaddr_in address; // Client IP address + socklen_t addressLength; // Internet address length + Client(void); + bool ConnectFrom(int serverFD); + bool ConnectTo(int portNumber); +}; + +struct Server { + unsigned int socketFD; // Server socket descriptor + sockaddr_in address; // Server Internet address + Server(int portNumber); + void Close(void); +}; + +#endif diff --git a/src/proxy.cpp b/src/proxy.cpp index 7422c2e..980c8f8 100644 --- a/src/proxy.cpp +++ b/src/proxy.cpp @@ -1,17 +1,9 @@ //----- Include files --------------------------------------------------------- -#include // Needed for printf() -#include // Needed for exit() -#include // Needed for strcpy() and strlen() -#include // Needed for file i/o constants -#include // Needed for file i/o constants +#include #include - -#include // -#include // -#include // -#include // -#include - +#include +#include +#include "network.hpp" //----- HTTP response messages ---------------------------------------------- #define OK_IMAGE "HTTP/1.0 200 OK\nContent-Type:image/gif\n\n" @@ -19,104 +11,38 @@ #define NOTOK_404 "HTTP/1.0 404 Not Found\nContent-Type:text/html\n\n" #define MESS_404 "

FILE NOT FOUND

" -//----- Defines ------------------------------------------------------------- -#define BUF_SIZE 4096 // Buffer size (big enough for a GET) -#define PORT_NUM 9080 // Port number for a Web server - -//----- Function prototypes ------------------------------------------------- -void BrowserToProxy(int server_s, int client_s); -void ProxyToServer(int server_s, int client_s); - -//===== modeule main ======================================================== int main(void) { - unsigned int proxy_s; // Server socket descriptor - struct sockaddr_in proxy_addr; // Server Internet address - unsigned int browser_s; // Client socket descriptor - struct sockaddr_in browser_addr; // Client Internet address - struct in_addr browser_ip_addr; // Client IP address - unsigned int server_s; // Client socket descriptor - struct sockaddr_in server_addr; // Client Internet address - struct in_addr server_ip_addr; // Client IP address - socklen_t addr_len; // Internet address length - - // Create a socket, fill-in address information, and then bind it - proxy_s = socket(AF_INET, SOCK_STREAM, 0); - if (proxy_s == -1) - { - printf("ERROR - Unable to create socket on server\n"); - exit(1); - } - proxy_addr.sin_family = AF_INET; - proxy_addr.sin_port = htons(PORT_NUM); - proxy_addr.sin_addr.s_addr = htonl(INADDR_ANY); - int bindRet = bind(proxy_s, (struct sockaddr *)&proxy_addr, sizeof(proxy_addr)); - if (bindRet == -1) - { - printf("ERROR - Unable to bind socket\n"); - exit(1); - } - // Listen for connections and then accept - listen(proxy_s, 100); + std::vector> pending_futures; + Server proxy(kProxyPort); + Client browser; + Client webserver; // Main loop to listen, accept, and then spin-off a thread to handle the GET while (1) { - addr_len = sizeof(browser_addr); - - browser_s = accept(proxy_s, (struct sockaddr *)&browser_addr, &addr_len); - if (browser_s == -1) - { - perror("ERROR - Unable to create socket to client\n"); + if (browser.ConnectFrom(proxy.socketFD) != 0) + { + std::cerr << "ERROR - Unable to create socket to client" << std::endl; continue; - } - unsigned int server_s = socket(AF_INET, SOCK_STREAM, 0); - connect(server_s, (struct sockaddr *)&server_addr, addr_len); - - std::async(std::launch::async, BrowserToProxy, browser_s, server_s); - std::async(std::launch::async, ProxyToServer, server_s, browser_s); - + } + if (webserver.ConnectTo(kWebserverPort) != 0) + { + std::cerr << "ERROR - Unable to connect to webserver" << std::endl; + continue; + } + auto newThreadRequest1 = std::async(std::launch::async, PipeSockets, browser.socketFD, webserver.socketFD); + auto newThreadRequest2 = std::async(std::launch::async, ProxySockets, webserver.socketFD, browser.socketFD); + pending_futures.push_back(std::move(newThreadRequest1)); + pending_futures.push_back(std::move(newThreadRequest2)); + /* + auto newThreadRequest = std::async(std::launch::async, TestSockets, browser.socketFD, webserver.socketFD); + pending_futures.push_back(std::move(newThreadRequest)); + std::cout << "Returned from creating threads, continuing..." << std::endl; + */ + //TestSockets(browser.socketFD, webserver.socketFD); } - close(browser_s); - return (1); + proxy.Close(); + return 0; } -void BrowserToProxy(int server_s, int client_s) { - char in_buf[BUF_SIZE]; // Input buffer for GET resquest - char out_buf[BUF_SIZE]; // Output buffer for HTML response - char *file_name; // File name - unsigned int fh; // File handle - ssize_t buf_len; // Buffer length for file reads - unsigned int retcode; // Return code - - // Receive the GET request from the Web browser - do { - buf_len = recv(server_s, in_buf, BUF_SIZE, 0); - send(client_s, in_buf, buf_len, 0); - } while (buf_len != 0); -} - -void ProxyToServer(int server_s, int client_s) { - /* - - loop { - recv from browser - send to server - } - - */ - char in_buf[BUF_SIZE]; // Input buffer for GET resquest - char out_buf[BUF_SIZE]; // Output buffer for HTML response - char *file_name; // File name - unsigned int fh; // File handle - ssize_t buf_len; // Buffer length for file reads - unsigned int retcode; // Return code - - // Receive the GET request from the Web browser - do { - buf_len = recv(server_s, in_buf, BUF_SIZE, 0); - send(client_s, in_buf, buf_len, 0); - } while (buf_len != 0); - close(server_s); - close(client_s); -} diff --git a/src/web_server.cpp b/src/web_server.cpp index c09fe76..595a8d5 100644 --- a/src/web_server.cpp +++ b/src/web_server.cpp @@ -31,12 +31,14 @@ #define UNIX // WIN for Windows environment, UNIX for BSD or LINUX env. //----- Include files --------------------------------------------------------- -#include // Needed for printf() -#include // Needed for exit() #include // Needed for strcpy() and strlen() #include // Needed for file i/o constants #include // Needed for file i/o constants +#include #include +#include +#include +#include "network.hpp" /* FOR BSD UNIX/LINUX ---------------------------------------------------- */ #ifdef UNIX @@ -84,19 +86,9 @@ int main(void) #endif /* --------------------------------------------------------------------- */ - unsigned int server_s; // Server socket descriptor - struct sockaddr_in server_addr; // Server Internet address - unsigned int client_s; // Client socket descriptor - struct sockaddr_in client_addr; // Client Internet address - struct in_addr client_ip_addr; // Client IP address - socklen_t addr_len; // Internet address length - - /* FOR UNIX/LINUX ------------------------------------------------------ */ -#ifdef UNIX - int nChild_proc_id; // New child process ID. -#endif - /* --------------------------------------------------------------------- */ - + std::vector> pending_futures; + Server webserver(kWebserverPort); + Client proxy; /* FOR WIN ------------------------------------------------------------- */ #ifdef WIN // Initialize winsock @@ -104,41 +96,19 @@ int main(void) #endif /* --------------------------------------------------------------------- */ - // Create a socket, fill-in address information, and then bind it - server_s = socket(AF_INET, SOCK_STREAM, 0); - if (server_s == -1) - { - printf("ERROR - Unable to create socket on server\n"); - exit(1); - } - server_addr.sin_family = AF_INET; - server_addr.sin_port = htons(PORT_NUM); - server_addr.sin_addr.s_addr = htonl(INADDR_ANY); - int bindRet = bind(server_s, (struct sockaddr *)&server_addr, sizeof(server_addr)); - if (bindRet == -1) - { - printf("ERROR - Unable to bind socket\n"); - exit(1); - } - // Listen for connections and then accept - listen(server_s, 100); - // Main loop to listen, accept, and then spin-off a thread to handle the GET while (1) { - addr_len = sizeof(client_addr); - - client_s = accept(server_s, (struct sockaddr *)&client_addr, &addr_len); - if (client_s == -1) - { - perror("ERROR - Unable to create socket to client\n"); + if (proxy.ConnectFrom(webserver.socketFD) != 0) + { + std::cerr << "ERROR - Unable to create socket to client" << std::endl; continue; - } - - std::async(std::launch::async, ClientRequest, client_s); + } + auto newThreadRequest = std::async(std::launch::async, ClientRequest, proxy.socketFD); + pending_futures.push_back(std::move(newThreadRequest)); } - close(server_s); - return (1); + webserver.Close(); + return 0; } void ClientRequest(int client_s) { @@ -152,46 +122,51 @@ void ClientRequest(int client_s) { // Receive the GET request from the Web browser retcode = recv(client_s, in_buf, BUF_SIZE, 0); + if (retcode == -1) { std::cerr << "ERROR (info) - recv" << std::endl; } // Handle the GET if there is one (see note #3 in the header) - if (retcode != -1) - { - // Parse out the filename from the GET request - strtok(in_buf, " "); - file_name = strtok(NULL, " "); + // Parse out the filename from the GET request + strtok(in_buf, " "); + file_name = strtok(NULL, " "); - // Open the requested file - // - Start at 2nd char to get rid of leading "\" + // Open the requested file + // - Start at 2nd char to get rid of leading "\" #ifdef WIN - fh = open(&file_name[1], O_RDONLY | O_BINARY, S_IREAD | S_IWRITE); + fh = open(&file_name[1], O_RDONLY | O_BINARY, S_IREAD | S_IWRITE); #endif #ifdef UNIX - fh = open(&file_name[1], O_RDONLY, S_IREAD | S_IWRITE); + fh = open(&file_name[1], O_RDONLY, S_IREAD | S_IWRITE); #endif - // Generate and send the response (404 if could not open the file) - if (fh == -1) - { - printf("File %s not found - sending an HTTP 404 \n", &file_name[1]); - strcpy(out_buf, NOTOK_404); - send(client_s, out_buf, strlen(out_buf), 0); - strcpy(out_buf, MESS_404); - send(client_s, out_buf, strlen(out_buf), 0); - } - else - { - printf("File %s is being sent \n", &file_name[1]); - if (strstr(file_name, ".gif") != NULL) - strcpy(out_buf, OK_IMAGE); - else - strcpy(out_buf, OK_TEXT); - send(client_s, out_buf, strlen(out_buf), 0); - do { - buf_len = read(fh, out_buf, BUF_SIZE); - send(client_s, out_buf, buf_len, 0); - } while (buf_len != 0); - close(fh); - } - } + // Generate and send the response (404 if could not open the file) + if (fh == -1) + { + printf("File %s not found - sending an HTTP 404 \n", &file_name[1]); + strcpy(out_buf, NOTOK_404); + send(client_s, out_buf, strlen(out_buf), 0); + strcpy(out_buf, MESS_404); + send(client_s, out_buf, strlen(out_buf), 0); + } else { + printf("File %s is being sent \n", &file_name[1]); + if (strstr(file_name, ".gif") != NULL) + strcpy(out_buf, OK_IMAGE); + else + strcpy(out_buf, OK_TEXT); + send(client_s, out_buf, strlen(out_buf), 0); + do { + buf_len = read(fh, out_buf, BUF_SIZE); + buf_len = send(client_s, out_buf, buf_len, 0); + if (buf_len == -1) { + std::cerr << "ERROR (info) - send -1\n"; + std::cerr << "File causing error: " << &file_name[1] << '\n'; + std::cerr << "Errno: " << errno << '\n'; + std::cout << std::endl; + return; + } + std::cout << "LOG (info) - webserver send size: " << buf_len << '\n'; + } while (buf_len == BUF_SIZE); + std::cout << std::endl; + close(fh); + } // Close the client socket and end the thread close(client_s); }