diff options
Diffstat (limited to 'src/vcli.c')
-rw-r--r-- | src/vcli.c | 228 |
1 files changed, 141 insertions, 87 deletions
@@ -25,14 +25,67 @@ #include <arpa/inet.h> #include <errno.h> +struct vcli_sockaddr { + socklen_t len; + struct sockaddr addr[1]; +}; + #define ISSPACE(c) ((c)==' '||(c)=='\t'||(c)=='\n') -static unsigned vcli_timeout = 5; +vcli_sockaddr_t +vcli_parse_sockaddr(char const *arg) +{ + char *node; + size_t n; + int rc; + struct addrinfo *res; + char const *p; + vcli_sockaddr_t sa; + + n = strcspn(arg, ": \t"); + node = malloc(n + 1); + if (!node) { + snmp_log(LOG_ERR, "out of memory\n"); + return NULL; + } -void -varnish_vcli_timeout_parser(const char *token, char *line) + memcpy(node, arg, n); + node[n] = 0; + p = arg + n; + if (*p == ':') + p++; + else + while (*p && ISSPACE(*p)) + p++; + + if (!p) + p = "6082"; + + rc = getaddrinfo(node, p, NULL, &res); + free(node); + if (rc) { + snmp_log(LOG_ERR, "can't resolve %s\n", arg); + return NULL; + } + + sa = malloc(sizeof(*sa) - sizeof(sa->addr) + res->ai_addrlen); + if (!sa) { + snmp_log(LOG_ERR, "out of memory\n"); + return NULL; + } + sa->len = res->ai_addrlen; + memcpy(sa->addr, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + return sa; +} + +vcli_sockaddr_t +vcli_sockaddr_dup(vcli_sockaddr_t src) { - varnish_mib_timeout_parser(token, line, &vcli_timeout); + vcli_sockaddr_t dst; + dst = malloc(sizeof(*dst) - sizeof(dst->addr) + src->len); + memcpy(dst, src, src->len); + return dst; } #define VCLI_INIT_ALLOC 16 @@ -146,7 +199,7 @@ vcli_read(struct vcli_conn *conn, size_t size) if (conn->bufsize == 0) ret = -1; conn->base[conn->bufsize] = 0; - DEBUGMSGTL(("varnish_mib:vcli", "<<varnish: %s\n", conn->base)); + DEBUGMSGTL(("transcript:varnish_mib", "<<varnish: %s\n", conn->base)); } return ret; @@ -229,7 +282,7 @@ vcli_write(struct vcli_conn *conn) { size_t size; - DEBUGMSGTL(("varnish_mib:vcli", ">>varnish: %s\n", conn->base)); + DEBUGMSGTL(("transcript:varnish_mib", ">>varnish: %s\n", conn->base)); for (size = 0; size < conn->bufsize; ) { int n = write(conn->fd, conn->base + size, conn->bufsize - size); @@ -316,14 +369,14 @@ vcli_asprintf(struct vcli_conn *conn, const char *fmt, ...) va_end(ap); return rc; } - - + static int -open_socket(struct sockaddr_in *sa, const char *connstr) +open_socket(vcli_sockaddr_t sa) { - int fd = socket(sa->sin_family, SOCK_STREAM, 0); + int fd; struct timeval start, connect_tv; - + + fd = socket(sa->addr->sa_family, SOCK_STREAM, 0); if (fd == -1) { snmp_log(LOG_ERR, "socket: %s\n", strerror(errno)); return -1; @@ -334,7 +387,7 @@ open_socket(struct sockaddr_in *sa, const char *connstr) gettimeofday(&start, NULL); for (;;) { - int rc = connect(fd, sa, sizeof(*sa)); + int rc = connect(fd, sa->addr, sa->len); if (rc == 0) break; else if (errno == ECONNREFUSED) { @@ -354,12 +407,22 @@ open_socket(struct sockaddr_in *sa, const char *connstr) select(fd + 1, &rset, &wset, &xset, &tv); continue; } + } else { + char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; + int ec = errno; + if (getnameinfo(sa->addr, sa->len, + hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), + NI_NUMERICHOST | NI_NUMERICSERV) == 0) + snmp_log(LOG_ERR, + "cannot connect to %s:%s: %s\n", + hbuf, sbuf, strerror(ec)); + else + snmp_log(LOG_ERR, + "cannot connect to varnish: %s\n", + strerror(ec)); + close(fd); + return -1; } - - snmp_log(LOG_ERR, "cannot connect to %s: %s\n", - connstr, strerror(errno)); - close(fd); - return -1; } return fd; @@ -423,82 +486,73 @@ vcli_handshake(struct vcli_conn *conn) return 0; } -int -vcli_connect(struct vsm *vsm, struct vcli_conn *conn) +static int +parse_connection(struct vsm *vsm, vcli_sockaddr_t *addr, char **secret) { - struct sockaddr_in vcli_sa; - char *portstr, *p; - unsigned long n; - short pn; - struct hostent *hp; - char *T_arg = NULL, *S_arg = NULL; - memset(conn, 0, sizeof(*conn)); - - T_arg = VSM_Dup(vsm, "Arg", "-T"); - if (!T_arg) { - snmp_log(LOG_ERR, "no -T arg in shared memory\n"); - return SNMP_ERR_GENERR; - } - S_arg = VSM_Dup(vsm, "Arg", "-S"); - if (!S_arg) { - free(T_arg); - snmp_log(LOG_ERR, "no -S arg in shared memory\n"); - return SNMP_ERR_GENERR; - } - - DEBUGMSGTL(("varnish_mib:vcli", "-T '%s'\n", (char*) T_arg)); - - for (portstr = T_arg; !ISSPACE(*portstr); portstr++) - ; - if (!*portstr) { - snmp_log(LOG_ERR, "unrecognized -T arg: %s\n", T_arg); - free(T_arg); - free(S_arg); - return SNMP_ERR_GENERR; - } - for (*portstr++ = 0; ISSPACE(*portstr); portstr++) - ; - - n = pn = strtoul(portstr, &p, 0); - if (n != pn || (*p && !ISSPACE(*p))) { - snmp_log(LOG_ERR, "unrecognized -T arg: %s\n", T_arg); + if (vcli_sockaddr) { + DEBUGMSGTL(("varnish_mib:vcli", + "using configured sockaddr\n")); + *addr = vcli_sockaddr_dup(vcli_sockaddr); + } else { + char *T_arg, *p; + T_arg = VSM_Dup(vsm, "Arg", "-T"); + if (!T_arg) { + snmp_log(LOG_ERR, "no -T arg in shared memory\n"); + return SNMP_ERR_GENERR; + } + p = T_arg + strlen(T_arg) - 1; + if (*p == '\n') + *p = 0; + DEBUGMSGTL(("varnish_mib:vcli", "-T '%s'\n", T_arg)); + *addr = vcli_parse_sockaddr(T_arg); free(T_arg); - free(S_arg); - return SNMP_ERR_GENERR; } - - hp = gethostbyname(T_arg); - if (!hp) { - snmp_log(LOG_ERR, "unknown host name %s\n", T_arg); - free(T_arg); - free(S_arg); + if (!*addr) return SNMP_ERR_GENERR; - } - vcli_sa.sin_family = hp->h_addrtype; - if (vcli_sa.sin_family != AF_INET) { - snmp_log(LOG_ERR, "unknown host name %s\n", T_arg); - free(T_arg); - free(S_arg); - return SNMP_ERR_GENERR; - } - - memmove(&vcli_sa.sin_addr, hp->h_addr, 4); - vcli_sa.sin_port = htons(pn); + if (vcli_secret) { + DEBUGMSGTL(("varnish_mib:vcli", + "using configured secret\n")); + *secret = strdup(vcli_secret); + if (!*secret) { + snmp_log(LOG_ERR, "out of memory"); + return SNMP_ERR_GENERR; + } + } else { + char *S_arg = VSM_Dup(vsm, "Arg", "-S"); + if (!S_arg) { + snmp_log(LOG_ERR, "no -S arg in shared memory\n"); + return SNMP_ERR_GENERR; + } + DEBUGMSGTL(("varnish_mib:vcli", "-S '%s'\n", S_arg)); + *secret = S_arg; + } + return 0; +} - conn->fd = open_socket(&vcli_sa, T_arg); - free(T_arg); - if (conn->fd == -1) { - free(S_arg); - return SNMP_ERR_GENERR; - } +int +vcli_connect(struct vsm *vsm, struct vcli_conn *conn) +{ + vcli_sockaddr_t addr = NULL; + char *secret = NULL; + int rc; - DEBUGMSGTL(("varnish_mib:vcli", "-S '%s'\n", S_arg)); - conn->secret = S_arg; - - if (vcli_handshake(conn)) { - vcli_disconnect(conn); - return SNMP_ERR_GENERR; + rc = parse_connection(vsm, &addr, &secret); + if (rc == 0) { + memset(conn, 0, sizeof(*conn)); + conn->fd = open_socket(addr); + if (conn->fd == -1) + rc = SNMP_ERR_GENERR; + else { + conn->secret = secret; + secret = NULL; + if (vcli_handshake(conn)) { + vcli_disconnect(conn); + rc = SNMP_ERR_GENERR; + } + } } - return SNMP_ERR_NOERROR; + free(addr); + free(secret); + return rc; } |