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