Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * server.cpp - Web server encapsulation around libmicrohttpd 00004 * 00005 * Created: Sun Aug 30 17:40:54 2009 00006 * Copyright 2006-2011 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. 00014 * 00015 * This program is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 * GNU Library General Public License for more details. 00019 * 00020 * Read the full text in the LICENSE.GPL file in the doc directory. 00021 */ 00022 00023 #include <webview/server.h> 00024 #include <webview/request_dispatcher.h> 00025 #include <core/exception.h> 00026 #include <core/exceptions/system.h> 00027 #include <logging/logger.h> 00028 00029 #include <sys/socket.h> 00030 #include <cstdlib> 00031 #include <cstdio> 00032 #include <cerrno> 00033 #include <microhttpd.h> 00034 00035 namespace fawkes { 00036 #if 0 /* just to make Emacs auto-indent happy */ 00037 } 00038 #endif 00039 00040 /** @class WebServer <webview/server.h> 00041 * Encapsulation of the libmicrohttpd webserver. 00042 * This class opens a port serving websites and calls the supplied dispatcher 00043 * for requests. 00044 * @author Tim Niemueller 00045 */ 00046 00047 /** Constructor. 00048 * @param port TCP port to listen on 00049 * @param dispatcher dispatcher to call for requests 00050 * @param logger optional logger, used to output possible run-time problems 00051 */ 00052 WebServer::WebServer(unsigned short int port, WebRequestDispatcher *dispatcher, 00053 fawkes::Logger *logger) 00054 { 00055 __port = port; 00056 __dispatcher = dispatcher; 00057 __logger = logger; 00058 00059 __ssl_key_mem = NULL; 00060 __ssl_cert_mem = NULL; 00061 00062 __daemon = MHD_start_daemon(MHD_NO_FLAG, 00063 __port, 00064 NULL, 00065 NULL, 00066 WebRequestDispatcher::process_request_cb, 00067 (void *)__dispatcher, 00068 MHD_OPTION_END); 00069 00070 if ( __daemon == NULL ) { 00071 throw fawkes::Exception("Could not start microhttpd"); 00072 } 00073 00074 } 00075 00076 /** SSL constructor. 00077 * @param port TCP port to listen on 00078 * @param dispatcher dispatcher to call for requests 00079 * @param key_pem_filepath path to PEM formatted file containing the key 00080 * @param cert_pem_filepath path to PEM formatted file containing the certificate 00081 * @param logger optional logger, used to output possible run-time problems 00082 */ 00083 WebServer::WebServer(unsigned short int port, WebRequestDispatcher *dispatcher, 00084 const char *key_pem_filepath, const char *cert_pem_filepath, 00085 fawkes::Logger *logger) 00086 { 00087 __port = port; 00088 __dispatcher = dispatcher; 00089 __logger = logger; 00090 00091 __ssl_key_mem = read_file(key_pem_filepath); 00092 __ssl_cert_mem = read_file(cert_pem_filepath); 00093 00094 __daemon = MHD_start_daemon(MHD_USE_SSL, 00095 __port, 00096 NULL, 00097 NULL, 00098 WebRequestDispatcher::process_request_cb, 00099 (void *)__dispatcher, 00100 MHD_OPTION_HTTPS_MEM_KEY, __ssl_key_mem, 00101 MHD_OPTION_HTTPS_MEM_CERT, __ssl_cert_mem, 00102 MHD_OPTION_END); 00103 00104 if ( __daemon == NULL ) { 00105 throw fawkes::Exception("Could not start microhttpd (SSL)"); 00106 } 00107 00108 } 00109 00110 00111 /** Destructor. */ 00112 WebServer::~WebServer() 00113 { 00114 MHD_stop_daemon(__daemon); 00115 __daemon = NULL; 00116 __dispatcher = NULL; 00117 00118 if (__ssl_key_mem) free(__ssl_key_mem); 00119 if (__ssl_cert_mem) free(__ssl_cert_mem); 00120 } 00121 00122 00123 /** Read file into memory. 00124 * @param filename file path 00125 * @return memory location of file content, free after done 00126 */ 00127 char * 00128 WebServer::read_file(const char *filename) 00129 { 00130 FILE *f = fopen(filename, "rb"); 00131 if (! f) { 00132 throw CouldNotOpenFileException(filename, errno); 00133 } 00134 00135 long size = 0; 00136 if ((fseek(f, 0, SEEK_END) != 0) || ((size = ftell(f)) == 1)) { 00137 fclose(f); 00138 throw Exception("Cannot determine file size of %s", filename); 00139 } 00140 fseek(f, 0, SEEK_SET); 00141 00142 if ( size == 0 ) { 00143 fclose(f); 00144 throw Exception("File %s has zero length", filename); 00145 } else if (size > 1024 * 1024) { 00146 // keys or certs should not be that long... 00147 fclose(f); 00148 throw Exception("File %s is unexpectedly large", filename); 00149 } 00150 00151 char *rv = (char *)malloc(size); 00152 if (fread(rv, size, 1, f) != 1) { 00153 int terrno = errno; 00154 fclose(f); 00155 free(rv); 00156 throw FileReadException(filename, terrno); 00157 } 00158 00159 fclose(f); 00160 00161 return rv; 00162 } 00163 00164 00165 /** Setup basic authentication. 00166 * @param realm authentication realm to display to the user 00167 * @param verifier verifier to use for checking credentials 00168 */ 00169 void 00170 WebServer::setup_basic_auth(const char *realm, WebUserVerifier *verifier) 00171 { 00172 __dispatcher->setup_basic_auth(realm, verifier); 00173 } 00174 00175 00176 /** Process requests. 00177 * This method waits for new requests and processes them when received. 00178 */ 00179 void 00180 WebServer::process() 00181 { 00182 fd_set read_fd, write_fd, except_fd; 00183 int max_fd = 0; 00184 FD_ZERO(&read_fd); FD_ZERO(&write_fd); FD_ZERO(&except_fd); 00185 if ( MHD_get_fdset(__daemon, &read_fd, &write_fd, &except_fd, &max_fd) != MHD_YES ) { 00186 if (__logger) 00187 __logger->log_warn("WebviewThread", "Could not get microhttpd fdsets"); 00188 return; 00189 } 00190 select(max_fd + 1, &read_fd, &write_fd, &except_fd, NULL); 00191 MHD_run(__daemon); 00192 } 00193 00194 } // end namespace fawkes