// webserver.c #include "./fileSystem.h" #include "./text.h" #include "./mimeTypes.h" #include #include #include #include #include #include #include #include #include #include #include #include class http{ int socket; struct sockaddr_in * hostAddress = malloc( sizeof( struct sockaddr_in ) ); int hostAddresslength = sizeof( struct sockaddr_in ); struct fileSystem * filesystem = new fileSystem(); struct mimeTypes * mimetypes = new mimeTypes(); struct headerManager * headers = new headerManager(); int useSSL = -1; SSL_CTX * sslContext; void ( * requestCallback )( struct request * requestInstance, struct text * response ); void createServer( void ( * requestCallback )( request * req, text * response ) ) { this->requestCallback = requestCallback; if( this->useSSL == 1 ) { this->initializeOpenSSL(); } printf("after initializeOpenSSL\n\n"); } initializeOpenSSL() { // OpenSSL 1.1.0 or above initializes by itself //SSL_load_error_strings(); //ssl_load_ciphers(); //OpenSSL_add_all_algorithms(); /* Lets get nice error messages */ SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); SSLeay_add_ssl_algorithms(); return; } int listen( int port ) { this->socket = socket( AF_INET, SOCK_STREAM, 0 ); int iSetOption = 1; setsockopt( this->socket, SOL_SOCKET, SO_REUSEADDR, ( char * ) & iSetOption, sizeof( iSetOption ) ); if ( this->socket == -1 ) { perror("webserver (socket)"); exit( 0 ); } else { printf("socket created successfully\n"); } // Create the address to bind the socket to this->hostAddress->sin_family = AF_INET; this->hostAddress->sin_port = htons( port ); this->hostAddress->sin_addr.s_addr = htonl( INADDR_ANY ); // Bind the socket to the address if ( bind( this->socket, ( struct sockaddr * ) this->hostAddress, this->hostAddresslength ) != 0 ) { perror("webserver (bind)"); exit( 0 ); } else { printf("socket successfully bound to address\n"); } // Listen for incoming connections if ( listen( this->socket, SOMAXCONN ) != 0 ) { perror("webserver (listen)"); exit( 0 ); } else { printf("server listening for connections\n"); } for (;;) { this->acceptConnection( ); } //this->DestroySSL(); printf("exit"); return 0; } char * getExtension( char * path ) { array * parts = path->split("."); int count = parts->length(); return parts->get( count - 1 ); } logRequest( request * requestInstance ) { printf("server address: [%s:%u]\n", requestInstance->address, requestInstance->port ); printf("mimeType: %-30s \n", requestInstance->mimeType); printf("header: %-30s \n", requestInstance->extension ); printf("method: %-30s \n", requestInstance->method ); printf("version: %-30s \n\n", requestInstance->version ); } acceptConnection( ) { fileSystem * filesystem = this->filesystem; mimeTypes * mimetypes = this->mimetypes; text * response = new text(""); char buffer[ 4096 ]; // Create client address struct sockaddr_in client_addr; int client_addrlen = sizeof(client_addr); // Accept incoming connections int socketConnection = accept( this->socket, (struct sockaddr *)this->hostAddress, ( socklen_t * ) & this->hostAddresslength ); /* struct rusage r_usage; getrusage(RUSAGE_SELF,&r_usage); // Print the maximum resident set size used (in kilobytes). printf("Memory usage: %ld kilobytes\n\n",r_usage.ru_maxrss); free( r_usage ); */ SSL * ssl = NULL; if( this->useSSL == 1 ) { const SSL_METHOD * method = SSLv23_server_method(); this->sslContext = SSL_CTX_new( method ); if ( this->sslContext == NULL ) { printf("Error loading SSL_CTX_NEW '%s'\n\n", stderr); } SSL_CTX_set_options( this->sslContext, SSL_OP_SINGLE_DH_USE ); int use_cert = SSL_CTX_use_certificate_file( this->sslContext, "/etc/letsencrypt/live/unifyjs.org/fullchain.pem" , SSL_FILETYPE_PEM ); int use_prv = SSL_CTX_use_PrivateKey_file( this->sslContext, "/etc/letsencrypt/live/unifyjs.org/privkey.pem", SSL_FILETYPE_PEM ); if( use_cert != 1 ) { printf( "error: SSL_CTX_use_certificate_file\n\n" ); } if( use_prv != 1 ) { printf( "error: SSL_CTX_use_PrivateKey_file\n\n" ); } if ( !SSL_CTX_check_private_key(this->sslContext) ) { printf("Private key does not match the certificate public key\n"); // initiate page describing error. } ssl = SSL_new( this->sslContext ); SSL_set_fd( ssl, socketConnection ); //Here is the SSL Accept portion. Now all reads and writes must use SSL int ssl_err = SSL_accept( ssl ); // SSL routines:SSL_UNDEFINED_FUNCTION:called a function you should not call //printf ("SSL connection using %s\n", SSL_get_cipher( ssl ) ); //ERR_print_errors_fp( stderr ); if( ssl_err == 0 ){ printf("SSL_accept returned zero\n"); } int n; if( ssl_err < 0 ) { int err; if( ( err = SSL_get_error(ssl,n ) ) == SSL_ERROR_WANT_READ) { printf("SSL_accept wants more data\n"); return ; } exit(7); } /* printf ("SSL connection using %s\n", SSL_get_cipher (this->sslContext)); #define CHK_NULL(x) if ((x)==NULL) exit (1) X509* client_cert; char* str; // Get client's certificate (note: beware of dynamic allocation) - opt client_cert = SSL_get_peer_certificate (this->sslContext); if ( client_cert != NULL ) { printf ("Client certificate:\n"); str = X509_NAME_oneline (X509_get_subject_name (client_cert), 0, 0); CHK_NULL(str); printf ("\t subject: %s\n", str); OPENSSL_free (str); str = X509_NAME_oneline (X509_get_issuer_name (client_cert), 0, 0); CHK_NULL(str); printf ("\t issuer: %s\n", str); OPENSSL_free (str); X509_free (client_cert); } else { printf ("Client does not have certificate.\n"); } if ( socketConnection == -1 ) { perror("webserver (accept)"); return; } */ //printf("connection accepted2\n\n"); } else { printf("connection accepted\n\n"); // Get client address int sockn = getsockname( socketConnection, ( struct sockaddr * ) &client_addr, ( socklen_t * ) &client_addrlen); if ( sockn == -1 ) { perror("webserver (getsockname)"); } } int valread; if( this->useSSL == 1 ) { valread = SSL_read( ssl, buffer, 4096 - 1 ); } else { printf("read without ssl\n\n"); int valread = read( socketConnection, buffer, 4096 -1 ); if ( valread == -1 ) { perror("webserver (read)"); //return; } } if ( valread == -1 ) { perror("webserver (read)"); } request * requestInstance = new request(); sscanf( buffer, "%s %s %s", requestInstance->method, requestInstance->url, requestInstance->version ); requestInstance->address = inet_ntoa( client_addr.sin_addr ); requestInstance->port = ntohs( client_addr.sin_port ); requestInstance->extension = this->getExtension( requestInstance->url ); requestInstance->mimeType = mimetypes->getByExtension( requestInstance->extension ); this->requestCallback( requestInstance, response ); //printf("response: %s",response->value); int writeResponse; if( this->useSSL == 1 ) { writeResponse = SSL_write( ssl, response->value, response->length ); } else { // Write to the socket int writeResponse = write( socketConnection, response->value, response->length ); printf("close connection"); if ( writeResponse == -1 ) { perror("webserver (write)"); return; } } if ( writeResponse == -1 ) { perror("webserver (write)"); return; } else { //printf("written a response\n"); } //free( buffer ); //SSL_free( writeResponse ); //response->free(); //requestInstance->free(); close( socketConnection ); //SSL_free( response->value ); // SSL_CTX_free( this->sslContext ); // close( this->socket ); } void dump_buffer(void *buffer, int buffer_size) { int i; for(i = 0;i < buffer_size;++i){ printf( "%c", ( (char *) buffer )[i]); } } } void abort() { } //kill -9 $(lsof -t -i tcp:8080)