ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/ihost/ihost.c
Revision: 1.16
Committed: Sun May 19 19:42:41 2002 UTC (22 years ago) by pajs
Content type: text/plain
Branch: MAIN
Changes since 1.15: +22 -2 lines
Log Message:
Now sends ip address of host. Doesn't cope with ip changing without at least
a reconfigure signal from the server. Only tested on solaris.

File Contents

# Content
1 /*
2 * i-scream central monitoring system
3 * Copyright (C) 2000-2002 i-scream
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <syslog.h>
24 #include <netinet/in.h>
25 #include "ukcprog.h"
26 #include <netdb.h>
27 #include <string.h>
28 #include "statgrab.h"
29 #include <time.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33
34 #define RECONFIGURE_RETURN_CODE 2
35 #define UDP_MAX_PACKET_SIZE 8192
36
37 typedef struct{
38 int fm_port;
39 char *fm_host;
40
41 char *my_ip;
42 char *my_fqdn;
43 char *server_fqdn;
44 int server_udp_port;
45 int server_tcp_port;
46 char *last_modified;
47 char *files_list;
48 char *key;
49 int udp_update_time;
50 int tcp_update_time;
51
52 }ihost_state_t;
53
54 char* sock_comm(FILE *f_r, FILE *f_w, char *sendString){
55 char *reply;
56 fprintf(f_w, "%s\n", sendString);
57 fflush(f_w);
58 reply=fpgetline(f_r);
59 /* Returns pointer to static buffer */
60 return reply;
61 }
62
63 int ihost_configure(ihost_state_t *ihost_state){
64 struct sockaddr_in addr;
65 struct in_addr haddr;
66 struct sockaddr ip;
67 int ip_len;
68 int sd;
69 FILE *fm_fd_r, *fm_fd_w;
70 char *reply;
71 char *reply_ptr;
72
73 /* Check to see if anything needs to be free'd */
74 if (ihost_state->my_fqdn!=NULL) free(ihost_state->my_fqdn);
75 if (ihost_state->server_fqdn!=NULL) free(ihost_state->server_fqdn);
76 if (ihost_state->last_modified!=NULL) free(ihost_state->last_modified);
77 if (ihost_state->files_list!=NULL) free(ihost_state->files_list);
78
79 if ((sd = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) {
80 errf("Can't create AF_INET socket (%m)");
81 return -1;
82 }
83
84 if (get_host_addr(ihost_state->fm_host, &haddr) != 0){
85 errf("Failed to resolve address %s (%m)", ihost_state->fm_host);
86 return -1;
87 }
88
89 memset(&addr, 0, sizeof addr);
90 addr.sin_family = AF_INET;
91 memcpy(&addr.sin_addr, &haddr, sizeof haddr);
92 addr.sin_port = htons(ihost_state->fm_port);
93
94 if (connect(sd, (struct sockaddr *)&addr, sizeof addr) != 0) {
95 errf("Failed to connect to %s on port %d (%m)", ihost_state->fm_host, ihost_state->fm_port);
96 return -1;
97 }
98
99 /* Need to open 2 files, one for reading one for writing, as it gets confused if we only use 1 :) */
100 if ((fm_fd_r=fdopen(sd,"r")) == NULL){
101 errf("Failed to open read stream (%m)");
102 return -1;
103 }
104
105 if ((fm_fd_w=fdopen(dup(sd),"w")) == NULL){
106 errf("Failed to open write stream (%m)");
107 return -1;
108 }
109 ip_len=sizeof ip;
110 memset(&ip, 0, ip_len);
111 if((getsockname(sd, &ip, &ip_len)) != 0){
112 errf("Failed to get IP address (%m)");
113 return -1;
114 }
115 if (ip.sa_family!=AF_INET){
116 errf("sa family is wrong type");
117 return -1;
118 }
119
120 if((ihost_state->my_ip=inet_ntoa(((struct sockaddr_in *)&ip)->sin_addr))==NULL){
121 errf("Failed to get IP (%m)");
122 return -1;
123 }
124
125 reply=sock_comm(fm_fd_r, fm_fd_w, "STARTCONFIG");
126 if ((reply==NULL) || (strncasecmp(reply, "OK", 2) != 0) ) {
127 errf("Server error");
128 return -1;
129 }
130
131 reply=sock_comm(fm_fd_r, fm_fd_w, "LASTMODIFIED");
132 if((reply== NULL) || (strncasecmp(reply, "ERROR", 5) ==0)){
133 errf("Server error (%m)");
134 return -1;
135 }
136 if((ihost_state->last_modified=strdup(reply)) == NULL){
137 errf("strdup failed (%m)");
138 return -1;
139 }
140
141 reply=sock_comm(fm_fd_r, fm_fd_w, "FILELIST");
142 if((reply== NULL) || (strncasecmp(reply, "ERROR", 5) ==0)){
143 errf("Server error (%m)");
144 return -1;
145 }
146 if((ihost_state->files_list=strdup(reply)) == NULL){
147 errf("strdup failed (%m)");
148 return -1;
149 }
150
151 reply=sock_comm(fm_fd_r, fm_fd_w, "FQDN");
152 if((reply== NULL) || (strncasecmp(reply, "ERROR", 5)==0)){
153 errf("Server error (%m)");
154 return -1;
155 }
156 if((ihost_state->my_fqdn=strdup(reply)) == NULL){
157 errf("strdup failed (%m)");
158 return -1;
159 }
160
161 reply=sock_comm(fm_fd_r, fm_fd_w, "UDPUpdateTime");
162 if(reply== NULL){
163 errf("Server error (%m)");
164 return -1;
165 }
166 if (strncasecmp(reply, "ERROR", 5) != 0){
167 ihost_state->udp_update_time=atoi(reply);
168 }
169
170 reply=sock_comm(fm_fd_r, fm_fd_w, "TCPUpdateTime");
171 if(reply== NULL){
172 errf("Server error (%m)");
173 return -1;
174 }
175 if (strncasecmp(reply, "ERROR", 5) != 0){
176 ihost_state->tcp_update_time=atoi(reply);
177 }
178
179 reply=sock_comm(fm_fd_r, fm_fd_w, "ENDCONFIG");
180 if(reply== NULL){
181 errf("Server error (%m)");
182 return -1;
183 }
184
185 reply=sock_comm(fm_fd_r, fm_fd_w, "FILTER");
186 if((reply== NULL) || (strncasecmp(reply, "ERROR", 5)==0)){
187 errf("Server error FILTER failed (%m)");
188 return -1;
189 }
190 reply_ptr=strchr(reply,';');
191 if (reply_ptr==NULL){
192 errf("Incorrect data returned");
193 return -1;
194 }
195 *reply_ptr='\0';
196 if((ihost_state->server_fqdn=strdup(reply)) == NULL){
197 errf("strdup failed (%m)");
198 return -1;
199 }
200 reply=reply_ptr + 1;
201 reply_ptr=strchr(reply,';');
202 if (reply_ptr==NULL){
203 errf("Incorrect data returned 2");
204 return -1;
205 }
206 *reply_ptr='\0';
207 ihost_state->server_udp_port=atoi(reply);
208 reply=reply_ptr+1;
209 ihost_state->server_tcp_port=atoi(reply);
210 if ((ihost_state->server_tcp_port==0) || (ihost_state->server_udp_port==0)){
211 errf("Incorrect data returned 3 ");
212 return -1;
213 }
214
215 reply=sock_comm(fm_fd_r, fm_fd_w, "END");
216 if((reply== NULL) || (strncasecmp(reply, "ERROR", 5) ==0 )){
217 errf("Server error (%m)");
218 return -1;
219 }
220
221 if(fclose(fm_fd_r) !=0){
222 errf("Failed to close read FD (%m)");
223 return -1;
224 }
225 if(fclose(fm_fd_w) !=0){
226 errf("Failed to close write FD (%m)");
227 return -1;
228 }
229
230 return 0;
231 }
232
233 int heartbeat(ihost_state_t *ihost_state){
234 struct sockaddr_in addr;
235 struct in_addr haddr;
236 int sd;
237 FILE *fm_fd_r, *fm_fd_w;
238 char *reply;
239 int exitcode=0;
240
241 if ((sd = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) {
242 errf("Can't create AF_INET socket (%m)");
243 return -1;
244 }
245
246 if (get_host_addr(ihost_state->server_fqdn, &haddr) != 0){
247 errf("Failed to resolve address %s (%m)", ihost_state->fm_host);
248 return -1;
249 }
250
251 memset(&addr, 0, sizeof addr);
252 addr.sin_family = AF_INET;
253 memcpy(&addr.sin_addr, &haddr, sizeof haddr);
254 addr.sin_port = htons(ihost_state->server_tcp_port);
255
256 if (connect(sd, (struct sockaddr *)&addr, sizeof addr) != 0) {
257 errf("Failed to connect to %s on port %d (%m)", ihost_state->fm_host, ihost_state->fm_port);
258 return -1;
259 }
260
261 /* Need to open 2 files, one for reading one for writing, as it gets confused if we only use 1 :) */
262 if ((fm_fd_r=fdopen(sd,"r")) == NULL){
263 errf("Failed to open stream (%m)");
264 return -1;
265 }
266
267 if ((fm_fd_w=fdopen(dup(sd),"w")) == NULL){
268 errf("Failed to open stream (%m)");
269 return -1;
270 }
271
272 reply=sock_comm(fm_fd_r, fm_fd_w, "HEARTBEAT");
273 if ((reply==NULL) || (strncasecmp(reply, "ERROR", 5) == 0) ) {
274 errf("Server error");
275 return -1;
276 }
277
278 reply=sock_comm(fm_fd_r, fm_fd_w, "CONFIG");
279 if ((reply==NULL) || (strncasecmp(reply, "ERROR", 5) == 0) ) {
280 errf("Server error");
281 return -1;
282 }
283
284 reply=sock_comm(fm_fd_r, fm_fd_w, ihost_state->files_list);
285 if ((reply==NULL) || (strncasecmp(reply, "OK", 2) != 0) ) {
286 errf("Server error");
287 return -1;
288 }
289
290 reply=sock_comm(fm_fd_r, fm_fd_w, ihost_state->last_modified);
291 if (reply==NULL) {
292 errf("Server error");
293 return -1;
294 }
295 if (strncasecmp(reply, "ERROR", 5) == 0){
296 /* Means the config has changed */
297 exitcode=RECONFIGURE_RETURN_CODE;
298 }
299 reply=sock_comm(fm_fd_r, fm_fd_w, "KEY");
300 if ((reply==NULL) || (strncasecmp(reply, "ERROR", 5) == 0) ) {
301 errf("Server error");
302 return -1;
303 }
304 if (ihost_state->key!=NULL) free(ihost_state->key);
305
306 if((ihost_state->key=strdup(reply)) == NULL){
307 errf("strdup failed (%m)");
308 return -1;
309 }
310
311 reply=sock_comm(fm_fd_r, fm_fd_w, "ENDHEARTBEAT");
312 if((reply== NULL) || (strncasecmp(reply, "ERROR", 5) ==0 )){
313 errf("Server error (%m)");
314 return -1;
315 }
316
317 fflush(fm_fd_r);
318 fflush(fm_fd_w);
319
320 if(fclose(fm_fd_r) !=0){
321 errf("Failed to close read FD (%m)");
322 return -1;
323 }
324 if(fclose(fm_fd_w) !=0){
325 errf("Failed to close write FD (%m)");
326 return -1;
327 }
328
329 return exitcode;
330 }
331
332 char *stat_grab(ihost_state_t *ihost_state, int counter){
333 #define NUM_STATS 9
334 char *stats[NUM_STATS];
335 char *xml_data=NULL;
336 char *xml_data_p;
337 int x=0;
338
339 stats[0]=get_cpu_stats();
340 stats[1]=get_disk_stats();
341 stats[2]=get_load_stats();
342 stats[3]=get_memory_stats();
343 stats[4]=get_os_info();
344 stats[5]=get_page_stats();
345 stats[6]=get_process_stats();
346 stats[7]=get_swap_stats();
347 stats[8]=get_user_stats();
348
349 for(;x<NUM_STATS;x++){
350 if(stats[x]==NULL){
351 return NULL;
352 }
353 if(xml_data==NULL){
354 if((xml_data=strf("%s", stats[x])) == NULL){
355 errf("str failed (%m)");
356 return NULL;
357 }
358 }else{
359 xml_data_p=xml_data;
360 if((xml_data=strf("%s%s", xml_data, stats[x])) == NULL){
361 errf("str failed (%m)");
362 return NULL;
363 }
364 free(xml_data_p);
365 }
366 free(stats[x]);
367 }
368 xml_data_p=xml_data;
369 xml_data=strf("<packet seq_no=\"%d\" machine_name=\"%s\" date=\"%ld\" type=\"data\" ip=\"%s\" key=\"%s\">%s</packet>", counter, ihost_state->my_fqdn, time(NULL), ihost_state->my_ip, ihost_state->key, xml_data);
370 free(xml_data_p);
371
372 return xml_data;
373 }
374
375 int send_stats(ihost_state_t *ihost_state, char *data_stream){
376 struct sockaddr_in addr;
377 struct in_addr haddr;
378
379 int sd;
380 size_t len;
381
382 len=strlen(data_stream);
383 if(len>UDP_MAX_PACKET_SIZE){
384 errf("Too big to send to server. Please reconfigure client and server and recompile");
385 exit(1);
386 }
387
388 if (get_host_addr(ihost_state->server_fqdn, &haddr) != 0){
389 errf("Failed to resolve address %s (%m)", ihost_state->fm_host);
390 return -1;
391 }
392
393 if((sd=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0){
394 errf("failed to create UDP socket (%m)");
395 return -1;
396 }
397
398 memset(&addr, 0, sizeof(addr));
399 addr.sin_family=AF_INET;
400 memcpy((char *)&addr.sin_addr, &haddr, sizeof haddr);
401 addr.sin_port = htons(ihost_state->server_udp_port);
402
403 if((sendto(sd, data_stream, len, 0, (struct sockaddr *) &addr, sizeof(addr))) != len){
404 errf("Send the wrong number of bytes (%m)");
405 return -1;
406 }
407
408 close(sd);
409
410 return 0;
411 }
412
413 int main(int argc, char **argv){
414 ihost_state_t ihost_state;
415 int heartbeat_exit;
416 int counter=0;
417 long udp_time=0, tcp_time=0, stat_grab_time=0, cur_time=0;
418 int sleep_delay=0;
419 char *xml_stats;
420
421 /* NULL'ify so i can tell if i need to free it or not */
422 ihost_state.fm_host=NULL;
423 ihost_state.my_fqdn=NULL;
424 ihost_state.server_fqdn=NULL;
425 ihost_state.last_modified=NULL;
426 ihost_state.files_list=NULL;
427 ihost_state.key=NULL;
428
429 errf_set_progname(argv[0]);
430 if(argc!=3){
431 errf_usage("<host> <port>");
432 exit(1);
433 }
434
435 ihost_state.fm_host=argv[1];
436 ihost_state.fm_port=atoi(argv[2]);
437
438 if(ihost_configure(&ihost_state)!=0){
439 errf("configure failed");
440 /* Ok, ideally we prob should have 2 copies of the structure and carry on if this
441 happens.. But we dont :) (at the moment) */
442 exit(1);
443 }
444
445 for(;;){
446 cur_time=time(NULL);
447 if(cur_time>=tcp_time){
448 /*printf("sending TCP\n");*/
449 heartbeat_exit=heartbeat(&ihost_state);
450 if(heartbeat_exit==RECONFIGURE_RETURN_CODE){
451 /*errf("heartbeat needs to be reconfigured");*/
452 ihost_configure(&ihost_state);
453 /* So udp doesn't wait til next sending before updating */
454 udp_time=0;
455 }
456 if(heartbeat_exit==-1){
457 errf("ah crap");
458 exit(1);
459 }
460 tcp_time=time(NULL)+ihost_state.tcp_update_time;
461 }
462
463 if(cur_time>=udp_time){
464 /*printf("sending UDP\n");*/
465 stat_grab_time=time(NULL);
466 if((xml_stats=stat_grab(&ihost_state, counter++)) == NULL){
467 errf("Failed to get stats (%m)");
468 exit(1);
469 }
470 stat_grab_time=time(NULL)-stat_grab_time;
471 send_stats(&ihost_state, xml_stats);
472 free(xml_stats);
473 udp_time=time(NULL)+ihost_state.udp_update_time-stat_grab_time;
474 }
475
476 if(tcp_time<udp_time){
477 sleep_delay=tcp_time-time(NULL);
478 }else{
479 sleep_delay=udp_time-time(NULL);
480 }
481
482 /*printf("tcp epoc: %ld \t udp epoc: %ld\ntime:%ld \tsleeping: %d\n", tcp_time, udp_time, time(NULL), sleep_delay);*/
483 if(sleep_delay>0) sleep(sleep_delay);
484 }
485 return 0;
486 }
487