diff options
Diffstat (limited to 'src/vcli.c')
-rw-r--r-- | src/vcli.c | 499 |
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 | |||
30 | unsigned long vcli_timeout = 500; | ||
31 | |||
32 | #define VCLI_INIT_ALLOC 16 | ||
33 | |||
34 | static int | ||
35 | vcli_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 | |||
51 | static int | ||
52 | vcli_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 | |||
73 | static int | ||
74 | vcli_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 | |||
149 | static int | ||
150 | vcli_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 | |||
221 | int | ||
222 | vcli_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 | |||
240 | int | ||
241 | vcli_read_response(struct vcli_conn *conn) | ||
242 | { | ||
243 | char *p; | ||
244 | unsigned long n; | ||