1 /*$Id: hb_api.c 20842 2012-01-23 06:50:17Z m-oki $*/
2
3 /*
4 * Copyright (c) 2012, Internet Initiative Japan, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <netdb.h>
34 #include <errno.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
39
40 #include "libarms.h"
41 #include "libarms_resource.h"
42 #include "hb_routine.h"
43 #include "errcode.h"
44
45 /*
46 * internal routines
47 */
48 int
hb_library_ver_major(void)49 hb_library_ver_major(void) {
50 return LIBHB_LIBRARY_VER_MAJOR;
51 }
52
53 int
hb_library_ver_minor(void)54 hb_library_ver_minor(void) {
55 return LIBHB_LIBRARY_VER_MINOR;
56 }
57
58 const char *
hb_library_ver_string(void)59 hb_library_ver_string(void)
60 {
61 static char verstr[HB_MAX_DESC_LEN + 1];
62
63 memset(verstr, 0, sizeof(verstr));
64 snprintf(verstr, sizeof(verstr), "%01d.%02d (%s)",
65 LIBHB_LIBRARY_VER_MAJOR,
66 LIBHB_LIBRARY_VER_MINOR,
67 LIBHB_LIBRARY_VER_DESCRIPTION);
68
69 return (const char *)verstr;
70 }
71
72 int
hb_protocol_ver_major(void)73 hb_protocol_ver_major(void) {
74 return LIBHB_PROTOCOL_VER_MAJOR;
75 }
76
77 int
hb_protocol_ver_minor(void)78 hb_protocol_ver_minor(void) {
79 return LIBHB_PROTOCOL_VER_MINOR;
80 }
81
82 static int
hb_init_common(hb_context_t * ctx,int buflen,int buflen_max)83 hb_init_common(hb_context_t *ctx, int buflen, int buflen_max)
84 {
85 if (ctx == NULL) {
86 return ARMS_EFATAL;
87 }
88 if (buflen < 0) {
89 return ARMS_EINVAL;
90 }
91 if (buflen < buflen_max) {
92 return ARMS_EINVAL;
93 }
94 memset(ctx, 0, sizeof(*ctx));
95 ctx->msgbuf = (uint8_t *)malloc(buflen);
96 ctx->buflen = buflen;
97 ctx->numsvr = 0;
98
99 return 0;
100 }
101
102 int
arms_hb_init(hb_context_t * ctx,int buflen,distribution_id_t id)103 arms_hb_init(hb_context_t *ctx, int buflen, distribution_id_t id)
104 {
105 int error;
106
107 error = hb_init_common(ctx, buflen, HB_NEED_LEN);
108 if (error)
109 return error;
110
111 ctx->id = id;
112 arms_hb_clear(ctx);
113
114 return 0;
115 }
116
117 static int
hb_clear_common(hb_context_t * ctx)118 hb_clear_common(hb_context_t *ctx)
119 {
120 if (ctx == NULL) {
121 return ARMS_EFATAL;
122 }
123 if (ctx->msgbuf == NULL) {
124 return ARMS_EFATAL;
125 }
126 memset(ctx->msgbuf, 0, ctx->buflen);
127 ctx->freeptr = 0;
128
129 return 0;
130 }
131
132 int
arms_hb_clear(hb_context_t * ctx)133 arms_hb_clear(hb_context_t *ctx)
134 {
135 int error;
136
137 error = hb_clear_common(ctx);
138 if (error)
139 return error;
140
141 if (buf_space(ctx) <= (HB_TL_LEN + HB_LEN_HMAC_SHA1)) {
142 return ARMS_ESIZE;
143 }
144 set16b(ctx, HB_TYPE_HMAC);
145 set16b(ctx, HB_LEN_HMAC_SHA1);
146 ctx->freeptr += HB_LEN_HMAC_SHA1;
147
148 if (buf_space(ctx) <= (HB_TL_LEN + HB_LEN_DIST_ID)) {
149 return ARMS_ESIZE;
150 }
151 set16b(ctx, HB_TYPE_DIST_ID);
152 set16b(ctx, HB_LEN_DIST_ID);
153 set16b(ctx, ctx->id.version);
154 set32b(ctx, ctx->id.vendor_code);
155 set16b(ctx, ctx->id.sa_type);
156 set64b(ctx, ctx->id.sa_code);
157
158 return 0;
159 }
160
161 static int
hb_update_server_common(hb_context_t * ctx,void * svr,int num)162 hb_update_server_common(hb_context_t *ctx, void *svr, int num)
163 {
164 if (ctx == NULL)
165 return ARMS_EFATAL;
166 if (ctx->msgbuf == NULL)
167 return ARMS_EFATAL;
168 if (svr == NULL)
169 return ARMS_EINVAL;
170 if ((num > HB_MAX_SERVER) || (num <= 0))
171 return ARMS_EINVAL;
172 return 0;
173 }
174
175 int
arms_hb_update_server(hb_context_t * ctx,arms_hbt_info_t * svr,int num)176 arms_hb_update_server(hb_context_t *ctx, arms_hbt_info_t *svr, int num)
177 {
178 int error;
179
180 error = hb_update_server_common(ctx, svr, num);
181 if (error)
182 return error;
183
184 ctx->numsvr = 0;
185 {
186 int i, n;
187 int count = 0;
188 for (i = 0; i < num; i++) {
189 if ((svr[i].host == NULL) ||
190 (strlen(svr[i].host) >= HB_MAX_HOSTLEN) ||
191 (svr[i].port < 0) ||
192 (svr[i].port > 65535) ||
193 (svr[i].passphrase == NULL) ||
194 (strlen(svr[i].passphrase) >= HB_MAX_PASSLEN)) {
195 ctx->numsvr = 0;
196 return ARMS_EINVAL;
197 }
198 if (count == 0) {
199 count = svr[i].interval;
200 } else {
201 if (count != svr[i].interval) {
202 ctx->numsvr = 0;
203 return ARMS_EINVAL;
204 }
205 }
206 n = sizeof(ctx->server[i].host);
207 strncpy(ctx->server[i].host, svr[i].host, n - 1);
208 ctx->server[i].host[n - 1] = '\0';
209 ctx->server[i].port = svr[i].port;
210 n = sizeof(ctx->server[i].passphrase);
211 strncpy(ctx->server[i].passphrase, svr[i].passphrase, n);
212 ctx->server[i].passphrase[n - 1] = '\0';
213 ctx->server[i].passlen = strlen(svr[i].passphrase);
214 ctx->numsvr++;
215 }
216 }
217 return 0;
218 }
219
220 int
arms_hb_send(hb_context_t * ctx,int af,hb_send_result_t * result)221 arms_hb_send(hb_context_t *ctx, int af, hb_send_result_t *result)
222 {
223 int error, sock, i, err_count;
224 struct addrinfo in, *out;
225 char portbuf[6];
226
227 if (ctx == NULL) {
228 return ARMS_EFATAL;
229 }
230 if (ctx->msgbuf == NULL) {
231 return ARMS_EFATAL;
232 }
233 if (ctx->numsvr <= 0) {
234 return ARMS_EINVAL;
235 }
236 if (result != NULL) {
237 result->err_count = 0;
238 }
239 err_count = 0;
240 for (i = 0; i < ctx->numsvr; i++) {
241 set_hmac(ctx, i);
242
243 memset(&in, 0, sizeof(in));
244 if (af == AF_INET || af == AF_INET6)
245 in.ai_family = af;
246 else
247 in.ai_family = AF_UNSPEC;
248 in.ai_socktype = SOCK_DGRAM;
249 snprintf(portbuf, sizeof(portbuf), "%u", ctx->server[i].port);
250
251 error = getaddrinfo(ctx->server[i].host, portbuf, &in, &out);
252 if (error) {
253 if (result != NULL) {
254 result->err_count++;
255 result->server[i].stage = HB_ESEND_GAI;
256 result->server[i].code = error;
257 }
258 err_count++;
259 continue;
260 }
261 sock = socket(out->ai_family, out->ai_socktype,
262 out->ai_protocol);
263 if (sock < 0) {
264 if (result != NULL) {
265 result->err_count++;
266 result->server[i].stage = HB_ESEND_SOCK;
267 result->server[i].code = errno;
268 }
269 close(sock);
270 freeaddrinfo(out);
271 err_count++;
272 continue;
273 }
274 if (sendto(sock, ctx->msgbuf, ctx->freeptr, 0,
275 out->ai_addr, out->ai_addrlen) < 0) {
276 if (result != NULL) {
277 result->err_count++;
278 result->server[i].stage = HB_ESEND_SENDTO;
279 result->server[i].code = errno;
280 }
281 close(sock);
282 freeaddrinfo(out);
283 err_count++;
284 continue;
285 } else {
286 if (result != NULL) {
287 result->server[i].stage = 0;
288 result->server[i].code = 0;
289 }
290 }
291 close(sock);
292 freeaddrinfo(out);
293 }
294 if (err_count) {
295 return HB_ESEND;
296 }
297 return 0;
298 }
299
300 int
arms_hb_end(hb_context_t * ctx)301 arms_hb_end(hb_context_t *ctx)
302 {
303 if (ctx == NULL) {
304 return ARMS_EFATAL;
305 }
306 if (ctx->msgbuf == NULL) {
307 return ARMS_EFATAL;
308 }
309 memset(ctx->msgbuf, 0, ctx->buflen);
310 free(ctx->msgbuf);
311 ctx->msgbuf = NULL;
312 memset(ctx, 0, sizeof(ctx));
313 return 0;
314 }
315
316 /*
317 * public APIs
318 */
319
320 int
arms_hb_set_cpu_usage(arms_context_t * acx,uint16_t idx,uint8_t utilization)321 arms_hb_set_cpu_usage(arms_context_t *acx, uint16_t idx, uint8_t utilization)
322 {
323 hb_context_t *ctx;
324
325 if (acx == NULL) {
326 return ARMS_EFATAL;
327 }
328 ctx = &acx->hb_ctx;
329 if (ctx->msgbuf == NULL) {
330 return ARMS_EFATAL;
331 }
332 if (buf_space(ctx) < (HB_TL_LEN + HB_LEN_CPU)) {
333 return ARMS_ESIZE;
334 }
335 if (find_multiplex_index(ctx, HB_TYPE_CPU, HB_LEN_CPU, idx)) {
336 return ARMS_EEXIST;
337 }
338 set16b(ctx, HB_TYPE_CPU);
339 set16b(ctx, HB_LEN_CPU);
340 set16b(ctx, idx);
341 set8b(ctx, utilization);
342
343 return 0;
344 }
345
346 int
arms_hb_set_cpu_detail_usage(arms_context_t * acx,uint16_t idx,uint8_t idle,uint8_t interrupt,uint8_t user,uint8_t sys,uint8_t other)347 arms_hb_set_cpu_detail_usage(arms_context_t *acx,
348 uint16_t idx, uint8_t idle,
349 uint8_t interrupt, uint8_t user,
350 uint8_t sys, uint8_t other)
351 {
352 hb_context_t *ctx;
353
354 if (acx == NULL) {
355 return ARMS_EFATAL;
356 }
357 ctx = &acx->hb_ctx;
358 if (ctx->msgbuf == NULL) {
359 return ARMS_EFATAL;
360 }
361 if (buf_space(ctx) < (HB_TL_LEN + HB_LEN_CPU_DETAIL)) {
362 return ARMS_ESIZE;
363 }
364 if (find_multiplex_index(ctx, HB_TYPE_CPU_DETAIL, HB_LEN_CPU_DETAIL, idx)) {
365 return ARMS_EEXIST;
366 }
367 set16b(ctx, HB_TYPE_CPU_DETAIL);
368 set16b(ctx, HB_LEN_CPU_DETAIL);
369 set16b(ctx, idx);
370 set8b(ctx, idle);
371 set8b(ctx, interrupt);
372 set8b(ctx, user);
373 set8b(ctx, sys);
374 set8b(ctx, other);
375 return 0;
376 }
377
378 int
arms_hb_set_mem_usage(arms_context_t * acx,uint16_t idx,uint64_t used,uint64_t avail)379 arms_hb_set_mem_usage(arms_context_t *acx, uint16_t idx,
380 uint64_t used, uint64_t avail)
381 {
382 hb_context_t *ctx;
383
384 if (acx == NULL) {
385 return ARMS_EFATAL;
386 }
387 ctx = &acx->hb_ctx;
388 if (ctx->msgbuf == NULL) {
389 return ARMS_EFATAL;
390 }
391 if (buf_space(ctx) < (HB_TL_LEN + HB_LEN_MEM)) {
392 return ARMS_ESIZE;
393 }
394 if (find_multiplex_index(ctx, HB_TYPE_MEM, HB_LEN_MEM, idx)) {
395 return ARMS_EEXIST;
396 }
397 set16b(ctx, HB_TYPE_MEM);
398 set16b(ctx, HB_LEN_MEM);
399 set16b(ctx, idx);
400 set64b(ctx, used);
401 set64b(ctx, avail);
402 return 0;
403 }
404
405 int
arms_hb_set_disk_usage(arms_context_t * acx,uint16_t idx,uint64_t used,uint64_t avail)406 arms_hb_set_disk_usage(arms_context_t *acx, uint16_t idx,
407 uint64_t used, uint64_t avail)
408 {
409 hb_context_t *ctx;
410
411 if (acx == NULL) {
412 return ARMS_EFATAL;
413 }
414 ctx = &acx->hb_ctx;
415 if (ctx->msgbuf == NULL) {
416 return ARMS_EFATAL;
417 }
418 if (buf_space(ctx) < (4 + HB_LEN_DISK)) {
419 return ARMS_ESIZE;
420 }
421 if (find_multiplex_index(ctx, HB_TYPE_DISK, HB_LEN_DISK, idx)) {
422 return ARMS_EEXIST;
423 }
424 set16b(ctx, HB_TYPE_DISK);
425 set16b(ctx, HB_LEN_DISK);
426 set16b(ctx, idx);
427 set64b(ctx, used);
428 set64b(ctx, avail);
429 return 0;
430 }
431
432 int
arms_hb_set_traffic_count(arms_context_t * acx,uint16_t ifidx,uint64_t in_octet,uint64_t out_octet,uint64_t in_packet,uint64_t out_packet,uint64_t in_error,uint64_t out_error)433 arms_hb_set_traffic_count(arms_context_t *acx, uint16_t ifidx,
434 uint64_t in_octet, uint64_t out_octet,
435 uint64_t in_packet, uint64_t out_packet,
436 uint64_t in_error, uint64_t out_error)
437 {
438 hb_context_t *ctx;
439
440 if (acx == NULL) {
441 return ARMS_EFATAL;
442 }
443 ctx = &acx->hb_ctx;
444 if (ctx->msgbuf == NULL) {
445 return ARMS_EFATAL;
446 }
447 if (buf_space(ctx) < (HB_TL_LEN + HB_LEN_TRAFFIC_COUNT)) {
448 return ARMS_ESIZE;
449 }
450 if (find_multiplex_index(ctx, HB_TYPE_TRAFFIC_COUNT, HB_LEN_TRAFFIC_COUNT, ifidx)) {
451 return ARMS_EEXIST;
452 }
453 set16b(ctx, HB_TYPE_TRAFFIC_COUNT);
454 set16b(ctx, HB_LEN_TRAFFIC_COUNT);
455 set16b(ctx, ifidx);
456 set64b(ctx, in_octet);
457 set64b(ctx, out_octet);
458 set64b(ctx, in_packet);
459 set64b(ctx, out_packet);
460 set64b(ctx, in_error);
461 set64b(ctx, out_error);
462 return 0;
463 }
464
465 int
arms_hb_set_traffic_rate(arms_context_t * acx,uint16_t ifidx,uint64_t in_octet,uint64_t out_octet,uint64_t in_packet,uint64_t out_packet,uint64_t in_error,uint64_t out_error)466 arms_hb_set_traffic_rate(arms_context_t *acx, uint16_t ifidx,
467 uint64_t in_octet, uint64_t out_octet,
468 uint64_t in_packet, uint64_t out_packet,
469 uint64_t in_error, uint64_t out_error)
470 {
471 hb_context_t *ctx;
472
473 if (acx == NULL) {
474 return ARMS_EFATAL;
475 }
476 ctx = &acx->hb_ctx;
477 if (ctx->msgbuf == NULL) {
478 return ARMS_EFATAL;
479 }
480 if (buf_space(ctx) < (HB_TL_LEN + HB_LEN_TRAFFIC_RATE)) {
481 return ARMS_ESIZE;
482 }
483 if (find_multiplex_index(ctx, HB_TYPE_TRAFFIC_RATE, HB_LEN_TRAFFIC_RATE, ifidx)) {
484 return ARMS_EEXIST;
485 }
486 set16b(ctx, HB_TYPE_TRAFFIC_RATE);
487 set16b(ctx, HB_LEN_TRAFFIC_RATE);
488 set16b(ctx, ifidx);
489 set64b(ctx, in_octet);
490 set64b(ctx, out_octet);
491 set64b(ctx, in_packet);
492 set64b(ctx, out_packet);
493 set64b(ctx, in_error);
494 set64b(ctx, out_error);
495 return 0;
496 }
497
498 int
arms_hb_set_radiowave(arms_context_t * acx,uint16_t ifidx,uint8_t misc,uint8_t max,uint8_t min,uint8_t avg)499 arms_hb_set_radiowave(arms_context_t *acx, uint16_t ifidx,
500 uint8_t misc, uint8_t max,
501 uint8_t min, uint8_t avg)
502 {
503 hb_context_t *ctx;
504
505 if (acx == NULL) {
506 return ARMS_EFATAL;
507 }
508 ctx = &acx->hb_ctx;
509 if (ctx->msgbuf == NULL) {
510 return ARMS_EFATAL;
511 }
512 if (buf_space(ctx) < (HB_TL_LEN + HB_LEN_RADIO_WAVE)) {
513 return ARMS_ESIZE;
514 }
515 if (find_multiplex_index(ctx, HB_TYPE_RADIO_WAVE, HB_LEN_RADIO_WAVE, ifidx)) {
516 return ARMS_EEXIST;
517 }
518 set16b(ctx, HB_TYPE_RADIO_WAVE);
519 set16b(ctx, HB_LEN_RADIO_WAVE);
520 set16b(ctx, ifidx);
521 set8b(ctx, misc);
522 set8b(ctx, max);
523 set8b(ctx, min);
524 set8b(ctx, avg);
525 return 0;
526 }
527