aboutsummaryrefslogtreecommitdiff
path: root/src/vcli.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vcli.c')
-rw-r--r--src/vcli.c499
1 files changed, 499 insertions, 0 deletions
diff --git a/src/vcli.c b/src/vcli.c
new file mode 100644
index 0000000..aaa0933
--- /dev/null
+++ b/src/vcli.c
@@ -0,0 +1,499 @@
1/* This file is part of varnish-mib -*- c -*-
2 Copyright (C) 2014 Sergey Poznyakoff
3
4 Varnish-mib is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 Varnish-mib is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with varnish-mib. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include "varnish_mib.h"
19#include <sys/types.h>
20#include <sys/socket.h>
21#include <sys/time.h>
22#include <sys/ioctl.h>
23#include <netinet/in.h>
24#include <netdb.h>
25#include <arpa/inet.h>
26#include <errno.h>
27
28#define ISSPACE(c) ((c)==' '||(c)=='\t'||(c)=='\n')
29
30unsigned long vcli_timeout = 500;
31
32#define VCLI_INIT_ALLOC 16
33
34static int
35vcli_alloc(struct vcli_conn *conn, size_t size)
36{
37 char *p;
38
39 if (size < conn->bufmax)
40 return 0;
41 p = realloc(conn->base, size);
42 if (!p) {
43 snmp_log(LOG_ERR, "out of memory\n");
44 return -1;
45 }
46 conn->base = p;
47 conn->bufmax = size;
48 return 0;
49}
50
51static int
52vcli_extra_size(struct vcli_conn *conn, size_t incr)
53{
54 if (incr + conn->bufsize > conn->bufmax) {
55 size_t size;
56 if (conn->bufmax == 0)
57 size = incr > VCLI_INIT_ALLOC
58 ? incr
59 : VCLI_INIT_ALLOC;
60 else {
61 for (size = conn->bufmax; size < conn->bufsize + incr;
62 size *= 2)
63 if (size <= conn->bufmax) {
64 snmp_log(LOG_ERR, "out of memory\n");
65 return -1;
66 }
67 }
68 return vcli_alloc(conn, size);
69 }
70 return 0;
71}
72
73static int
74vcli_read(struct vcli_conn *conn, size_t size)
75{
76 fd_set rd;
77 time_t start;
78 struct timeval tv;
79 long ttl;
80 int ret = 0;
81 int rc;
82
83 ++size;
84 rc = vcli_alloc(conn, size + 1);
85 if (rc)
86 return SNMP_ERR_GENERR;
87
88 conn->bufsize = 0;
89 time(&start);
90 while (size) {
91 FD_ZERO(&rd);
92 FD_SET(conn->fd, &rd);
93
94 ttl = vcli_timeout - (time(NULL) - start);
95 if (ttl <= 0) {
96 snmp_log(LOG_ERR, "timed out reading from varnish\n");
97 ret = -1;
98 break;
99 }
100
101 tv.tv_sec = ttl;
102 tv.tv_usec = 0;
103 rc = select(conn->fd + 1, &rd, NULL, NULL, &tv);
104 if (rc < 0) {
105 if (errno == EINTR || errno == EAGAIN)
106 continue;
107 snmp_log(LOG_ERR, "select: %s\n", strerror(errno));
108 ret = -1;
109 break;
110 }
111
112 if (FD_ISSET(conn->fd, &rd)) {
113 int n;
114
115 if (ioctl(conn->fd, FIONREAD, &n) < 0) {
116 snmp_log(LOG_ERR, "ioctl: %s\n",
117 strerror(errno));
118 ret = -1;
119 break;
120 }
121 if (n > size)
122 n = size;
123 rc = read(conn->fd, conn->base + conn->bufsize, n);
124 if (rc > 0) {
125 conn->bufsize += rc;
126 size -= rc;
127 } else if (rc == 0
128 || errno == EINTR || errno == EAGAIN) {
129 continue;
130 } else {
131 snmp_log(LOG_ERR, "read: %s\n",
132 strerror(errno));
133 ret = -1;
134 break;
135 }
136 }
137 }
138
139 if (ret == 0) {
140 if (conn->bufsize == 0)
141 ret = -1;
142 conn->base[conn->bufsize] = 0;
143 DEBUGMSGTL(("vcli_mib", "<<varnish: %s\n", conn->base));
144 }
145
146 return ret;
147}
148
149static int
150vcli_getline(struct vcli_conn *conn)
151{
152 fd_set rd;
153 time_t start;
154 struct timeval tv;
155 long ttl;
156 int ret = 0;
157 int rc;
158
159 conn->bufsize = 0;
160 time(&start);
161 while (1) {
162 FD_ZERO(&rd);
163 FD_SET(conn->fd, &rd);
164
165 ttl = vcli_timeout - (time(NULL) - start);
166 if (ttl <= 0) {
167 snmp_log(LOG_ERR, "timed out reading from varnish\n");
168 ret = -1;
169 break;
170 }
171
172 tv.tv_sec = ttl;
173 tv.tv_usec = 0;
174 rc = select(conn->fd + 1, &rd, NULL, NULL, &tv);
175 if (rc < 0) {
176 if (errno == EINTR || errno == EAGAIN)
177 continue;
178 snmp_log(LOG_ERR, "select: %s\n", strerror(errno));
179 ret = -1;
180 break;
181 }
182
183 if (FD_ISSET(conn->fd, &rd)) {
184 char c;
185
186 rc = read(conn->fd, &c, 1);
187 if (rc == 1) {
188 if (vcli_extra_size(conn, 1)) {
189 ret = -1;
190 break;
191 }
192 conn->base[conn->bufsize++] = c;
193 if (c == '\n')
194 break;
195 } else if (rc == 0
196 || errno == EINTR || errno == EAGAIN) {
197 continue;
198 } else {
199 snmp_log(LOG_ERR, "read: %s\n",
200 strerror(errno));
201 ret = -1;
202 break;
203 }
204 }
205 }
206
207 if (ret == 0) {
208 if (conn->bufsize == 0)
209 ret = -1;
210 else if (conn->base[conn->bufsize-1] == '\n') {
211 conn->bufsize--;
212 if (conn->base[conn->bufsize-1] == '\r')
213 conn->bufsize--;
214 }
215 conn->base[conn->bufsize] = 0;
216 }
217
218 return ret;
219}
220
221int
222vcli_write(struct vcli_conn *conn)
223{
224 size_t size;
225
226 DEBUGMSGTL(("vcli_mib", ">>varnish: %s\n", conn->base));
227 for (size = 0; size < conn->bufsize; ) {
228 int n = write(conn->fd, conn->base + size,
229 conn->bufsize - size);
230 if (n < 0) {
231 snmp_log(LOG_ERR, "write error: %s\n",
232 strerror(errno));
233 return -1;
234 }
235 size += n;
236 }
237 return 0;
238}
239
240int
241vcli_read_response(struct vcli_conn *conn)
242{
243 char *p;
244 unsigned long n;