]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/ctl.c
Add some additional GCC options by default.
[thirdparty/lldpd.git] / src / ctl.c
1 /*
2 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include "lldpd.h"
18
19 #include <unistd.h>
20 #include <errno.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24
25 int
26 ctl_create(char *name)
27 {
28 int s;
29 struct sockaddr_un su;
30 int rc;
31
32 if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
33 return -1;
34 su.sun_family = AF_UNIX;
35 strlcpy(su.sun_path, name, UNIX_PATH_MAX);
36 if (bind(s, (struct sockaddr *)&su, sizeof(struct sockaddr_un)) == -1) {
37 rc = errno; close(s); errno = rc;
38 return -1;
39 }
40 if (listen(s, 5) == -1) {
41 rc = errno; close(s); errno = rc;
42 return -1;
43 }
44 return s;
45 }
46
47 int
48 ctl_connect(char *name)
49 {
50 int s;
51 struct sockaddr_un su;
52 int rc;
53
54 if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
55 return -1;
56 su.sun_family = AF_UNIX;
57 strlcpy(su.sun_path, name, UNIX_PATH_MAX);
58 if (connect(s, (struct sockaddr *)&su, sizeof(struct sockaddr_un)) == -1) {
59 rc = errno;
60 LLOG_WARN("unable to connect to socket " LLDPD_CTL_SOCKET);
61 errno = rc; return -1;
62 }
63 return s;
64 }
65
66 void
67 ctl_msg_init(struct hmsg *t, enum hmsg_type type)
68 {
69 memset(t, 0, MAX_HMSGSIZE);
70 t->hdr.type = type;
71 t->hdr.len = 0;
72 t->hdr.pid = getpid();
73 }
74
75 int
76 ctl_msg_send(int fd, struct hmsg *t)
77 {
78 return write(fd, t, t->hdr.len + sizeof(struct hmsg_hdr));
79 }
80
81 int
82 ctl_msg_recv(int fd, struct hmsg *t)
83 {
84 int n;
85 if ((n = read(fd, t, MAX_HMSGSIZE)) == -1) {
86 return -1;
87 }
88 if (n < sizeof(struct hmsg_hdr)) {
89 LLOG_WARNX("message received too short");
90 errno = 0;
91 return -1;
92 }
93 if (n != sizeof(struct hmsg_hdr) + t->hdr.len) {
94 LLOG_WARNX("message from %d seems to be truncated (or too large)",
95 t->hdr.pid);
96 errno = 0;
97 return -1;
98 }
99 return 1;
100 }
101
102 void
103 ctl_cleanup(char *name)
104 {
105 if (unlink(name) == -1)
106 LLOG_WARN("unable to unlink %s", name);
107 }
108
109 /* Packing/unpacking */
110
111 /* This structure is used to track memory allocation when unpacking */
112 struct gc {
113 TAILQ_ENTRY(gc) next;
114 void *pointer;
115 };
116 TAILQ_HEAD(gc_l, gc);
117
118 typedef struct { char c; int16_t x; } st_int16;
119 typedef struct { char c; int32_t x; } st_int32;
120 typedef struct { char c; time_t x; } st_timet;
121 typedef struct { char c; void *x; } st_void_p;
122
123 #define INT16_ALIGN (sizeof(st_int16) - sizeof(int16_t))
124 #define INT32_ALIGN (sizeof(st_int32) - sizeof(int32_t))
125 #define TIMET_ALIGN (sizeof(st_timet) - sizeof(time_t))
126 #define VOID_P_ALIGN (sizeof(st_void_p) - sizeof(void *))
127
128 struct formatdef {
129 char format;
130 int size;
131 int alignment;
132 int (*pack)(struct hmsg*, void **, void *,
133 const struct formatdef *);
134 int (*unpack)(struct hmsg*, void **, void *,
135 const struct formatdef *, struct gc_l *);
136 };
137
138 /* void** is a pointer to a pointer to the end of struct hmsg*. It should be
139 * updated. void* is a pointer to the entity to pack */
140
141 static int
142 ctl_alloc_pointer(struct gc_l *pointers, void *pointer)
143 {
144 struct gc *gpointer;
145 if (pointers != NULL) {
146 if ((gpointer = (struct gc *)calloc(1,
147 sizeof(struct gc))) == NULL) {
148 LLOG_WARN("unable to allocate memory for garbage collector");
149 return -1;
150 }
151 gpointer->pointer = pointer;
152 TAILQ_INSERT_TAIL(pointers, gpointer, next);
153 }
154 return 0;
155 }
156
157 static void
158 ctl_free_pointers(struct gc_l *pointers, int listonly)
159 {
160 struct gc *pointer, *pointer_next;
161 for (pointer = TAILQ_FIRST(pointers);
162 pointer != NULL;
163 pointer = pointer_next) {
164 pointer_next = TAILQ_NEXT(pointer, next);
165 TAILQ_REMOVE(pointers, pointer, next);
166 if (!listonly)
167 free(pointer->pointer);
168 free(pointer);
169 }
170 }
171
172 static int
173 pack_copy(struct hmsg *h, void **p, void *s,
174 const struct formatdef *ct)
175 {
176 if (h->hdr.len + ct->size > MAX_HMSGSIZE - sizeof(struct hmsg_hdr)) {
177 LLOG_WARNX("message became too large");
178 return -1;
179 }
180 memcpy(*p, s, ct->size);
181 *p += ct->size;
182 h->hdr.len += ct->size;
183 return ct->size;
184 }
185
186 static int
187 unpack_copy(struct hmsg *h, void **p, void *s,
188 const struct formatdef *ct, struct gc_l *pointers)
189 {
190 memcpy(s, *p, ct->size);
191 *p += ct->size;
192 return ct->size;
193 }
194
195 static int
196 pack_string(struct hmsg *h, void **p, void *s,
197 const struct formatdef *ct)
198 {
199 int len, ss;
200 if ((*(char**)s) == NULL)
201 len = -1;
202 else
203 len = strlen(*(char**)s);
204 if (h->hdr.len + len + sizeof(int) > MAX_HMSGSIZE -
205 sizeof(struct hmsg_hdr)) {
206 LLOG_WARNX("message became too large");
207 return -1;
208 }
209 memcpy(*p, &len, sizeof(int));
210 *p += sizeof(int);
211 ss = sizeof(int);
212 if (len != -1) {
213 memcpy(*p, *(char **)s, len);
214 *p += len;
215 ss += len;
216 }
217 h->hdr.len += ss;
218 return ss;
219 }
220
221 static int
222 unpack_string(struct hmsg *h, void **p, void *s,
223 const struct formatdef *ct, struct gc_l *pointers)
224 {
225 char *string;
226 int len;
227 memcpy(&len, *p, sizeof(int));
228 *p += sizeof(int);
229 if (len == -1) {
230 string = NULL;
231 } else {
232 if ((string = (char *)calloc(1, len + 1)) == NULL) {
233 LLOG_WARNX("unable to allocate new string");
234 return -1;
235 }
236 if (ctl_alloc_pointer(pointers, string) == -1) {
237 free(string);
238 return -1;
239 }
240 memcpy(string, *p, len);
241 *p += len;
242 }
243 memcpy(s, &string, sizeof(char *));
244 return sizeof(char*);
245 }
246
247 static int
248 pack_chars(struct hmsg *h, void **p, void *s,
249 const struct formatdef *ct)
250 {
251 char *string;
252 int string_len;
253 string = *(char **)s;
254 s += sizeof(char *);
255 memcpy(&string_len, s, sizeof(int));
256
257 if (h->hdr.len + string_len + sizeof(int) > MAX_HMSGSIZE -
258 sizeof(struct hmsg_hdr)) {
259 LLOG_WARNX("message became too large");
260 return -1;
261 }
262 memcpy(*p, &string_len, sizeof(int));
263 *p += sizeof(int);
264 memcpy(*p, string, string_len);
265 *p += string_len;
266 h->hdr.len += sizeof(int) + string_len;
267 return sizeof(int) + string_len;
268 }
269
270 static int
271 unpack_chars(struct hmsg *h, void **p, void *s,
272 const struct formatdef *ct, struct gc_l *pointers)
273 {
274 char *string;
275 struct __attribute__ ((__packed__)) {
276 char *string;
277 int len;
278 } reals;
279 int len;
280 memcpy(&len, *p, sizeof(int));
281 *p += sizeof(int);
282 if ((string = (char *)malloc(len)) == NULL) {
283 LLOG_WARN("unable to allocate new string");
284 return -1;
285 }
286 if (ctl_alloc_pointer(pointers, string) == -1) {
287 free(string);
288 return -1;
289 }
290 memcpy(string, *p, len);
291 *p += len;
292 reals.string = string;
293 reals.len = len;
294 memcpy(s, &reals, sizeof(reals));
295 return sizeof(char*);
296 }
297
298 static int
299 pack_zero(struct hmsg *h, void **p, void *s,
300 const struct formatdef *ct)
301 {
302 if (h->hdr.len + ct->size > MAX_HMSGSIZE - sizeof(struct hmsg_hdr)) {
303 LLOG_WARNX("message became too large");
304 return -1;
305 }
306 memset(*p, 0, ct->size);
307 *p += ct->size;
308 h->hdr.len += ct->size;
309 return ct->size;
310 }
311
312 static struct formatdef conv_table[] = {
313 {'b', 1, 0,
314 pack_copy, unpack_copy},
315 {'w', 2, INT16_ALIGN,
316 pack_copy, unpack_copy},
317 {'l', 4, INT32_ALIGN,
318 pack_copy, unpack_copy},
319 {'t', sizeof(time_t), TIMET_ALIGN,
320 pack_copy, unpack_copy},
321 /* Null terminated string */
322 {'s', sizeof(void*), VOID_P_ALIGN,
323 pack_string, unpack_string},
324 /* Pointer (is packed with 0) */
325 {'P', sizeof(void*), VOID_P_ALIGN,
326 pack_zero, unpack_copy},
327 /* A list (same as pointer), should be at the beginning */
328 {'L', sizeof(void*)*2, VOID_P_ALIGN,
329 pack_zero, unpack_copy},
330 /* Non null terminated string, followed by an int for the size */
331 {'C', sizeof(void*) + sizeof(int), VOID_P_ALIGN,
332 pack_chars, unpack_chars},
333 {0, 0, 0, NULL, NULL}
334 };
335
336 /* Lists can be packed only if the "next" member is the first one of the
337 * structure! No check is done for this. */
338 struct fakelist_m {
339 TAILQ_ENTRY(fakelist_m) next;
340 void *data;
341 };
342 TAILQ_HEAD(fakelist_l, fakelist_m);
343
344 static int ctl_msg_get_alignment(char *format)
345 {
346 char *f;
347 int maxalign = 0, align;
348 int paren = 0;
349 struct formatdef *ce;
350
351 /* We just want to get the maximum required alignment for the
352 * structure. Instead of going recursive, we just count parentheses to
353 * get the end of the structure. */
354 for (f = format; *f != 0; f++) {
355 if (*f == ')') {
356 paren--;
357 if (!paren)
358 return maxalign;
359 continue;
360 } else if (*f == '(') {
361 paren++;
362 continue;
363 } else {
364 for (ce = conv_table;
365 (ce->format != 0) && (ce->format != *f);
366 ce++);
367 align = ce->alignment;
368 }
369 if (align != 0)
370 maxalign = (maxalign>align)?maxalign:align;
371 }
372 if (paren)
373 LLOG_WARNX("unbalanced parenthesis in format '%s'",
374 format);
375 return maxalign;
376 }
377
378 /* Define a stack of align values */
379 struct stack_align {
380 SLIST_ENTRY(stack_align) next;
381 int align;
382 };
383
384 static int
385 ctl_msg_packunpack_structure(char *format, void *structure, unsigned int size,
386 struct hmsg *h, void **p, struct gc_l *pointers, int pack)
387 {
388 char *f;
389 struct formatdef *ce = NULL;
390 unsigned int csize = 0;
391 uintptr_t offset;
392 struct stack_align *align, *align_next;
393 int talign;
394 SLIST_HEAD(, stack_align) aligns;
395
396 SLIST_INIT(&aligns);
397 for (f = format; *f != 0; f++) {
398 /* If we have a substructure, when entering into the structure,
399 * we get the alignment and push it to the stack. When exiting
400 * the structure, we pop the alignment from the stack and we do
401 * the padding. This means that the whole structure should be
402 * enclosed into parentheses, otherwise the padding won't
403 * occur. */
404 ce = NULL;
405 if (*f == '(') {
406 /* We need to align, compute the needed alignment */
407 if ((align = calloc(1,
408 sizeof(struct stack_align))) == NULL) {
409 LLOG_WARN("unable to allocate memory "
410 "for alignment stack");
411 goto packunpack_error;
412 }
413 talign = align->align = ctl_msg_get_alignment(f);
414 SLIST_INSERT_HEAD(&aligns, align, next);
415 } else if (*f == ')') {
416 /* We need to pad, retrieve the needed alignment */
417 align = SLIST_FIRST(&aligns);
418 talign = align->align;
419 align_next = SLIST_NEXT(align, next);
420 SLIST_REMOVE_HEAD(&aligns, next);
421 free(align);
422 } else {
423 for (ce = conv_table;
424 (ce->format != 0) && (ce->format != *f);
425 ce++);
426 if (ce->format != *f) {
427 LLOG_WARNX("unknown format char %c", *f);
428 goto packunpack_error;
429 }
430 talign = ce->alignment;
431 }
432
433 /* Align the structure member */
434 if (talign != 0) {
435 offset = (uintptr_t)structure % talign;
436 if (offset != 0) {
437 structure += talign - offset;
438 csize += talign - offset;
439 }
440 }
441
442 if (!ce) continue;
443
444 /* Check that the size is still ok */
445 csize += ce->size;
446 if (csize > size) {
447 LLOG_WARNX("size of structure is too small for given "
448 "format (%d vs %d)", size, csize);
449 goto packunpack_error;
450 }
451
452 /* Pack or unpack */
453 if (pack) {
454 if (ce->pack(h, p, structure, ce) == -1) {
455 LLOG_WARNX("error while packing %c in %s", *f,
456 format);
457 goto packunpack_error;
458 }
459 } else {
460 if (ce->unpack(h, p, structure, ce, pointers) == -1) {
461 LLOG_WARNX("error while unpacking %c", *f);
462 goto packunpack_error;
463 }
464 }
465 structure += ce->size;
466 }
467
468 if (size < csize) {
469 LLOG_WARNX("size of structure does not match its "
470 "declaration (%d vs %d)", size, csize);
471 goto packunpack_error;
472 }
473 if (!SLIST_EMPTY(&aligns)) {
474 LLOG_WARNX("format is badly balanced ('%s')", format);
475 goto packunpack_error;
476 }
477 return 0;
478
479 packunpack_error:
480 for (align = SLIST_FIRST(&aligns);
481 align != NULL;
482 align = align_next) {
483 align_next = SLIST_NEXT(align, next);
484 SLIST_REMOVE_HEAD(&aligns, next);
485 free(align);
486 }
487 return -1;
488
489 }
490
491 int
492 ctl_msg_pack_structure(char *format, void *structure, unsigned int size,
493 struct hmsg *h, void **p)
494 {
495 return ctl_msg_packunpack_structure(format, structure, size, h, p, NULL, 1);
496 }
497
498 int
499 ctl_msg_unpack_structure(char *format, void *structure, unsigned int size,
500 struct hmsg *h, void **p)
501 {
502 struct gc_l pointers;
503 int rc;
504 TAILQ_INIT(&pointers);
505 if ((rc = ctl_msg_packunpack_structure(format, structure, size,
506 h, p, &pointers, 0)) == -1) {
507 LLOG_WARNX("unable to unpack structure, freeing");
508 ctl_free_pointers(&pointers, 0);
509 return -1;
510 }
511 ctl_free_pointers(&pointers, 1);
512 return rc;
513 }
514
515 int
516 ctl_msg_pack_list(char *format, void *list, unsigned int size, struct hmsg *h, void **p)
517 {
518 struct fakelist_m *member;
519 struct fakelist_l *flist = (struct fakelist_l *)list;
520 TAILQ_FOREACH(member, flist, next) {
521 if (ctl_msg_pack_structure(format, member, size, h, p) == -1) {
522 LLOG_WARNX("error while packing list, aborting");
523 return -1;
524 }
525 }
526 return 0;
527 }
528
529 int
530 ctl_msg_unpack_list(char *format, void *list, unsigned int size, struct hmsg *h, void **p)
531 {
532 struct fakelist_m *member, *member_next;
533 struct gc_l pointers;
534 struct fakelist_l *flist = (struct fakelist_l *)list;
535 TAILQ_INIT(flist);
536 TAILQ_INIT(&pointers);
537 while (*p - (void *)h - sizeof(struct hmsg_hdr) < h->hdr.len) {
538 if ((member = calloc(1, size)) == NULL) {
539 LLOG_WARN("unable to allocate memory for structure");
540 return -1;
541 }
542 if (ctl_msg_packunpack_structure(format, member, size,
543 h, p, &pointers, 0) == -1) {
544 LLOG_WARNX("unable to unpack list, aborting");
545 free(member);
546 /* Free each list member */
547 for (member = TAILQ_FIRST(flist);
548 member != NULL;
549 member = member_next) {
550 member_next = TAILQ_NEXT(member, next);
551 TAILQ_REMOVE(flist, member, next);
552 free(member);
553 }
554 ctl_free_pointers(&pointers, 0);
555 return -1;
556 }
557 TAILQ_INSERT_TAIL(flist, member, next);
558 }
559 ctl_free_pointers(&pointers, 1);
560 return 0;
561 }