#include #include #include #include #include #include #include #include #include #include "server.h" #include "string_functions.h" Server::Server() { main_socket = -1; close_server = false; } Server::~Server() { Close(); } void Server::CloseMainSocket() { if( main_socket != -1 ) { close(main_socket); main_socket = -1; } } void Server::CloseClientSockets() { for(size_t i=0 ; i 0 ) { if( FD_ISSET(main_socket, &read_set) ) { AddNewClient(); } else { ReadWriteToClients(); } } } } int Server::AddSocketsToSet() { FD_ZERO(&read_set); FD_ZERO(&write_set); int fd_max = 0; if( main_socket >= 0 ) { FD_SET(main_socket, &read_set); fd_max = main_socket; for(size_t i=0 ; i fd_max ) fd_max = client_tab[i].socket; } } else { std::cout << "there is no main socket" << std::endl; } return fd_max; } void Server::AddNewClient() { struct sockaddr_in client_addr; socklen_t len; int client_socket; //int optval; memset(&client_addr, 0, sizeof(client_addr)); len = sizeof(client_addr); client_socket = accept(main_socket, (struct sockaddr*)&client_addr, &len); if( client_socket < 0 ) { std::cout << "accept failed" << std::endl; } else { int opt = fcntl(client_socket, F_GETFL); if( opt >= 0 ) { opt = opt | O_NONBLOCK; if( fcntl(client_socket, F_SETFL, opt) >= 0 ) { Client c; c.socket = client_socket; c.close_connection = false; client_tab.push_back(c); client_tab.back().PrepareToNewRequest(); } else { std::cout << "I cannot fcntl (O_NONBLOCK)" << std::endl; } } } } void Server::ReadWriteToClients() { size_t i = 0; while( i < client_tab.size() ) { if( FD_ISSET(client_tab[i].socket, &read_set)) { ReadInputFromClient(client_tab[i]); } if( client_tab[i].answer_generated && FD_ISSET(client_tab[i].socket, &write_set) ) { WriteOutputToClient(client_tab[i]); } if( client_tab[i].output_buffer.empty() && client_tab[i].close_connection ) { std::cout << "closing connection for client nr " << client_tab[i].socket << std::endl; close(client_tab[i].socket); client_tab.erase(client_tab.begin() + i); } else { i += 1; } } } void Server::ReadInputFromClient(Client & client) { std::cout << "trying read something from client number: " << client.socket << std::endl; // we need at least one char more (for terminating zero for logging/debugging) if( client.in_buffer_max_len - client.in_buffer_len < 2 ) { client.input_buffer.append(client.in_buffer, client.in_buffer_len); client.in_buffer_len = 0; } char * old_pointer = client.in_buffer + client.in_buffer_len; // after adding to client.input_buffer we set in_buffer_len to 0 // so here is sufficient client.in_buffer (without adding client.in_buffer_len) int read_len = read(client.socket, client.in_buffer + client.in_buffer_len, client.in_buffer_max_len - client.in_buffer_len - 1); if( read_len < 0 ) { // read failed, we do not parse this request std::cout << "read failed" << std::endl; client.close_connection = true; } else if( read_len == 0 ) { // end if( client.in_buffer_len > 0 ) { client.input_buffer.append(client.in_buffer, client.in_buffer_len); client.in_buffer_len = 0; } std::cout << "------------------------------ client: " << client.socket << " calosc komunikatu " << std::endl; std::cout << client.input_buffer; std::cout << "----------------------------------------" << std::endl; // the client has terminated connection client.close_connection = true; } else { client.in_buffer_len += read_len; size_t input_buffer_index = client.input_buffer.size(); client.input_buffer.append(client.in_buffer, client.in_buffer_len); client.in_buffer_len = 0; if( client.parsing_headers ) CheckHeaders(client, input_buffer_index); client.in_buffer[client.in_buffer_len] = 0; // only for logging (we have at least one character more for terminating zero) std::cout << "------------------------------ client: " << client.socket << std::endl; std::cout << old_pointer; std::cout << "----------------------------------------" << std::endl; } } void Server::WriteOutputToClient(Client & client) { std::cout << "writing to client nr " << client.socket << std::endl; const char * data = client.output_buffer.c_str() + client.output_buffer_sent; size_t how_many_to_send = client.output_buffer.size() - client.output_buffer_sent; if( how_many_to_send > 0 ) { int len = send(client.socket, data, how_many_to_send, 0); if( len < 0 ) { std::cout << "writing failed" << std::endl; } else { client.output_buffer_sent += len; if( client.output_buffer_sent == client.output_buffer.size() ) { client.PrepareToNewRequest(); } } } } void Server::CheckHeaders(Client & client, size_t input_buffer_index) { // at least 3 bytes before if( input_buffer_index > 3 ) input_buffer_index -= 3; else input_buffer_index = 0; for( ; input_buffer_index + 3 < client.input_buffer.size() ; ++input_buffer_index) { if( headers_parser.IsHeadersEnding(client.input_buffer.c_str() + input_buffer_index) ) { headers_parser.ParseHeaders(client); if( !SelectMethodName(client, client.http_method_str) ) { std::cout << "unsupported http method" << std::endl; client.close_connection = true; } client.parsing_headers = false; client.input_buffer.erase(0, input_buffer_index + 4); // temporarily we are using only get method with http 1.0 (closing connection after answering) if( client.http_method == http_method_get ) { CreateAnswer(client); client.answer_generated = true; if( client.http_version == http_version_1_0 ) { std::cout << "answer generated, closing connection for http 1.0" << std::endl; client.close_connection = true; } } if( client.http_method != http_method_get ) { // at the moment only get method client.close_connection = true; } break; } } } bool Server::SelectMethodName(Client & client, const std::wstring & method_name) { client.http_method = http_method_unsupported; if( CompareNoCase(method_name, L"get") ) { client.http_method = http_method_get; } else if( CompareNoCase(method_name, L"put") ) { client.http_method = http_method_put; } else if( CompareNoCase(method_name, L"post") ) { client.http_method = http_method_post; } else if( CompareNoCase(method_name, L"delete") ) { client.http_method = http_method_delete; } else if( CompareNoCase(method_name, L"options") ) { client.http_method = http_method_options; } return client.http_method != http_method_unsupported; } //void Server::RemoveClientSocket(int client_socket) //{ // for(size_t i=0 ; i
bye bye"; close_server = true; } std::string c_ascii; PT::WideToUTF8(c,c_ascii); a = L"HTTP/"; if( client.http_version == http_version_1_0 ) a += L"1.0"; else a += L"1.1"; a += L" 200 OK\r\n"; a += L"Content-Type: text/html; charset=UTF-8\r\n"; wchar_t buf[32]; swprintf(buf, sizeof(buf)/sizeof(wchar_t), L"%d", c_ascii.size()); a += L"Content-Length: "; a += buf; a += L"\r\n"; a += L"\r\n"; PT::WideToUTF8(a, client.output_buffer); client.output_buffer += c_ascii; }