1 /**
2 * collectd - src/ascent.c
3 * Copyright (C) 2008 Florian octo Forster
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; only version 2 of the License is applicable.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 * Authors:
19 * Florian octo Forster <octo at verplant.org>
20 **/
22 #include "collectd.h"
23 #include "common.h"
24 #include "plugin.h"
25 #include "configfile.h"
27 #include <curl/curl.h>
28 #include <libxml/parser.h>
30 static char *url = NULL;
31 static char *user = NULL;
32 static char *pass = NULL;
33 static char *cacert = NULL;
35 static CURL *curl = NULL;
37 static char *ascent_buffer = NULL;
38 static size_t ascent_buffer_size = 0;
39 static size_t ascent_buffer_fill = 0;
40 static char ascent_curl_error[CURL_ERROR_SIZE];
42 static const char *config_keys[] =
43 {
44 "URL",
45 "User",
46 "Password",
47 "CACert"
48 };
49 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
51 static size_t ascent_curl_callback (void *buf, size_t size, size_t nmemb, /* {{{ */
52 void *stream)
53 {
54 size_t len = size * nmemb;
56 if (len <= 0)
57 return (len);
59 if ((ascent_buffer_fill + len) >= ascent_buffer_size)
60 {
61 char *temp;
63 temp = (char *) realloc (ascent_buffer,
64 ascent_buffer_fill + len + 1);
65 if (temp == NULL)
66 {
67 ERROR ("ascent plugin: realloc failed.");
68 return (0);
69 }
70 ascent_buffer = temp;
71 ascent_buffer_size = ascent_buffer_fill + len + 1;
72 }
74 memcpy (ascent_buffer + ascent_buffer_fill, (char *) buf, len);
75 ascent_buffer_fill += len;
76 ascent_buffer[ascent_buffer_fill] = 0;
78 return (len);
79 } /* }}} size_t ascent_curl_callback */
81 static int ascent_xml_submit_gauge (xmlDoc *doc, xmlNode *node, /* {{{ */
82 const char *plugin_instance, const char *type, const char *type_instance)
83 {
84 char *str_ptr;
86 value_t values[1];
87 value_list_t vl = VALUE_LIST_INIT;
89 str_ptr = (char *) xmlNodeListGetString (doc, node->xmlChildrenNode, 1);
90 if (str_ptr == NULL)
91 {
92 ERROR ("ascent plugin: ascent_xml_submit_gauge: xmlNodeListGetString failed.");
93 return (-1);
94 }
96 if (strcasecmp ("N/A", str_ptr) == 0)
97 values[0].gauge = NAN;
98 else
99 {
100 char *end_ptr = NULL;
101 values[0].gauge = strtod (str_ptr, &end_ptr);
102 if (str_ptr == end_ptr)
103 {
104 ERROR ("ascent plugin: ascent_xml_submit_gauge: strtod failed.");
105 return (-1);
106 }
107 }
109 vl.values = values;
110 vl.values_len = 1;
111 vl.time = time (NULL);
112 strcpy (vl.host, hostname_g);
113 strcpy (vl.plugin, "ascent");
115 if (plugin_instance != NULL)
116 sstrncpy (vl.plugin_instance, plugin_instance,
117 sizeof (vl.plugin_instance));
119 if (type_instance != NULL)
120 sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
122 plugin_dispatch_values (type, &vl);
123 } /* }}} int ascent_xml_submit_gauge */
125 static int ascent_xml_status (xmlDoc *doc, xmlNode *node) /* {{{ */
126 {
127 xmlNode *child;
129 for (child = node->xmlChildrenNode; child != NULL; child = child->next)
130 {
131 if ((xmlStrcmp ((const xmlChar *) "comment", child->name) == 0)
132 || (xmlStrcmp ((const xmlChar *) "text", child->name) == 0))
133 /* ignore */;
134 else if (xmlStrcmp ((const xmlChar *) "alliance", child->name) == 0)
135 ascent_xml_submit_gauge (doc, child, NULL, "players", "alliance");
136 else if (xmlStrcmp ((const xmlChar *) "horde", child->name) == 0)
137 ascent_xml_submit_gauge (doc, child, NULL, "players", "horde");
138 else if (xmlStrcmp ((const xmlChar *) "qplayers", child->name) == 0)
139 ascent_xml_submit_gauge (doc, child, NULL, "players", "queued");
140 else
141 {
142 WARNING ("ascent plugin: ascent_xml_status: Unknown tag: %s", child->name);
143 }
144 } /* for (child) */
146 return (0);
147 } /* }}} int ascent_xml_status */
149 static int ascent_xml (const char *data) /* {{{ */
150 {
151 xmlDoc *doc;
152 xmlNode *cur;
153 xmlNode *child;
155 #if 0
156 doc = xmlParseMemory (data, strlen (data),
157 /* URL = */ "ascent.xml",
158 /* encoding = */ NULL,
159 /* options = */ 0);
160 #else
161 doc = xmlParseMemory (data, strlen (data));
162 #endif
163 if (doc == NULL)
164 {
165 ERROR ("ascent plugin: xmlParseMemory failed.");
166 return (-1);
167 }
169 cur = xmlDocGetRootElement (doc);
170 if (cur == NULL)
171 {
172 ERROR ("ascent plugin: XML document is empty.");
173 xmlFreeDoc (doc);
174 return (-1);
175 }
177 if (xmlStrcmp ((const xmlChar *) "serverpage", cur->name) != 0)
178 {
179 ERROR ("ascent plugin: XML root element is not \"serverpage\".");
180 xmlFreeDoc (doc);
181 return (-1);
182 }
184 for (child = cur->xmlChildrenNode; child != NULL; child = child->next)
185 {
186 if ((xmlStrcmp ((const xmlChar *) "comment", child->name) == 0)
187 || (xmlStrcmp ((const xmlChar *) "text", child->name) == 0))
188 /* ignore */;
189 else if (xmlStrcmp ((const xmlChar *) "status", child->name) == 0)
190 ascent_xml_status (doc, child);
191 else if (xmlStrcmp ((const xmlChar *) "instances", child->name) == 0)
192 /* ignore for now */;
193 else if (xmlStrcmp ((const xmlChar *) "gms", child->name) == 0)
194 /* ignore for now */;
195 else if (xmlStrcmp ((const xmlChar *) "sessions", child->name) == 0)
196 /* ignore for now */;
197 else
198 {
199 WARNING ("ascent plugin: ascent_xml: Unknown tag: %s", child->name);
200 }
201 } /* for (child) */
203 xmlFreeDoc (doc);
204 return (0);
205 } /* }}} int ascent_xml */
207 static int config_set (char **var, const char *value) /* {{{ */
208 {
209 if (*var != NULL)
210 {
211 free (*var);
212 *var = NULL;
213 }
215 if ((*var = strdup (value)) == NULL)
216 return (1);
217 else
218 return (0);
219 } /* }}} int config_set */
221 static int ascent_config (const char *key, const char *value) /* {{{ */
222 {
223 if (strcasecmp (key, "URL") == 0)
224 return (config_set (&url, value));
225 else if (strcasecmp (key, "User") == 0)
226 return (config_set (&user, value));
227 else if (strcasecmp (key, "Password") == 0)
228 return (config_set (&pass, value));
229 else if (strcasecmp (key, "CACert") == 0)
230 return (config_set (&cacert, value));
231 else
232 return (-1);
233 } /* }}} int ascent_config */
235 static int ascent_init (void) /* {{{ */
236 {
237 static char credentials[1024];
239 if (url == NULL)
240 {
241 WARNING ("ascent plugin: ascent_init: No URL configured, "
242 "returning an error.");
243 return (-1);
244 }
246 if (curl != NULL)
247 {
248 curl_easy_cleanup (curl);
249 }
251 if ((curl = curl_easy_init ()) == NULL)
252 {
253 ERROR ("ascent plugin: ascent_init: curl_easy_init failed.");
254 return (-1);
255 }
257 curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, ascent_curl_callback);
258 curl_easy_setopt (curl, CURLOPT_USERAGENT, PACKAGE_NAME"/"PACKAGE_VERSION);
259 curl_easy_setopt (curl, CURLOPT_ERRORBUFFER, ascent_curl_error);
261 if (user != NULL)
262 {
263 int status;
265 status = snprintf (credentials, sizeof (credentials), "%s:%s",
266 user, (pass == NULL) ? "" : pass);
267 if (status >= sizeof (credentials))
268 {
269 ERROR ("ascent plugin: ascent_init: Returning an error because the "
270 "credentials have been truncated.");
271 return (-1);
272 }
273 credentials[sizeof (credentials) - 1] = '\0';
275 curl_easy_setopt (curl, CURLOPT_USERPWD, credentials);
276 }
278 curl_easy_setopt (curl, CURLOPT_URL, url);
280 if (cacert != NULL)
281 curl_easy_setopt (curl, CURLOPT_CAINFO, cacert);
283 return (0);
284 } /* }}} int ascent_init */
286 static int ascent_read (void) /* {{{ */
287 {
288 int status;
290 if (curl == NULL)
291 {
292 ERROR ("ascent plugin: I don't have a CURL object.");
293 return (-1);
294 }
296 if (url == NULL)
297 {
298 ERROR ("ascent plugin: No URL has been configured.");
299 return (-1);
300 }
302 ascent_buffer_fill = 0;
303 if (curl_easy_perform (curl) != 0)
304 {
305 ERROR ("ascent plugin: curl_easy_perform failed: %s",
306 ascent_curl_error);
307 return (-1);
308 }
310 status = ascent_xml (ascent_buffer);
311 if (status != 0)
312 return (-1);
313 else
314 return (0);
315 } /* }}} int ascent_read */
317 void module_register (void)
318 {
319 plugin_register_config ("ascent", ascent_config, config_keys, config_keys_num);
320 plugin_register_init ("ascent", ascent_init);
321 plugin_register_read ("ascent", ascent_read);
322 } /* void module_register */
324 /* vim: set sw=2 sts=2 ts=8 et fdm=marker : */