From: Florian Forster Date: Sun, 22 Jun 2008 15:04:30 +0000 (+0200) Subject: src/rrd_client.[ch]: Add files that handle the the network communication. X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=5866ee35c85e55923a8c128166e063e4c6148000;p=rrdtool.git src/rrd_client.[ch]: Add files that handle the the network communication. The files have been developed as `librrdc.so' as part of the `RRDd' package. They have been renamed and adapted for inclusion into `RRDTool'. --- diff --git a/src/Makefile.am b/src/Makefile.am index c567679..5311592 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -25,6 +25,7 @@ UPD_C_FILES = \ rrd_info.c \ rrd_error.c \ rrd_open.c \ + rrd_client.c \ rrd_nan_inf.c \ rrd_rpncalc.c \ rrd_update.c diff --git a/src/rrd_client.c b/src/rrd_client.c new file mode 100644 index 0000000..619a32a --- /dev/null +++ b/src/rrd_client.c @@ -0,0 +1,271 @@ +/** + * RRDTool - src/rrd_client.c + * Copyright (C) 2008 Florian octo Forster + * + * 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; only version 2 of the License is applicable. + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Florian octo Forster + **/ + +#include "rrd.h" +#include "rrd_client.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +static int sd; +static FILE *sh; + +static int buffer_add_string (const char *str, /* {{{ */ + char **buffer_ret, size_t *buffer_size_ret) +{ + size_t str_size; + + str_size = strlen (str) + 1; + + if (*buffer_size_ret < str_size) + return (-1); + + memcpy (*buffer_ret, str, str_size); + *buffer_ret += str_size; + *buffer_size_ret -= str_size; + + return (0); +} /* }}} int buffer_add_string */ + +static int buffer_add_value (const char *value, /* {{{ */ + char **buffer_ret, size_t *buffer_size_ret) +{ + char temp[4096]; + + if (strncmp (value, "N:", 2) == 0) + snprintf (temp, sizeof (temp), "%lu:%s", + (unsigned long) time (NULL), value + 2); + else + strncpy (temp, value, sizeof (temp)); + temp[sizeof (temp) - 1] = 0; + + return (buffer_add_string (temp, buffer_ret, buffer_size_ret)); +} /* }}} int buffer_add_value */ + +static int rrdd_connect_unix (const char *path) /* {{{ */ +{ + struct sockaddr_un sa; + int status; + + if (path == NULL) + path = RRDD_SOCK_PATH; + + pthread_mutex_lock (&lock); + + if (sh != NULL) + { + pthread_mutex_unlock (&lock); + return (0); + } + + sd = socket (PF_UNIX, SOCK_STREAM, /* protocol = */ 0); + if (sd < 0) + { + status = errno; + pthread_mutex_unlock (&lock); + return (status); + } + + memset (&sa, 0, sizeof (sa)); + sa.sun_family = AF_UNIX; + strncpy (sa.sun_path, path, sizeof (sa.sun_path) - 1); + + status = connect (sd, (struct sockaddr *) &sa, sizeof (sa)); + if (status != 0) + { + status = errno; + pthread_mutex_unlock (&lock); + return (status); + } + + sh = fdopen (sd, "w+"); + if (sh == NULL) + { + status = errno; + close (sd); + sd = -1; + pthread_mutex_unlock (&lock); + return (status); + } + + pthread_mutex_unlock (&lock); + + return (0); +} /* }}} int rrdd_connect_unix */ + +int rrdd_connect (const char *addr) /* {{{ */ +{ + struct addrinfo ai_hints; + struct addrinfo *ai_res; + struct addrinfo *ai_ptr; + int status; + + if (addr == NULL) + addr = RRDD_SOCK_PATH; + + if (strncmp ("unix:", addr, strlen ("unix:")) == 0) + return (rrdd_connect_unix (addr + strlen ("unix:"))); + else if (addr[0] == '/') + return (rrdd_connect_unix (addr)); + + pthread_mutex_lock (&lock); + + if (sh != NULL) + { + pthread_mutex_unlock (&lock); + return (0); + } + + memset (&ai_hints, 0, sizeof (ai_hints)); + ai_hints.ai_flags = 0; +#ifdef AI_ADDRCONFIG + ai_hints.ai_flags |= AI_ADDRCONFIG; +#endif + ai_hints.ai_family = AF_UNSPEC; + ai_hints.ai_socktype = SOCK_STREAM; + + ai_res = NULL; + status = getaddrinfo (addr, DEFAULT_PORT, &ai_hints, &ai_res); + if (status != 0) + { + pthread_mutex_unlock (&lock); + return (status); + } + + for (ai_ptr = ai_res; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) + { + sd = socket (ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol); + if (sd < 0) + { + status = errno; + sd = -1; + continue; + } + + status = connect (sd, ai_ptr->ai_addr, ai_ptr->ai_addrlen); + if (status != 0) + { + status = errno; + close (sd); + sd = -1; + continue; + } + + sh = fdopen (sd, "w+"); + if (sh == NULL) + { + status = errno; + close (sd); + sd = -1; + continue; + } + + assert (status == 0); + break; + } /* for (ai_ptr) */ + pthread_mutex_unlock (&lock); + + return (status); +} /* }}} int rrdd_connect */ + +int rrdd_disconnect (void) /* {{{ */ +{ + int status; + + pthread_mutex_lock (&lock); + + if (sh == NULL) + { + pthread_mutex_unlock (&lock); + return (-1); + } + + status = fclose (sh); + if (status != 0) + status = errno; + + sh = NULL; + sd = -1; + + pthread_mutex_unlock (&lock); + + return (status); +} /* }}} int rrdd_disconnect */ + +int rrdd_update (const char *filename, int values_num, /* {{{ */ + const char * const *values) +{ + char buffer[4096]; + char *buffer_ptr; + size_t buffer_size; + int status; + int i; + + memset (buffer, 0, sizeof (buffer)); + buffer_ptr = &buffer[0]; + buffer_size = sizeof (buffer) - 1; + + buffer_add_string ("update", &buffer_ptr, &buffer_size); + buffer_add_string (filename, &buffer_ptr, &buffer_size); + for (i = 0; i < values_num; i++) + buffer_add_value (values[i], &buffer_ptr, &buffer_size); + + pthread_mutex_lock (&lock); + + if (sh == NULL) + { + pthread_mutex_unlock (&lock); + return (ENOTCONN); + } + + status = write (sd, buffer, sizeof (buffer) - buffer_size); + + status = read (sd, buffer, sizeof (buffer)); + if (status < 0) + { + status = errno; + pthread_mutex_unlock (&lock); + return (status); + } + else if (status == 0) + { + pthread_mutex_unlock (&lock); + return (ENODATA); + } + + status = atoi (buffer); + + pthread_mutex_unlock (&lock); + + return (status); +} /* }}} int rrd_update_daemon */ + +/* + * vim: set sw=2 sts=2 ts=8 et fdm=marker : + */ diff --git a/src/rrd_client.h b/src/rrd_client.h new file mode 100644 index 0000000..e4b012e --- /dev/null +++ b/src/rrd_client.h @@ -0,0 +1,34 @@ +/** + * RRDTool - src/rrd_client.h + * Copyright (C) 2008 Florian octo Forster + * + * 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; only version 2 of the License is applicable. + * + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Florian octo Forster + **/ + +#ifndef __RRD_CLIENT_H +#define __RRD_CLIENT_H 1 + +#define RRDD_SOCK_PATH "unix:/tmp/rrdd.sock" +#define DEFAULT_PORT "42217" + +int rrdd_connect (const char *addr); +int rrdd_disconnect (void); + +int rrdd_update (const char *filename, int values_num, + const char * const *values); + +#endif /* __RRD_CLIENT_H */