Re: api to query gkrellmd
Bill WIlson <[email protected]>
| Newsgroups | gmane.comp.gnome.apps.gkrellm |
|---|---|
| Message-ID | <[email protected]> |
On Mon, 13 Nov 2006 15:52:20 -0700 Bill Nalen <[email protected]> wrote: > > Unfortunately, the answer sent by the server is not well xml > > defined. I > > show an output, of my java program: > > Yeah, that's what I meant by this line: > "Also Bill's xmlish format lacks the closing xml tag to lower bytes > transmitted." > > You can close the tag yourself when receiving the data, just keep > track of the open tag name and close it when you see a new tag or > something. Right, if there are no embedded xml blocks then the closing xml tag is assumed. To get a dump of everything and see the structure, run gkrellm -s servername -d 0x1000 Once the data starts streaming all the xml is only one level deep so omitting the closing xml tags saves bandwidth. Attached is a standalone C program that Viktor Urban put together based on the gkrellmd source and some info I sent him. It's a good reduction to a simple connect to gkrellmd and dump of the initial data every 60 seconds loop and it doesn't bother with reading the streaming data (though it could be expanded to to so). For applications where data updates are needed only every few seconds, this is fine and simplifies things. It is hardwired to connect to localhost but that is easily modified/expanded in main() to any host you want. I think it's a good starting point. Also, attached is gkrellmd-protocol which is the simple outline I sent to Viktor and a couple of others who have asked about this in the past. At the bottom of gkrellmd_to_text.c there's a collection of the scanning functions from the gkrellm source so you can figure out what data is being sent by each monitor. Bill _______________________________________________ Gkrellm mailing list [email protected] http://lists.jutley.org/cgi-bin/mailman/listinfo/gkrellm
gkrellmd_to_text.c
(text/x-csrc, 6.8 KB)
/* ========================================================================== */
/* */
/* gkrelld_to_text.c minimal skeleton for retrieval of the text data */
/* Modified from Bill Wilson's sources (c) 2001 by Viktor Coyot Urban 2006 */
/* */
/* ========================================================================== */
#include <sys/socket.h>
#include <utime.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#define TYPES 19
#define GKRELLM_VERSION_MAJOR 2
#define GKRELLM_VERSION_MINOR 2
#define GKRELLM_VERSION_REV 9
#define GKRELLM_EXTRAVERSION ""
/* Prototypes */
int gkrellm_client_mode_connect(char *server, int port);
int gkrellm_connect_to(char *server, int server_port);
static void read_server_data(int fd);
static void process_server_line(char *line);
static int getline(int fd, char *buf, int len);
char hostname[20];
const char *message_type_table[TYPES] = {
"", "<cpu>", "<proc>", "<disk>", "<net>", "<net_routed>", "<net_timer>",
"<mem>", "<swap>", "<fs>", "<fs_fstab>", "<fs_mounts>", "<inet>",
"<mail>", "<apm>", "<battery>", "<sensors>", "<time>", "<uptime>"
};
int gkrellm_client_mode_connect(char *server, int port)
{
char buf[128];
int client_fd;
client_fd = gkrellm_connect_to(server, port);
if (client_fd < 0)
{
printf("Cannot connect to %s", server);
return (-1);
}
snprintf(buf, sizeof(buf), "gkrellm %d.%d.%d%s\n",
GKRELLM_VERSION_MAJOR, GKRELLM_VERSION_MINOR, GKRELLM_VERSION_REV, GKRELLM_EXTRAVERSION);
send(client_fd, buf, strlen(buf), 0);
read_server_data(client_fd);
close(client_fd);
return 1;
}
int gkrellm_connect_to(char *server, int server_port)
{
int fd = -1;
struct hostent *addr;
struct sockaddr_in s;
addr = gethostbyname(server);
if (addr)
{
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd >= 0)
{
memset(&s, 0, sizeof(s));
memcpy(&s.sin_addr.s_addr, addr->h_addr, addr->h_length);
s.sin_family = AF_INET;
s.sin_port = htons(server_port);
if (connect(fd, (struct sockaddr *) &s, sizeof(s)) < 0)
{
close(fd);
fd = -1;
}
}
}
if (fd < 0)
return -1;
return fd;
}
static void read_server_data(int fd)
{
char buf[256];
while (1)
{
/* Just discard the setup stuff */
getline(fd, buf, sizeof(buf));
if (!strcmp(buf, "</gkrellmd_setup>"))
break;
}
while (1)
{
getline(fd, buf, sizeof(buf));
if (!strcmp(buf, "</initial_update>"))
break;
process_server_line(buf);
}
/* Here will come the disconnect as we're happy with initial values only
* and we're going to move to the next hostname anyway */
}
static void process_server_line(char *line)
{
int i;
int type = 0;
static int last_valid = 0;
if (!*line || *line == '#')
return;
if (*line == '<')
{
for (i = 0; i < TYPES; ++i)
{
if (!strcmp(message_type_table[i], line))
{
type = i;
break;
}
}
if (type)
last_valid = type;
else
last_valid = 0;
}
/* If we're in a data block (but not the header itself), show it */
/* Lines passing this condition could be fscanf-ed - see the end of the file */
/* I'm just plainly printing them and will extract the important data in a shell script */
if (last_valid && strcmp(message_type_table[last_valid], line))
printf("Hostname: %s Data type: %s Data: %s\n", hostname, message_type_table[last_valid], line);
return;
}
static int getline(int fd, char *buf, int len)
{
fd_set read_fds;
struct timeval tv;
char *s;
int result, n, nread = 0;
FD_ZERO(&read_fds);
FD_SET(fd, &read_fds);
tv.tv_usec = 0;
tv.tv_sec = 15;
s = buf;
*s = '\0';
for (n = 0; n < len - 1; ++n)
{
nread = 0;
result = select(fd + 1, &read_fds, NULL, NULL, &tv);
if (result <= 0 || (nread = recv(fd, s, 1, 0)) != 1)
break;
if (*s == '\n')
{
*s = '\0';
break;
}
*++s = '\0';
}
if (nread < 0 && errno != EINTR)
printf("Broken server connection: %s\n", hostname);
return n;
}
int main()
{
long now, last_check, interval;
int nhosts;
char **hosts;
int i;
int port;
last_check = 0;
interval = 60;
port = 19150;
/* Read the hostnames here as needed */
nhosts = 1;
hosts[0] = strdup("localhost");
/* In the working cycle, walk them in specified interval */
time(&now);
while (1)
{
if (!(now - last_check > interval))
{
sleep(2);
time(&now);
continue;
}
last_check = now;
for (i = 0; i < nhosts; i++)
{
printf("connecting to %s", hosts[i]);
strcpy(hostname, hosts[i]);
gkrellm_client_mode_connect(hosts[i], port);
}
}
}
/*
Lines:
CPU: sscanf(line, "%d %llu %llu %llu %llu", &n, &user, &nice, &sys, &idle);
Proc: sscanf(line, "%d %d %lu %f %d", &proc.n_processes, &proc.n_running, &proc.n_forks, &proc.load, &proc.n_users);
Disk: sscanf(line, "%15s %31s %31s %31s", name, s1, s2, s3);
Net: sscanf(line, "%31s %llu %llu", name, &rx, &tx);
Routed: sscanf(line, "%31s %d", name, &routed);
Timer: sscanf(line, "%s %d", name, &net_timer->up_time);
inet: scrap!
mem: sscanf(line, "%llu %llu %llu %llu %llu %llu", &mem.total, &mem.used, &mem.free, &mem.shared, &mem.buffers, &mem.cached);
swap sscanf(line, "%llu %llu %lu %lu", &mem.swap_total, &mem.swap_used, &mem.swap_in, &mem.swap_out);
fstab sscanf(line, "%127s %63s %63s", dir, dev, type);
mounts sscanf(line, "%127s %63s %63s %lu %lu %lu %lu", dir, dev, type, &m->blocks, &m->bavail, &m->bfree, &m->bsize);
fs sscanf(line, "%127s %63s %lu %lu %lu %lu", dir, dev, &blocks, &bavail, &bfree, &bsize);
mail sscanf(line, "%255s %d %d", path, &total, &new) < 3
battery sscanf(line, "%d %d %d %d %d %d", &present, &on_line, &charging, &percent, &time_left, &n) < 5)
sensors sscanf(line, "%d \"%127[^\"]\" %d %d %d %f", &s.type, basename, &s.id, &s.iodev, &s.inter, &s.raw_value);
uptime sscanf(s, "%lu", &up_minutes);
time sscanf(s, "%d %d %d %d %d %d %d %d %d", &t->tm_sec, &t->tm_min, &t->tm_hour, &t->tm_mday, &t->tm_mon, &t->tm_year, &t->tm_wday, &t->tm_yday, &t->tm_isdst);
*/
gkrellmd-protocol
(application/octet-stream, 1.5 KB) - not displayed