/* * Copyright (C), 2000-2007 by the monit project group. * All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #ifdef HAVE_STDIO_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_SIGNAL_H #include #endif #ifdef HAVE_ERRNO_H #include #endif #include "monitor.h" #include "socket.h" #include "event.h" /** * Connect to a data collector server and send event or status message. * * @author Martin Pala, * * @version \$Id: collector.c,v 1.15 2007/07/25 12:54:28 hauk Exp $ * * @file */ /* -------------------------------------------------------------- Prototypes */ static int data_send(Collector_T, char *); static int data_check(Collector_T); /* ------------------------------------------------------------------ Public */ /** * Post event or status data message to the collector * @param E An event object or NULL for status data * @return If failed, return HANDLER_COLLECTOR flag or HANDLER_PASSED flag if passed */ int handle_collector(Event_T E) { char *D = NULL; Collector_T C = Run.collectors; sigset_t ns; sigset_t os; int rv = HANDLER_PASSED; /* The event is send to the collector just once - only in the case * that the state changed/matched */ if(!C || (E && !E->state_changed && (E->id != EVENT_CHANGED || E->id != EVENT_MATCH))) { return rv; } set_signal_block(&ns, &os); while(!(C->socket= socket_create_t(C->url->hostname, C->url->port, SOCKET_TCP, C->ssl, C->timeout) )) { LogError("Collector: cannot open a connection to %s -- %s\n", C->url->url, STRERROR); if((C= C->next)) { LogInfo("Collector: trying next server %s\n", C->url->url); continue; } else { LogError("Collector: no server available\n"); rv = HANDLER_COLLECTOR; goto exit2; } } D = status_xml(E, LEVEL_FULL); if(!data_send(C, D)) { LogError("Collector: communication failure\n"); rv = HANDLER_COLLECTOR; goto exit1; } if(!data_check(C)) { LogError("Collector: communication failure\n"); rv = HANDLER_COLLECTOR; goto exit1; } DEBUG("Collector: %s message send to %s\n", E?"event":"status", C->url->url); exit1: FREE(D); if(C->socket) { socket_free(&C->socket); } exit2: unset_signal_block(&os); return rv; } /* ----------------------------------------------------------------- Private */ /** * Send message to the server * @param C An collector object * @param D Data to send * @return TRUE if the message sending succeeded otherwise FALSE */ static int data_send(Collector_T C, char *D) { int rv; char *auth; auth = Util_getBasicAuthHeader(); rv = socket_print(C->socket, "POST %s HTTP/1.1\r\n" "Host: %s:%d\r\n" "Content-Type: text/xml\r\n" "Content-Length: %d\r\n" "Pragma: no-cache\r\n" "Accept: */*\r\n" "User-Agent: %s/%s\r\n" "Connection: close\r\n" "%s" "\r\n" "%s", C->url->path, C->url->hostname, C->url->port, strlen(D), prog, VERSION, auth?auth:"", D); FREE(auth); if(rv <0) { LogError("Collector: error sending data to %s -- %s\n", C->url->url, STRERROR); return FALSE; } return TRUE; } /** * Check that the server returns a valid HTTP response * @param C An collector object * @return TRUE if the response is valid otherwise FALSE */ static int data_check(Collector_T C) { int n; int status; char buf[STRLEN]; if(!socket_readln(C->socket, buf, sizeof(buf))) { LogError("Collector: error receiving data from %s -- %s\n", C->url->url, STRERROR); return FALSE; } Util_chomp(buf); n = sscanf(buf, "%*s %d", &status); if(n != 1 || (status >= 400)) { LogError("Collector: message sending failed to %s -- %s\n", C->url->url, buf); return FALSE; } return TRUE; }