00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <syslog.h>
00032 #include <pthread.h>
00033 #include <signal.h>
00034 #include <errno.h>
00035 #include <time.h>
00036
00037
00038 #include <sys/types.h>
00039 #include <unistd.h>
00040
00041
00042 #include <string.h>
00043
00044
00045 #include <sys/wait.h>
00046
00047 #include "httpd.h"
00048 #include "safe.h"
00049 #include "debug.h"
00050 #include "conf.h"
00051 #include "gateway.h"
00052 #include "firewall.h"
00053 #include "commandline.h"
00054 #include "auth.h"
00055 #include "http.h"
00056 #include "client_list.h"
00057 #include "wdctl_thread.h"
00058 #include "ping_thread.h"
00059 #include "httpd_thread.h"
00060 #include "util.h"
00061
00066 static pthread_t tid_fw_counter = 0;
00067 static pthread_t tid_ping = 0;
00068
00076 void
00077 sigchld_handler(int s)
00078 {
00079 int status;
00080
00081 wait(&status);
00082 }
00083
00086 void
00087 termination_handler(int s)
00088 {
00089 static pthread_mutex_t sigterm_mutex = PTHREAD_MUTEX_INITIALIZER;
00090
00091 debug(LOG_INFO, "Caught signal %d", s);
00092
00093
00094 if (pthread_mutex_trylock(&sigterm_mutex)) {
00095 debug(LOG_INFO, "Another thread already began global termination handler. I'm exiting");
00096 pthread_exit(NULL);
00097 }
00098 else {
00099 debug(LOG_INFO, "Cleaning up and exiting");
00100 }
00101
00102 debug(LOG_DEBUG, "Flushing firewall rules...");
00103 fw_destroy();
00104
00105
00106
00107
00108
00109 if (tid_fw_counter) {
00110 debug(LOG_INFO, "Explicitly killing the fw_counter thread");
00111 pthread_kill(tid_fw_counter, SIGKILL);
00112 }
00113 if (tid_ping) {
00114 debug(LOG_INFO, "Explicitly killing the ping thread");
00115 pthread_kill(tid_ping, SIGKILL);
00116 }
00117
00118 debug(LOG_DEBUG, "Exiting...");
00119 exit(s == 0 ? 1 : 0);
00120 }
00121
00125 static void
00126 init_signals(void)
00127 {
00128 struct sigaction sa;
00129
00130 debug(LOG_DEBUG, "Initializing signal handlers");
00131
00132 sa.sa_handler = sigchld_handler;
00133 sigemptyset(&sa.sa_mask);
00134 sa.sa_flags = SA_RESTART;
00135 if (sigaction(SIGCHLD, &sa, NULL) == -1) {
00136 debug(LOG_ERR, "sigaction(): %s", strerror(errno));
00137 exit(1);
00138 }
00139
00140
00141
00142
00143
00144
00145
00146 sa.sa_handler = SIG_IGN;
00147 if (sigaction(SIGPIPE, &sa, NULL) == -1) {
00148 debug(LOG_ERR, "sigaction(): %s", strerror(errno));
00149 exit(1);
00150 }
00151
00152 sa.sa_handler = termination_handler;
00153 sigemptyset(&sa.sa_mask);
00154 sa.sa_flags = SA_RESTART;
00155
00156
00157 if (sigaction(SIGTERM, &sa, NULL) == -1) {
00158 debug(LOG_ERR, "sigaction(): %s", strerror(errno));
00159 exit(1);
00160 }
00161
00162
00163 if (sigaction(SIGQUIT, &sa, NULL) == -1) {
00164 debug(LOG_ERR, "sigaction(): %s", strerror(errno));
00165 exit(1);
00166 }
00167
00168
00169 if (sigaction(SIGINT, &sa, NULL) == -1) {
00170 debug(LOG_ERR, "sigaction(): %s", strerror(errno));
00171 exit(1);
00172 }
00173 }
00174
00178 static void
00179 main_loop(void)
00180 {
00181 httpd * webserver;
00182 int result;
00183 pthread_t tid;
00184 s_config *config = config_get_config();
00185 request *r;
00186 void **params;
00187
00188
00189 client_list_init();
00190
00191
00192 if (!config->gw_address) {
00193 debug(LOG_DEBUG, "Finding IP address of %s", config->gw_interface);
00194 if ((config->gw_address = get_iface_ip(config->gw_interface)) == NULL) {
00195 debug(LOG_ERR, "Could not get IP address information of %s, exiting...", config->gw_interface);
00196 exit(1);
00197 }
00198 debug(LOG_DEBUG, "%s = %s", config->gw_interface, config->gw_address);
00199 }
00200
00201
00202 debug(LOG_NOTICE, "Creating web server on %s:%d",
00203 config->gw_address, config->gw_port);
00204 webserver = httpdCreate(config->gw_address, config->gw_port);
00205 if (webserver == NULL) {
00206 debug(LOG_ERR, "Could not create web server: %s",
00207 strerror(errno));
00208 exit(1);
00209 }
00210 debug(LOG_DEBUG, "Assigning callbacks to web server");
00211 httpdAddCContent(webserver, "/", "wifidog", 0, NULL, http_callback_wifidog);
00212 httpdAddCContent(webserver, "/wifidog", "", 0, NULL, http_callback_wifidog);
00213 httpdAddCContent(webserver, "/wifidog", "about", 0, NULL, http_callback_about);
00214 httpdAddCContent(webserver, "/wifidog", "status", 0, NULL, http_callback_status);
00215 httpdAddCContent(webserver, "/wifidog", "auth", 0, NULL, http_callback_auth);
00216 httpdAddC404Content(webserver, http_callback_404);
00217
00218
00219 init_signals();
00220
00221
00222 fw_destroy();
00223 fw_init();
00224
00225
00226 result = pthread_create(&tid_fw_counter, NULL, (void *)thread_client_timeout_check, NULL);
00227 if (result != 0) {
00228 debug(LOG_ERR, "FATAL: Failed to create a new thread (fw_counter) - exiting");
00229 termination_handler(0);
00230 }
00231 pthread_detach(tid_fw_counter);
00232
00233
00234 result = pthread_create(&tid, NULL, (void *)thread_wdctl, (void *)safe_strdup(config->wdctl_sock));
00235 if (result != 0) {
00236 debug(LOG_ERR, "FATAL: Failed to create a new thread (wdctl) - exiting");
00237 termination_handler(0);
00238 }
00239 pthread_detach(tid);
00240
00241
00242 result = pthread_create(&tid_ping, NULL, (void *)thread_ping, NULL);
00243 if (result != 0) {
00244 debug(LOG_ERR, "FATAL: Failed to create a new thread (ping) - exiting");
00245 termination_handler(0);
00246 }
00247 pthread_detach(tid_ping);
00248
00249 debug(LOG_NOTICE, "Waiting for connections");
00250 while(1) {
00251 r = httpdGetConnection(webserver, NULL);
00252
00253
00254
00255 if (webserver->lastError == -1) {
00256
00257 continue;
00258 }
00259 else if (webserver->lastError < -1) {
00260
00261
00262
00263
00264
00265 debug(LOG_ERR, "FATAL: httpdGetConnection returned unexpected value %d, exiting.", webserver->lastError);
00266 termination_handler(0);
00267 }
00268 else if (r != NULL) {
00269
00270
00271
00272
00273
00274 debug(LOG_INFO, "Received connection from %s, spawning worker thread", r->clientAddr);
00275
00276
00277 params = safe_malloc(2 * sizeof(void *));
00278 *params = webserver;
00279 *(params + 1) = r;
00280
00281 result = pthread_create(&tid, NULL, (void *)thread_httpd, (void *)params);
00282 if (result != 0) {
00283 debug(LOG_ERR, "FATAL: Failed to create a new thread (httpd) - exiting");
00284 termination_handler(0);
00285 }
00286 pthread_detach(tid);
00287 }
00288 else {
00289
00290
00291
00292 }
00293 }
00294
00295
00296 }
00297
00299 int
00300 main(int argc, char **argv)
00301 {
00302 s_config *config = config_get_config();
00303 config_init();
00304
00305 parse_commandline(argc, argv);
00306
00307 config_read(config->configfile);
00308 config_validate();
00309
00310 if (config->daemon) {
00311
00312 debug(LOG_INFO, "Forking into background");
00313
00314 switch(fork()) {
00315 case -1:
00316 debug(LOG_ERR, "fork(): %s", strerror(errno));
00317 exit(1);
00318 break;
00319
00320 case 0:
00321 main_loop();
00322 break;
00323
00324 default:
00325 exit(0);
00326 break;
00327 }
00328 } else {
00329 main_loop();
00330 }
00331
00332 return(0);
00333 }