Main Page | Data Structures | Directories | File List | Data Fields

src/gateway.c

00001 /********************************************************************\
00002  * This program is free software; you can redistribute it and/or    *
00003  * modify it under the terms of the GNU General Public License as   *
00004  * published by the Free:Software Foundation; either version 2 of   *
00005  * the License, or (at your option) any later version.              *
00006  *                                                                  *
00007  * This program is distributed in the hope that it will be useful,  *
00008  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00009  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00010  * GNU General Public License for more details.                     *
00011  *                                                                  *
00012  * You should have received a copy of the GNU General Public License*
00013  * along with this program; if not, contact:                        *
00014  *                                                                  *
00015  * Free Software Foundation           Voice:  +1-617-542-5942       *
00016  * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652       *
00017  * Boston, MA  02111-1307,  USA       gnu@gnu.org                   *
00018  *                                                                  *
00019  \********************************************************************/
00020 
00021 /* $Header: /cvsroot/wifidog/wifidog/src/gateway.c,v 1.43 2005/03/12 22:16:38 minaguib Exp $ */
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 /* for fork() */
00038 #include <sys/types.h>
00039 #include <unistd.h>
00040 
00041 /* for strerror() */
00042 #include <string.h>
00043 
00044 /* for wait() */
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         /* Makes sure we only call fw_destroy() once. */
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         /* XXX Hack
00106          * Aparently pthread_cond_timedwait under openwrt prevents signals (and therefore termination handler) from happening
00107          * so we need to explicitly kill the threads that use that
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         /* Trap SIGPIPE */
00141         /* This is done so that when libhttpd does a socket operation on
00142          * a disconnected socket (i.e.: Broken Pipes) we catch the signal
00143          * and do nothing. The alternative is to exit. SIGPIPE are harmless
00144          * if not desirable.
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         /* Trap SIGTERM */
00157         if (sigaction(SIGTERM, &sa, NULL) == -1) {
00158                 debug(LOG_ERR, "sigaction(): %s", strerror(errno));
00159                 exit(1);
00160         }
00161 
00162         /* Trap SIGQUIT */
00163         if (sigaction(SIGQUIT, &sa, NULL) == -1) {
00164                 debug(LOG_ERR, "sigaction(): %s", strerror(errno));
00165                 exit(1);
00166         }
00167 
00168         /* Trap SIGINT */
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         /* Initializes the linked list of connected clients */
00189         client_list_init();
00190 
00191     /* If we don't have the Gateway IP address, get it. Can't fail. */
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         /* Initializes the web server */
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         /* Init the signals to catch chld/quit/etc */
00219         init_signals();
00220 
00221         /* Reset the firewall (if WiFiDog crashed) */
00222         fw_destroy();
00223         fw_init();
00224 
00225         /* start clean up thread */
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         /* start control thread */
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         /* start heartbeat thread */
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                 /* We can't convert this to a switch because there might be
00254                  * values that are not -1, 0 or 1. */
00255                 if (webserver->lastError == -1) {
00256                         /* Interrupted system call */
00257                         continue; /* restart loop */
00258                 }
00259                 else if (webserver->lastError < -1) {
00260                         /*
00261                          * FIXME
00262                          * An error occurred - should we abort?
00263                          * reboot the device ?
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                          * We got a connection
00271                          *
00272                          * We should fork another thread
00273                          */
00274                         debug(LOG_INFO, "Received connection from %s, spawning worker thread", r->clientAddr);
00275                         /* The void**'s are a simulation of the normal C
00276                          * function calling sequence. */
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                         /* webserver->lastError should be 2 */
00290                         /* XXX We failed an ACL.... No handling because
00291                          * we don't set any... */
00292                 }
00293         }
00294 
00295         /* never reached */
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: /* error */
00316                         debug(LOG_ERR, "fork(): %s", strerror(errno));
00317                         exit(1);
00318                         break;
00319 
00320                 case 0: /* parent */
00321                         main_loop();
00322                         break;
00323 
00324                 default: /* child */
00325                         exit(0);
00326                         break;
00327                 }
00328         } else {
00329                 main_loop();
00330         }
00331 
00332         return(0); /* never reached */
00333 }

Generated on Sun Apr 3 20:04:46 2005 for WifiDog by  doxygen 1.4.1