/* bind socket with port for server socket */ int bind_socket( int *socket_ptr, int port) { struct sockaddr_in serv_addr; int ret = 0; //printf("port = %d\n", port ); //printf("socket_ptr = %d\n", socket_ptr ); *socket_ptr = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP); if ( *socket_ptr < 0 ) { fprintf(stdout,"create socket failed\n"); return -1; } set_socket_reusable(*socket_ptr); set_TCP_keepalive(*socket_ptr); set_TCP_NODELAY ( *socket_ptr ); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl( INADDR_ANY ); serv_addr.sin_port = htons ( port ); ret = bind( *socket_ptr, (struct sockaddr*)&serv_addr, sizeof(struct sockaddr_in)); if ( ret < 0 ) { fprintf(stdout,"bind socket error\n"); return -1; } return 0; }
/* * TCP Connections Establishment function */ int connect_to ( int *fd , char *ip , int port ) { struct sockaddr_in peer_addr; int ret = 0; *fd =socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if ( *fd < 0 ) { fprintf(stdout," socket creation failed\n"); return -1; } set_socket_send_timeout( *fd, 3); set_socket_reusable(*fd); //set_TCP_keepalive(*fd); set_TCP_NODELAY ( *fd ); peer_addr.sin_family = AF_INET; peer_addr.sin_addr.s_addr = inet_addr(ip); peer_addr.sin_port = htons(port); fprintf(stdout," connect to %s:%d\n", ip, port); ret = connect( *fd, (struct sockaddr*) &peer_addr, sizeof( peer_addr ) ); if ( ret < 0 ) { fprintf(stdout," connect() failed\n"); close_socket( fd ); return -1; } return 0; }
int main(int argc, char *argv[]) { auto log = std::unique_ptr<sammy::log>(new sammy::log()); log->info("Starting server."); unsigned int request_id = 1; addrinfo* res = create_addrinfo(); int sockfd = create_socket(res); set_socket_reusable(sockfd); set_socket_bind(sockfd, res); set_socket_non_blocking(sockfd); set_socket_listen(sockfd); int efd = create_epoll(); set_epoll_interface(efd, sockfd); // Init the domain config loading auto domain_storage = std::make_shared<sammy::domain_storage>(); if(domain_storage->errors()) { log->error("Error loading config."); exit(1); } // Init cache auto cache = std::make_shared<sammy::cache_storage>(); // Init events epoll_event* events = new epoll_event[MAX_EPOLL_EVENTS]; sammy::thread::pool thread_pool; std::map<int, std::string> client_ip_address; log->info("Server started"); while( true ) { const int event_count = epoll_wait(efd, events, MAX_EPOLL_EVENTS, -1); for(int i = 0; i < event_count; ++i) { const epoll_event& event = events[i]; if( (event.events & EPOLLERR) || (event.events & EPOLLHUP) || (!(event.events & EPOLLIN))) { std::cout << "Error in the file descriptor." << std::endl; close(event.data.fd); continue; } else if(sockfd == event.data.fd) { while( true ) { sockaddr_in cli_addr; socklen_t clilen{ sizeof(cli_addr) }; // Accept the the request int newsockfd = accept(sockfd, (sockaddr*)&cli_addr, &clilen); if(newsockfd == -1) { break; } set_socket_non_blocking(sockfd); set_epoll_interface(efd, newsockfd); std::string out; inet_ntop(AF_INET, &(cli_addr.sin_addr), &out[0], INET_ADDRSTRLEN); client_ip_address[newsockfd] = out; } continue; } else { int newsockfd = event.data.fd; std::string client_address = client_ip_address[newsockfd]; std::string request_str = ""; size_t read_result = 0; read_request(newsockfd, read_result, request_str); // If the read result isn't ok if(read_result == -1) { log->error("Error in read result, error #" + std::to_string(errno)); close(newsockfd); continue; } // The request string is empty if(request_str.empty()) { log->error("Request string empty."); close(newsockfd); continue; } // Parse request string auto client_request = std::make_shared<sammy::request>(request_id, request_str); if(client_request->errors()) { log->error("Request parse error: " + client_request->error_text()); close(newsockfd); continue; } request_id++; // Load domain configuration std::string response = ""; auto domain = domain_storage->get_domain(client_request->get_host()); // If this server does not serve the domain being asked for, we close the connection. if(!domain) { log->error(client_address + " : " + client_request->get_host() + " : " + client_request->get_method() + " : " + client_request->get_path() + " : Domain not served."); close(newsockfd); continue; } // If the client address is blacklisted, we close the connection. if(domain->is_blacklisted(client_address)) { log->error(client_address + " : " + client_request->get_host() + " : " + client_request->get_method() + " : " + client_request->get_path() + " : IP blacklisted."); close(newsockfd); continue; } // Add the task, to be processed by the thread pool when possible thread_pool.add_task(std::make_shared<sammy::thread::task>(newsockfd, domain, client_request, cache, client_address)); continue; } } } delete [] events; return 0; }