|
1 | | -#include <cstring> |
2 | | -#include <string.h> |
3 | 1 | #include <sys/types.h> |
4 | 2 | #include <sys/socket.h> |
| 3 | +#include <errno.h> |
5 | 4 | #include <netdb.h> |
6 | 5 | #include <unistd.h> |
7 | | -#include <stdio.h> |
8 | | -#include <pthread.h> |
| 6 | +#include <thread> |
| 7 | +#include <chrono> |
| 8 | +#include <cstring> |
| 9 | +#include <netinet/in.h> |
| 10 | +#include <arpa/inet.h> |
9 | 11 |
|
10 | 12 | #include "Router.h" |
| 13 | +#include "Manager.h" |
11 | 14 |
|
12 | 15 | /* |
13 | 16 | * router - watches the designated port and for launches a new worker for every connection |
14 | 17 | * (when all workers are busy, waits some time before returning an error - "how long" should be kept in the config) |
15 | 18 | * Handles *some* of the HTTP errors |
16 | 19 | */ |
17 | 20 |
|
18 | | -Router::Router(int qsize) { |
| 21 | +Router::Router(int qsize, std::string port) { |
19 | 22 | this->queue_size = qsize; |
20 | 23 | this->logger = Logger("Router"); |
| 24 | + this->port = port; |
| 25 | + // initialize the socket |
| 26 | + this->listening_socket_fd = this->init_socket(); |
21 | 27 | } |
22 | 28 |
|
23 | 29 | Router::~Router() { |
24 | | - // TODO Auto-generated destructor stub |
| 30 | + // close our socket |
| 31 | + close(this->listening_socket_fd); |
| 32 | + // free the address |
| 33 | + freeaddrinfo(addr); |
| 34 | +} |
| 35 | + |
| 36 | +void *get_in_addr(struct sockaddr *sa) { |
| 37 | + if (sa->sa_family == AF_INET) { |
| 38 | + return &(((struct sockaddr_in*)sa)->sin_addr); |
| 39 | + } |
| 40 | + |
| 41 | + return &(((struct sockaddr_in6*)sa)->sin6_addr); |
25 | 42 | } |
26 | 43 |
|
27 | | -void *newSocketFunction(void *socket_fd); |
28 | | -void Router::watch(std::string port) { |
29 | | - this->logger.debug("starting with port" + port); |
| 44 | +void Router::watch() { |
| 45 | + socklen_t addr_size; |
| 46 | + struct sockaddr_storage client; |
| 47 | + int handling_socket; |
| 48 | + |
| 49 | + this->logger.debug("watching port: " + this->port); |
| 50 | + |
| 51 | + // create a manager object to handle different threads |
| 52 | + Manager manager; |
| 53 | + |
| 54 | + // we work until we're told to stop working |
| 55 | + while (true) { |
| 56 | + // listen for new connections |
| 57 | + listen(this->listening_socket_fd, this->queue_size); |
| 58 | + |
| 59 | + addr_size = sizeof client; |
| 60 | + handling_socket = accept(this->listening_socket_fd, (struct sockaddr *) &client, &addr_size); |
| 61 | + if (handling_socket < 0) { |
| 62 | + char * err = std::strerror(errno); |
| 63 | + throw RouterException("Error when accepting connection: " + std::string(err ? err : "unknown error")); |
| 64 | + } |
| 65 | + |
| 66 | + struct sockaddr_in *sin = (struct sockaddr_in *)&client; |
| 67 | + char client_addr[INET6_ADDRSTRLEN]; |
| 68 | + inet_ntop(AF_INET, &sin->sin_addr, client_addr, sizeof client_addr); |
| 69 | + this->logger.info("Handling incoming connection from: " + std::string(client_addr)); |
| 70 | + // this will create a new worker to work with |
| 71 | + // TODO: add try/catch and handle too many workers exception |
| 72 | + manager.handle_request(handling_socket); |
| 73 | + } |
| 74 | +} |
30 | 75 |
|
31 | | - struct sockaddr_storage incoming_connection_info; |
32 | | - socklen_t addr_size; |
33 | | - struct addrinfo listening_socket_description, *results; |
34 | | - int listening_socket_fd, new_socket_fd; |
| 76 | +int Router::init_socket() { |
| 77 | + struct addrinfo listening_socket_description; |
35 | 78 |
|
36 | 79 | // first, load up address structs with getaddrinfo(): |
| 80 | + // TODO error handling (what if there's no memory available) |
37 | 81 | memset(&listening_socket_description, 0, sizeof listening_socket_description); |
38 | 82 |
|
39 | 83 | listening_socket_description.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever |
40 | 84 | listening_socket_description.ai_socktype = SOCK_STREAM; |
41 | 85 | listening_socket_description.ai_flags = AI_PASSIVE; // fill in my IP for me |
42 | | - getaddrinfo(NULL, port.c_str(), &listening_socket_description, &results); |
| 86 | + getaddrinfo(NULL, this->port.c_str(), &listening_socket_description, &this->addr); |
43 | 87 |
|
44 | | - // make a socket, bind it, and listen on it: |
45 | | - listening_socket_fd = socket(results->ai_family, results->ai_socktype, results->ai_protocol); |
46 | | - bind(listening_socket_fd, results->ai_addr, results->ai_addrlen); |
47 | | - |
48 | | - listen(listening_socket_fd, this->queue_size); |
49 | | - |
50 | | - addr_size = sizeof incoming_connection_info; |
51 | | - new_socket_fd = accept(listening_socket_fd, (struct sockaddr *) &incoming_connection_info, &addr_size); |
52 | | - this->logger.info("handling connection"); |
53 | | - |
54 | | - pthread_t t1; |
55 | | - this->logger.debug("creating new thread"); |
56 | | - pthread_create(&t1, NULL, newSocketFunction, (void *) &new_socket_fd); |
57 | | - pthread_join(t1, NULL); |
58 | | - |
59 | | - this->logger.debug("closing connection"); |
60 | | - freeaddrinfo(results); |
61 | | - close(listening_socket_fd); |
62 | | - close(new_socket_fd); |
63 | | - |
64 | | - this->logger.debug("done"); |
65 | | -} |
| 88 | + // TODO error handling (what if we cannot open the socket) |
| 89 | + int listening_socket = socket(this->addr->ai_family, this->addr->ai_socktype, this->addr->ai_protocol); |
| 90 | + if (listening_socket < 0) { |
| 91 | + char * err = std::strerror(errno); |
| 92 | + throw RouterException("Error opening socket: " + std::string(err ? err : "unknown error")); |
| 93 | + } |
66 | 94 |
|
67 | | -// Possibly this code will be moved and divided to manager/worker |
68 | | -// that's why I'm leaving this out of the Router:: class |
69 | | -void *newSocketFunction(void *socket_fd_ptr){ |
70 | | - int *socket_fd = (int *)socket_fd_ptr; |
71 | | - char reply[100], *msg; |
72 | | - |
73 | | - std::string string = "Welcome to HACKttp: " + std::to_string(*socket_fd) + "\nYour message: "; |
74 | | - //msg = "Welcome to HACKttp " + (char) socket_fd; |
75 | | - msg = (char *) string.c_str(); |
76 | | - send(*socket_fd, msg, strlen(msg), 0); |
77 | | - |
78 | | - std::string response; |
79 | | - while(1){ |
80 | | - memset(&reply, 0, sizeof reply); |
81 | | - if(recv(*socket_fd, reply, 100, 0) <= 0) break; |
82 | | - response.append("HackTTP echo: "); |
83 | | - response.append(reply); |
84 | | - response.append("\nYour message: "); |
85 | | - msg = (char *)response.c_str(); |
86 | | - send(*socket_fd, msg, strlen(msg), 0); |
87 | | - //reply[99] = '\0'; |
88 | | - printf("Sent back: %s", response.c_str()); |
89 | | - response.clear(); |
| 95 | + // TODO error handling (what if we can't bind) |
| 96 | + int check = bind(listening_socket, this->addr->ai_addr, this->addr->ai_addrlen); |
| 97 | + if (check < 0) { |
| 98 | + char * err = std::strerror(errno); |
| 99 | + throw RouterException("Error binding socket: " + std::string(err ? err : "unknown error")); |
90 | 100 | } |
91 | 101 |
|
92 | | - return NULL; |
| 102 | + this->logger.debug("Got socket: " + std::to_string(listening_socket)); |
| 103 | + return listening_socket; |
93 | 104 | } |
0 commit comments