root/trunk/wifidog/src/ping_thread.c @ 451

Revision 451, 7.7 KB (checked in by minaguib, 8 years ago)

Insignificant

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/********************************************************************\
2 * This program is free software; you can redistribute it and/or    *
3 * modify it under the terms of the GNU General Public License as   *
4 * published by the Free Software Foundation; either version 2 of   *
5 * the License, or (at your option) any later version.              *
6 *                                                                  *
7 * This program is distributed in the hope that it will be useful,  *
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
10 * GNU General Public License for more details.                     *
11 *                                                                  *
12 * You should have received a copy of the GNU General Public License*
13 * along with this program; if not, contact:                        *
14 *                                                                  *
15 * Free Software Foundation           Voice:  +1-617-542-5942       *
16 * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652       *
17 * Boston, MA  02111-1307,  USA       gnu@gnu.org                   *
18 *                                                                  *
19\********************************************************************/
20
21/* $Header$ */
22/** @file ping_thread.c
23    @brief Periodically checks in with the central auth server to make sure everything is running properly.
24    @author Copyright (C) 2004 Alexandre Carmel-Veilleux <acv@acv.ca>
25*/
26
27#define _GNU_SOURCE
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <pthread.h>
32#include <string.h>
33#include <stdarg.h>
34#include <sys/types.h>
35#include <sys/socket.h>
36#include <netinet/in.h>
37#include <arpa/inet.h>
38#include <netdb.h>
39#include <unistd.h>
40#include <syslog.h>
41#include <signal.h>
42#include <errno.h>
43
44#include "../config.h"
45#include "common.h"
46#include "conf.h"
47#include "debug.h"
48#include "ping_thread.h"
49#include "util.h"
50
51static void ping(void);
52
53/** Launches a thread that periodically checks in with the wifidog auth server to perform heartbeat function.
54@param arg NULL
55@todo This thread loops infinitely, need a watchdog to verify that it is still running?
56*/ 
57void
58thread_ping(void *arg)
59{
60        pthread_cond_t          cond = PTHREAD_COND_INITIALIZER;
61        pthread_mutex_t         cond_mutex = PTHREAD_MUTEX_INITIALIZER;
62        struct  timespec        timeout;
63       
64        while (1) {
65                /* Make sure we check the servers at the very begining */
66                /** @todo  Note that this will only help if the second server responds.  The logic of the ping itslef should be changed so it iterates in the list until it finds one that responds ox exausts the list */
67                debug(LOG_DEBUG, "Running ping()");
68                ping();
69               
70                /* Sleep for config.checkinterval seconds... */
71                timeout.tv_sec = time(NULL) +
72                                config_get_config()->checkinterval;
73                timeout.tv_nsec = 0;
74
75                /* Mutex must be locked for pthread_cond_timedwait... */
76                pthread_mutex_lock(&cond_mutex);
77               
78                /* Thread safe "sleep" */
79                pthread_cond_timedwait(&cond, &cond_mutex, &timeout);
80
81                /* No longer needs to be locked */
82                pthread_mutex_unlock(&cond_mutex);
83        }
84}
85
86/** @internal
87 * This function does the actual request.
88 */
89static void
90ping(void)
91{
92        size_t                  numbytes,
93                                totalbytes;
94        int                     sockfd,
95                                nfds,
96                                done,
97                                i;
98        t_auth_serv             *auth_server;
99        char                    request[MAX_BUF],
100                                *tmp_addr;
101        struct in_addr          *h_addr;
102        struct sockaddr_in      their_addr;
103        fd_set                  readfds;
104        struct timeval          timeout;
105        FILE * fh;
106        unsigned long int sys_uptime  = 0;
107        unsigned int      sys_memfree = 0;
108        float             sys_load    = 0;
109
110
111        debug(LOG_DEBUG, "Entering ping()");
112       
113        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
114                debug(LOG_ERR, "socket(): %s", strerror(errno));
115                exit(1);
116        }
117
118        auth_server = get_auth_server();
119
120        debug(LOG_DEBUG, "Using auth server %s",
121                        auth_server->authserv_hostname);
122       
123        debug(LOG_DEBUG, "Resolving IP");
124        if ((h_addr = (struct in_addr *)wd_gethostbyname(auth_server->authserv_hostname)) == NULL) {
125                debug(LOG_ERR, "Failed to resolve %s via gethostbyname"
126                                "(): %s", auth_server->authserv_hostname, 
127                                strerror(errno));
128                debug(LOG_ERR, "Bumping auth server to last in line.");
129                mark_auth_server_bad(auth_server);
130                close(sockfd);
131                return;
132        }
133
134        if (auth_server->last_ip == NULL) {
135                auth_server->last_ip = strdup(inet_ntoa(*h_addr));
136                if (auth_server->last_ip == NULL) {
137                        debug(LOG_CRIT, "Could not allocate memory, Banzai!");
138                        exit(-1);
139                }
140        } else {
141                tmp_addr = strdup(inet_ntoa(*h_addr));
142                if (strcmp(auth_server->last_ip, tmp_addr) != 0) {
143                        free(auth_server->last_ip);
144                        auth_server->last_ip = tmp_addr;
145                        fw_clear_authservers();
146                        fw_set_authservers();
147                } else {
148                        free(tmp_addr);
149                }
150        }
151
152        their_addr.sin_family = AF_INET;
153        their_addr.sin_port = htons(auth_server->authserv_http_port);
154        their_addr.sin_addr = *h_addr;
155        memset(&(their_addr.sin_zero), '\0', sizeof(their_addr.sin_zero));
156
157        debug(LOG_INFO, "Connecting to auth server %s on port %d", 
158                        auth_server->authserv_hostname, 
159                        auth_server->authserv_http_port);
160
161        if (connect(sockfd, (struct sockaddr *)&their_addr,
162                                sizeof(struct sockaddr)) == -1) {
163                debug(LOG_ERR, "connect(): %s", strerror(errno));
164                debug(LOG_ERR, "Bumping auth server to last in line.");
165                mark_auth_server_bad(auth_server);
166                close(sockfd);
167                free(h_addr);
168                return;
169        }
170        free(h_addr);
171               
172        mark_online();
173
174        /*
175         * Populate uptime, memfree and load
176         */
177        if ((fh = fopen("/proc/uptime", "r"))) {
178                fscanf(fh, "%lu", &sys_uptime);
179                fclose(fh);
180        }
181        if ((fh = fopen("/proc/meminfo", "r"))) {
182                while (!feof(fh)) {
183                        if (fscanf(fh, "MemFree: %u", &sys_memfree) == 0) {
184                                /* Not on this line */
185                                while (!feof(fh) && fgetc(fh) != '\n');
186                        }
187                        else {
188                                /* Found it */
189                                break;
190                        }
191                }
192                fclose(fh);
193        }
194        if ((fh = fopen("/proc/loadavg", "r"))) {
195                fscanf(fh, "%f", &sys_load);
196                fclose(fh);
197        }
198
199        /*
200         * Prep & send request
201         */
202        snprintf(request, sizeof(request) - 1, "GET %sping/?gw_id=%s&sys_uptime=%lu&sys_memfree=%u&sys_load=%.2f HTTP/1.0\n"
203                        "User-Agent: WiFiDog %s\n"
204                        "Host: %s\n"
205                        "\n",
206                        auth_server->authserv_path,
207                        config_get_config()->gw_id,
208                        sys_uptime,
209                        sys_memfree,
210                        sys_load,
211                        VERSION,
212                        auth_server->authserv_hostname);
213
214        debug(LOG_DEBUG, "HTTP Request to Server: [%s]", request);
215       
216        send(sockfd, request, strlen(request), 0);
217
218        debug(LOG_DEBUG, "Reading response");
219       
220        numbytes = totalbytes = 0;
221        done = 0;
222        do {
223                FD_ZERO(&readfds);
224                FD_SET(sockfd, &readfds);
225                timeout.tv_sec = 30; /* XXX magic... 30 second */
226                timeout.tv_usec = 0;
227                nfds = sockfd + 1;
228
229                nfds = select(nfds, &readfds, NULL, NULL, &timeout);
230
231                if (nfds > 0) {
232                        /** We don't have to use FD_ISSET() because there
233                         *  was only one fd. */
234                        numbytes = read(sockfd, request + totalbytes,
235                                        MAX_BUF - (totalbytes + 1));
236                        if (numbytes < 0) {
237                                debug(LOG_ERR, "read(): %s", strerror(errno));
238                                mark_auth_server_bad(auth_server);
239                                close(sockfd);
240                                return;
241                        } else if (numbytes == 0) {
242                                done = 1;
243                        } else {
244                                totalbytes += numbytes;
245                                debug(LOG_DEBUG, "Read %d bytes, total now %d",
246                                                numbytes, totalbytes);
247                        }
248                } else if (nfds == 0) {
249                        debug(LOG_ERR, "select() timed out");
250                        mark_auth_server_bad(auth_server);
251                        close(sockfd);
252                        return;
253                } else if (nfds < 0) {
254                        debug(LOG_ERR, "select(): %s", strerror(errno));
255                        mark_auth_server_bad(auth_server);
256                        close(sockfd);
257                        return;
258                }
259        } while (!done);
260
261        debug(LOG_DEBUG, "Done reading reply, total %d bytes", totalbytes);
262
263        numbytes = totalbytes;
264       
265        request[numbytes] = '\0';
266
267        close(sockfd);
268
269        debug(LOG_DEBUG, "HTTP Response from Server: [%s]", request);
270       
271        if (!strstr(request, "Pong")) {
272                debug(LOG_ERR, "Primary auth server offline");
273                debug(LOG_ERR, "Bumping auth server to last in line.");
274                mark_auth_server_bad(auth_server);
275                return;
276        }
277       
278        debug(LOG_DEBUG, "Auth Server Says: Pong");
279        return; 
280}
Note: See TracBrowser for help on using the browser.