* Florian octo Forster <octo at collectd.org>
**/
-#if HAVE_CONFIG_H
-#include "config.h"
+#ifdef WIN32
+#include "gnulib_config.h"
+#include <winsock2.h>
#endif
+#include "config.h"
+
#if !defined(__GNUC__) || !__GNUC__
#define __attribute__(x) /**/
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/socket.h>
#include <sys/types.h>
-#include <sys/un.h>
#include <unistd.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif
+
#include "collectd/client.h"
/* NI_MAXHOST has been obsoleted by RFC 3493 which is a reason for SunOS 5.11
#endif
#endif
+#ifdef WIN32
+#define AI_ADDRCONFIG 0
+#endif
+
/* Secure/static macros. They work like `strcpy' and `strcat', but assure null
* termination. They work for static buffers only, because they use `sizeof'.
* The `SSTRCATF' combines the functionality of `snprintf' and `strcat' which
* is very useful to add formatted stuff to the end of a buffer. */
#define SSTRCPY(d, s) \
do { \
- strncpy((d), (s), sizeof(d)); \
- (d)[sizeof(d) - 1] = 0; \
+ strncpy((d), (s), sizeof(d) - 1); \
+ (d)[sizeof(d) - 1] = '\0'; \
} while (0)
#define SSTRCAT(d, s) \
do { \
size_t _l = strlen(d); \
strncpy((d) + _l, (s), sizeof(d) - _l); \
- (d)[sizeof(d) - 1] = 0; \
+ (d)[sizeof(d) - 1] = '\0'; \
} while (0)
#define SSTRCATF(d, ...) \
do { \
char _b[sizeof(d)]; \
snprintf(_b, sizeof(_b), __VA_ARGS__); \
- _b[sizeof(_b) - 1] = 0; \
+ _b[sizeof(_b) - 1] = '\0'; \
SSTRCAT((d), _b); \
} while (0)
#define LCC_SET_ERRSTR(c, ...) \
do { \
snprintf((c)->errbuf, sizeof((c)->errbuf), __VA_ARGS__); \
- (c)->errbuf[sizeof((c)->errbuf) - 1] = 0; \
} while (0)
/*
*/
struct lcc_connection_s {
FILE *fh;
- char errbuf[1024];
+ char errbuf[2048];
};
struct lcc_response_s {
#if !HAVE_STRERROR_R
snprintf(buf, buflen, "Error #%i; strerror_r is not available.", errnum);
-/* #endif !HAVE_STRERROR_R */
+ /* #endif !HAVE_STRERROR_R */
#elif STRERROR_R_CHAR_P
{
if ((temp != NULL) && (temp != buf) && (temp[0] != 0))
strncpy(buf, temp, buflen);
else
- strncpy(buf, "strerror_r did not return "
- "an error message",
+ strncpy(buf,
+ "strerror_r did not return "
+ "an error message",
buflen);
}
}
-/* #endif STRERROR_R_CHAR_P */
+ /* #endif STRERROR_R_CHAR_P */
#else
if (strerror_r(errnum, buf, buflen) != 0) {
- snprintf(buf, buflen, "Error #%i; "
- "Additionally, strerror_r failed.",
+ snprintf(buf, buflen,
+ "Error #%i; "
+ "Additionally, strerror_r failed.",
errnum);
}
#endif /* STRERROR_R_CHAR_P */
- buf[buflen - 1] = 0;
+ buf[buflen - 1] = '\0';
- return (buf);
+ return buf;
} /* char *sstrerror */
static int lcc_set_errno(lcc_connection_t *c, int err) /* {{{ */
{
if (c == NULL)
- return (-1);
+ return -1;
sstrerror(err, c->errbuf, sizeof(c->errbuf));
- c->errbuf[sizeof(c->errbuf) - 1] = 0;
+ c->errbuf[sizeof(c->errbuf) - 1] = '\0';
- return (0);
+ return 0;
} /* }}} int lcc_set_errno */
static char *lcc_strescape(char *dest, const char *src,
size_t src_pos;
if ((dest == NULL) || (src == NULL))
- return (NULL);
+ return NULL;
dest_pos = 0;
src_pos = 0;
dest_pos++;
src_pos++;
- return (dest);
+ return dest;
} /* }}} char *lcc_strescape */
/* lcc_chomp: Removes all control-characters at the end of a string. */
while (str_len > 0) {
if (str[str_len - 1] >= 32)
break;
- str[str_len - 1] = 0;
+ str[str_len - 1] = '\0';
str_len--;
}
} /* }}} void lcc_chomp */
status = fprintf(c->fh, "%s\r\n", command);
if (status < 0) {
lcc_set_errno(c, errno);
- return (-1);
+ return -1;
}
fflush(c->fh);
- return (0);
+ return 0;
} /* }}} int lcc_send */
static int lcc_receive(lcc_connection_t *c, /* {{{ */
ptr = fgets(buffer, sizeof(buffer), c->fh);
if (ptr == NULL) {
lcc_set_errno(c, errno);
- return (-1);
+ return -1;
}
lcc_chomp(buffer);
lcc_tracef("receive: <-- %s\n", buffer);
res.status = (int)strtol(buffer, &ptr, 0);
if ((errno != 0) || (ptr == &buffer[0])) {
lcc_set_errno(c, errno);
- return (-1);
+ return -1;
}
/* Skip white spaces after the status number */
/* Now copy the message. */
strncpy(res.message, ptr, sizeof(res.message));
- res.message[sizeof(res.message) - 1] = 0;
+ res.message[sizeof(res.message) - 1] = '\0';
/* Error or no lines follow: We're done. */
if (res.status <= 0) {
memcpy(ret_res, &res, sizeof(res));
- return (0);
+ return 0;
}
/* Allocate space for the char-pointers */
res.lines = malloc(res.lines_num * sizeof(*res.lines));
if (res.lines == NULL) {
lcc_set_errno(c, ENOMEM);
- return (-1);
+ return -1;
}
/* Now receive all the lines */
free(res.lines[i]);
}
free(res.lines);
- return (-1);
+ return -1;
}
memcpy(ret_res, &res, sizeof(res));
- return (0);
+ return 0;
} /* }}} int lcc_receive */
static int lcc_sendreceive(lcc_connection_t *c, /* {{{ */
if (c->fh == NULL) {
lcc_set_errno(c, EBADF);
- return (-1);
+ return -1;
}
status = lcc_send(c, command);
if (status != 0)
- return (status);
+ return status;
status = lcc_receive(c, &res);
if (status == 0)
memcpy(ret_res, &res, sizeof(*ret_res));
- return (status);
+ return status;
} /* }}} int lcc_sendreceive */
static int lcc_open_unixsocket(lcc_connection_t *c, const char *path) /* {{{ */
{
+#ifdef WIN32
+ lcc_set_errno(c, ENOTSUP);
+ return -1;
+#else
struct sockaddr_un sa = {0};
int fd;
int status;
fd = socket(AF_UNIX, SOCK_STREAM, /* protocol = */ 0);
if (fd < 0) {
lcc_set_errno(c, errno);
- return (-1);
+ return -1;
}
sa.sun_family = AF_UNIX;
if (status != 0) {
lcc_set_errno(c, errno);
close(fd);
- return (-1);
+ return -1;
}
c->fh = fdopen(fd, "r+");
if (c->fh == NULL) {
lcc_set_errno(c, errno);
close(fd);
- return (-1);
+ return -1;
}
- return (0);
+ return 0;
+#endif /* WIN32 */
} /* }}} int lcc_open_unixsocket */
static int lcc_open_netsocket(lcc_connection_t *c, /* {{{ */
port = strchr(addr, ']');
if (port == NULL) {
LCC_SET_ERRSTR(c, "malformed address: %s", addr_orig);
- return (-1);
+ return -1;
}
*port = 0;
port++;
port = NULL;
else {
LCC_SET_ERRSTR(c, "garbage after address: %s", port);
- return (-1);
+ return -1;
}
} /* if (*addr = ']') */
else if (strchr(addr, '.') != NULL) /* Hostname or IPv4 */
&ai_res);
if (status != 0) {
LCC_SET_ERRSTR(c, "getaddrinfo: %s", gai_strerror(status));
- return (-1);
+ return -1;
}
for (struct addrinfo *ai_ptr = ai_res; ai_ptr != NULL;
if (status != 0) {
lcc_set_errno(c, status);
freeaddrinfo(ai_res);
- return (-1);
+ return -1;
}
freeaddrinfo(ai_res);
- return (0);
+ return 0;
} /* }}} int lcc_open_netsocket */
static int lcc_open_socket(lcc_connection_t *c, const char *addr) /* {{{ */
int status = 0;
if (addr == NULL)
- return (-1);
+ return -1;
assert(c != NULL);
assert(c->fh == NULL);
else
status = lcc_open_netsocket(c, addr);
- return (status);
+ return status;
} /* }}} int lcc_open_socket */
/*
*/
unsigned int lcc_version(void) /* {{{ */
{
- return (LCC_VERSION);
+ return LCC_VERSION;
} /* }}} unsigned int lcc_version */
const char *lcc_version_string(void) /* {{{ */
{
- return (LCC_VERSION_STRING);
+ return LCC_VERSION_STRING;
} /* }}} const char *lcc_version_string */
const char *lcc_version_extra(void) /* {{{ */
{
- return (LCC_VERSION_EXTRA);
+ return LCC_VERSION_EXTRA;
} /* }}} const char *lcc_version_extra */
int lcc_connect(const char *address, lcc_connection_t **ret_con) /* {{{ */
int status;
if (address == NULL)
- return (-1);
+ return -1;
if (ret_con == NULL)
- return (-1);
+ return -1;
c = calloc(1, sizeof(*c));
if (c == NULL)
- return (-1);
+ return -1;
status = lcc_open_socket(c, address);
if (status != 0) {
lcc_disconnect(c);
- return (status);
+ return status;
}
*ret_con = c;
- return (0);
+ return 0;
} /* }}} int lcc_connect */
int lcc_disconnect(lcc_connection_t *c) /* {{{ */
{
if (c == NULL)
- return (-1);
+ return -1;
if (c->fh != NULL) {
fclose(c->fh);
}
free(c);
- return (0);
+ return 0;
} /* }}} int lcc_disconnect */
int lcc_getval(lcc_connection_t *c, lcc_identifier_t *ident, /* {{{ */
int status;
if (c == NULL)
- return (-1);
+ return -1;
if (ident == NULL) {
lcc_set_errno(c, EINVAL);
- return (-1);
+ return -1;
}
/* Build a commend with an escaped version of the identifier string. */
status = lcc_identifier_to_string(c, ident_str, sizeof(ident_str), ident);
if (status != 0)
- return (status);
+ return status;
snprintf(command, sizeof(command), "GETVAL %s",
lcc_strescape(ident_esc, ident_str, sizeof(ident_esc)));
- command[sizeof(command) - 1] = 0;
+ command[sizeof(command) - 1] = '\0';
/* Send talk to the daemon.. */
status = lcc_sendreceive(c, command, &res);
if (status != 0)
- return (status);
+ return status;
if (res.status != 0) {
LCC_SET_ERRSTR(c, "Server error: %s", res.message);
lcc_response_free(&res);
- return (-1);
+ return -1;
}
values_num = res.lines_num;
} \
free(values_names); \
lcc_response_free(&res); \
- return (-1); \
+ return -1; \
} while (0)
/* If neither the values nor the names are requested, return here.. */
if (ret_values_num != NULL)
*ret_values_num = values_num;
lcc_response_free(&res);
- return (0);
+ return 0;
}
/* Allocate space for the values */
lcc_response_free(&res);
- return (0);
+ return 0;
} /* }}} int lcc_getval */
int lcc_putval(lcc_connection_t *c, const lcc_value_list_t *vl) /* {{{ */
if ((c == NULL) || (vl == NULL) || (vl->values_len < 1) ||
(vl->values == NULL) || (vl->values_types == NULL)) {
lcc_set_errno(c, EINVAL);
- return (-1);
+ return -1;
}
status = lcc_identifier_to_string(c, ident_str, sizeof(ident_str),
&vl->identifier);
if (status != 0)
- return (status);
+ return status;
SSTRCATF(command, "PUTVAL %s",
lcc_strescape(ident_esc, ident_str, sizeof(ident_esc)));
status = lcc_sendreceive(c, command, &res);
if (status != 0)
- return (status);
+ return status;
if (res.status != 0) {
LCC_SET_ERRSTR(c, "Server error: %s", res.message);
lcc_response_free(&res);
- return (-1);
+ return -1;
}
lcc_response_free(&res);
- return (0);
+ return 0;
} /* }}} int lcc_putval */
int lcc_flush(lcc_connection_t *c, const char *plugin, /* {{{ */
if (c == NULL) {
lcc_set_errno(c, EINVAL);
- return (-1);
+ return -1;
}
SSTRCPY(command, "FLUSH");
status = lcc_identifier_to_string(c, ident_str, sizeof(ident_str), ident);
if (status != 0)
- return (status);
+ return status;
SSTRCATF(command, " identifier=%s",
lcc_strescape(ident_esc, ident_str, sizeof(ident_esc)));
status = lcc_sendreceive(c, command, &res);
if (status != 0)
- return (status);
+ return status;
if (res.status != 0) {
LCC_SET_ERRSTR(c, "Server error: %s", res.message);
lcc_response_free(&res);
- return (-1);
+ return -1;
}
lcc_response_free(&res);
- return (0);
+ return 0;
} /* }}} int lcc_flush */
/* TODO: Implement lcc_putnotif */
size_t ident_num;
if (c == NULL)
- return (-1);
+ return -1;
if ((ret_ident == NULL) || (ret_ident_num == NULL)) {
lcc_set_errno(c, EINVAL);
- return (-1);
+ return -1;
}
status = lcc_sendreceive(c, "LISTVAL", &res);
if (status != 0)
- return (status);
+ return status;
if (res.status != 0) {
LCC_SET_ERRSTR(c, "Server error: %s", res.message);
lcc_response_free(&res);
- return (-1);
+ return -1;
}
ident_num = res.lines_num;
if (ident == NULL) {
lcc_response_free(&res);
lcc_set_errno(c, ENOMEM);
- return (-1);
+ return -1;
}
for (size_t i = 0; i < res.lines_num; i++) {
if (status != 0) {
free(ident);
- return (-1);
+ return -1;
}
*ret_ident = ident;
*ret_ident_num = ident_num;
- return (0);
+ return 0;
} /* }}} int lcc_listval */
const char *lcc_strerror(lcc_connection_t *c) /* {{{ */
{
if (c == NULL)
- return ("Invalid object");
- return (c->errbuf);
+ return "Invalid object";
+ return c->errbuf;
} /* }}} const char *lcc_strerror */
int lcc_identifier_to_string(lcc_connection_t *c, /* {{{ */
const lcc_identifier_t *ident) {
if ((string == NULL) || (string_size < 6) || (ident == NULL)) {
lcc_set_errno(c, EINVAL);
- return (-1);
+ return -1;
}
if (ident->plugin_instance[0] == 0) {
ident->type_instance);
}
- string[string_size - 1] = 0;
- return (0);
+ string[string_size - 1] = '\0';
+ return 0;
} /* }}} int lcc_identifier_to_string */
int lcc_string_to_identifier(lcc_connection_t *c, /* {{{ */
string_copy = strdup(string);
if (string_copy == NULL) {
lcc_set_errno(c, ENOMEM);
- return (-1);
+ return -1;
}
host = string_copy;
if (plugin == NULL) {
LCC_SET_ERRSTR(c, "Malformed identifier string: %s", string);
free(string_copy);
- return (-1);
+ return -1;
}
*plugin = 0;
plugin++;
if (type == NULL) {
LCC_SET_ERRSTR(c, "Malformed identifier string: %s", string);
free(string_copy);
- return (-1);
+ return -1;
}
*type = 0;
type++;
SSTRCPY(ident->type_instance, type_instance);
free(string_copy);
- return (0);
+ return 0;
} /* }}} int lcc_string_to_identifier */
int lcc_identifier_compare(const void *a, /* {{{ */
int status;
if ((i0 == NULL) && (i1 == NULL))
- return (0);
+ return 0;
else if (i0 == NULL)
- return (-1);
+ return -1;
else if (i1 == NULL)
- return (1);
+ return 1;
#define CMP_FIELD(f) \
do { \
status = strcmp(i0->f, i1->f); \
if (status != 0) \
- return (status); \
+ return status; \
} while (0);
CMP_FIELD(host);
#undef CMP_FIELD
- return (0);
+ return 0;
} /* }}} int lcc_identifier_compare */
int lcc_sort_identifiers(lcc_connection_t *c, /* {{{ */
lcc_identifier_t *idents, size_t idents_num) {
if (idents == NULL) {
lcc_set_errno(c, EINVAL);
- return (-1);
+ return -1;
}
qsort(idents, idents_num, sizeof(*idents), lcc_identifier_compare);
- return (0);
+ return 0;
} /* }}} int lcc_sort_identifiers */