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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.