]>
git.ipfire.org Git - thirdparty/lldpd.git/blob - src/ctl.c
2 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
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.
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.
21 #include <sys/types.h>
22 #include <sys/socket.h>
26 ctl_create(char *name
)
29 struct sockaddr_un su
;
32 if ((s
= socket(PF_UNIX
, SOCK_STREAM
, 0)) == -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
;
40 if (listen(s
, 5) == -1) {
41 rc
= errno
; close(s
); errno
= rc
;
48 ctl_connect(char *name
)
51 struct sockaddr_un su
;
54 if ((s
= socket(PF_UNIX
, SOCK_STREAM
, 0)) == -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) {
60 LLOG_WARN("unable to connect to socket " LLDPD_CTL_SOCKET
);
61 errno
= rc
; return -1;
67 ctl_accept(struct lldpd
*cfg
, int c
)
70 struct lldpd_client
*lc
;
71 if ((s
= accept(c
, NULL
, NULL
)) == -1) {
72 LLOG_WARN("unable to accept connection from socket");
75 if ((lc
= (struct lldpd_client
*)malloc(sizeof(
76 struct lldpd_client
))) == NULL
) {
77 LLOG_WARN("failed to allocate memory for new client");
82 TAILQ_INSERT_TAIL(&cfg
->g_clients
, lc
, next
);
87 ctl_msg_init(struct hmsg
*t
, enum hmsg_type type
)
89 memset(t
, 0, MAX_HMSGSIZE
);
92 t
->hdr
.pid
= getpid();
96 ctl_msg_send(int fd
, struct hmsg
*t
)
98 return write(fd
, t
, t
->hdr
.len
+ sizeof(struct hmsg_hdr
));
102 ctl_msg_recv(int fd
, struct hmsg
*t
)
105 if ((n
= read(fd
, t
, MAX_HMSGSIZE
)) == -1) {
108 if (n
< sizeof(struct hmsg_hdr
)) {
109 LLOG_WARNX("message received too short");
113 if (n
!= sizeof(struct hmsg_hdr
) + t
->hdr
.len
) {
114 LLOG_WARNX("message from %d seems to be truncated (or too large)",
123 ctl_close(struct lldpd
*cfg
, int c
)
125 struct lldpd_client
*client
, *client_next
;
126 for (client
= TAILQ_FIRST(&cfg
->g_clients
);
128 client
= client_next
) {
129 client_next
= TAILQ_NEXT(client
, next
);
130 if (client
->fd
== c
) {
132 TAILQ_REMOVE(&cfg
->g_clients
, client
, next
);
142 ctl_cleanup(char *name
)
144 if (unlink(name
) == -1)
145 LLOG_WARN("unable to unlink %s", name
);
148 /* Packing/unpacking */
150 /* This structure is used to track memory allocation when unpacking */
152 TAILQ_ENTRY(gc
) next
;
155 TAILQ_HEAD(gc_l
, gc
);
157 typedef struct { char c
; int16_t x
; } st_int16
;
158 typedef struct { char c
; int32_t x
; } st_int32
;
159 typedef struct { char c
; void *x
; } st_void_p
;
161 #define INT16_ALIGN (sizeof(st_int16) - sizeof(int16_t))
162 #define INT32_ALIGN (sizeof(st_int32) - sizeof(int32_t))
163 #define VOID_P_ALIGN (sizeof(st_void_p) - sizeof(void *))
169 int (*pack
)(struct hmsg
*, void **, void *,
170 const struct formatdef
*);
171 int (*unpack
)(struct hmsg
*, void **, void *,
172 const struct formatdef
*, struct gc_l
*);
175 /* void** is a pointer to a pointer to the end of struct hmsg*. It should be
176 * updated. void* is a pointer to the entity to pack */
179 ctl_alloc_pointer(struct gc_l
*pointers
, void *pointer
)
182 if (pointers
!= NULL
) {
183 if ((gpointer
= (struct gc
*)calloc(1,
184 sizeof(struct gc
))) == NULL
) {
185 LLOG_WARN("unable to allocate memory for garbage collector");
188 gpointer
->pointer
= pointer
;
189 TAILQ_INSERT_TAIL(pointers
, gpointer
, next
);
195 ctl_free_pointers(struct gc_l
*pointers
, int listonly
)
197 struct gc
*pointer
, *pointer_next
;
198 for (pointer
= TAILQ_FIRST(pointers
);
200 pointer
= pointer_next
) {
201 pointer_next
= TAILQ_NEXT(pointer
, next
);
202 TAILQ_REMOVE(pointers
, pointer
, next
);
204 free(pointer
->pointer
);
210 pack_copy(struct hmsg
*h
, void **p
, void *s
,
211 const struct formatdef
*ct
)
213 if (h
->hdr
.len
+ ct
->size
> MAX_HMSGSIZE
- sizeof(struct hmsg_hdr
)) {
214 LLOG_WARNX("message became too large");
217 memcpy(*p
, s
, ct
->size
);
219 h
->hdr
.len
+= ct
->size
;
224 unpack_copy(struct hmsg
*h
, void **p
, void *s
,
225 const struct formatdef
*ct
, struct gc_l
*pointers
)
227 memcpy(s
, *p
, ct
->size
);
233 pack_string(struct hmsg
*h
, void **p
, void *s
,
234 const struct formatdef
*ct
)
237 if ((*(char**)s
) == NULL
)
240 len
= strlen(*(char**)s
);
241 if (h
->hdr
.len
+ len
+ sizeof(int) > MAX_HMSGSIZE
-
242 sizeof(struct hmsg_hdr
)) {
243 LLOG_WARNX("message became too large");
246 memcpy(*p
, &len
, sizeof(int));
250 memcpy(*p
, *(char **)s
, len
);
259 unpack_string(struct hmsg
*h
, void **p
, void *s
,
260 const struct formatdef
*ct
, struct gc_l
*pointers
)
264 memcpy(&len
, *p
, sizeof(int));
269 if ((string
= (char *)calloc(1, len
+ 1)) == NULL
) {
270 LLOG_WARNX("unable to allocate new string");
273 if (ctl_alloc_pointer(pointers
, string
) == -1) {
277 memcpy(string
, *p
, len
);
280 memcpy(s
, &string
, sizeof(char *));
281 return sizeof(char*);
285 pack_chars(struct hmsg
*h
, void **p
, void *s
,
286 const struct formatdef
*ct
)
290 string
= *(char **)s
;
292 memcpy(&string_len
, s
, sizeof(int));
294 if (h
->hdr
.len
+ string_len
+ sizeof(int) > MAX_HMSGSIZE
-
295 sizeof(struct hmsg_hdr
)) {
296 LLOG_WARNX("message became too large");
299 memcpy(*p
, &string_len
, sizeof(int));
301 memcpy(*p
, string
, string_len
);
303 h
->hdr
.len
+= sizeof(int) + string_len
;
304 return sizeof(int) + string_len
;
308 unpack_chars(struct hmsg
*h
, void **p
, void *s
,
309 const struct formatdef
*ct
, struct gc_l
*pointers
)
315 } reals
__attribute__ ((__packed__
));
317 memcpy(&len
, *p
, sizeof(int));
319 if ((string
= (char *)malloc(len
)) == NULL
) {
320 LLOG_WARN("unable to allocate new string");
323 if (ctl_alloc_pointer(pointers
, string
) == -1) {
327 memcpy(string
, *p
, len
);
329 reals
.string
= string
;
331 memcpy(s
, &reals
, sizeof(reals
));
332 return sizeof(char*);
336 pack_zero(struct hmsg
*h
, void **p
, void *s
,
337 const struct formatdef
*ct
)
339 if (h
->hdr
.len
+ ct
->size
> MAX_HMSGSIZE
- sizeof(struct hmsg_hdr
)) {
340 LLOG_WARNX("message became too large");
343 memset(*p
, 0, ct
->size
);
345 h
->hdr
.len
+= ct
->size
;
349 static struct formatdef conv_table
[] = {
351 pack_copy
, unpack_copy
},
352 {'w', 2, INT16_ALIGN
,
353 pack_copy
, unpack_copy
},
354 {'l', 4, INT32_ALIGN
,
355 pack_copy
, unpack_copy
},
356 /* Null terminated string */
357 {'s', sizeof(void*), VOID_P_ALIGN
,
358 pack_string
, unpack_string
},
359 /* Pointer (is packed with 0) */
360 {'P', sizeof(void*), VOID_P_ALIGN
,
361 pack_zero
, unpack_copy
},
362 /* A list (same as pointer), should be at the beginning */
363 {'L', sizeof(void*)*2, VOID_P_ALIGN
,
364 pack_zero
, unpack_copy
},
365 /* Non null terminated string, followed by an int for the size */
366 {'C', sizeof(void*) + sizeof(int), VOID_P_ALIGN
,
367 pack_chars
, unpack_chars
},
371 /* Lists can be packed only if the "next" member is the first one of the
372 * structure! No check is done for this. */
374 TAILQ_ENTRY(fakelist_m
) next
;
377 TAILQ_HEAD(fakelist_l
, fakelist_m
);
379 static int ctl_msg_get_alignment(char *format
)
382 int maxalign
= 0, align
;
384 struct formatdef
*ce
;
386 /* We just want to get the maximum required alignment for the
387 * structure. Instead of going recursive, we just count parentheses to
388 * get the end of the structure. */
389 for (f
= format
; *f
!= 0; f
++) {
395 } else if (*f
== '(') {
399 for (ce
= conv_table
;
400 (ce
->format
!= 0) && (ce
->format
!= *f
);
402 align
= ce
->alignment
;
405 maxalign
= (maxalign
>align
)?maxalign
:align
;
408 LLOG_WARNX("unbalanced parenthesis in format '%s'",
413 /* Define a stack of align values */
415 SLIST_ENTRY(stack_align
) next
;
420 ctl_msg_packunpack_structure(char *format
, void *structure
, unsigned int size
,
421 struct hmsg
*h
, void **p
, struct gc_l
*pointers
, int pack
)
424 struct formatdef
*ce
= NULL
;
425 unsigned int csize
= 0;
427 struct stack_align
*align
, *align_next
;
429 SLIST_HEAD(, stack_align
) aligns
;
432 for (f
= format
; *f
!= 0; f
++) {
433 /* If we have a substructure, when entering into the structure,
434 * we get the alignment and push it to the stack. When exiting
435 * the structure, we pop the alignment from the stack and we do
436 * the padding. This means that the whole structure should be
437 * enclosed into parentheses, otherwise the padding won't
441 /* We need to align, compute the needed alignment */
442 if ((align
= calloc(1,
443 sizeof(struct stack_align
))) == NULL
) {
444 LLOG_WARN("unable to allocate memory "
445 "for alignment stack");
446 goto packunpack_error
;
448 talign
= align
->align
= ctl_msg_get_alignment(f
);
449 SLIST_INSERT_HEAD(&aligns
, align
, next
);
450 } else if (*f
== ')') {
451 /* We need to pad, retrieve the needed alignment */
452 align
= SLIST_FIRST(&aligns
);
453 talign
= align
->align
;
454 align_next
= SLIST_NEXT(align
, next
);
455 SLIST_REMOVE_HEAD(&aligns
, next
);
458 for (ce
= conv_table
;
459 (ce
->format
!= 0) && (ce
->format
!= *f
);
461 if (ce
->format
!= *f
) {
462 LLOG_WARNX("unknown format char %c", *f
);
463 goto packunpack_error
;
465 talign
= ce
->alignment
;
468 /* Align the structure member */
470 offset
= (uintptr_t)structure
% talign
;
472 structure
+= talign
- offset
;
473 csize
+= talign
- offset
;
479 /* Check that the size is still ok */
482 LLOG_WARNX("size of structure is too small for given "
483 "format (%d vs %d)", size
, csize
);
484 goto packunpack_error
;
489 if (ce
->pack(h
, p
, structure
, ce
) == -1) {
490 LLOG_WARNX("error while packing %c in %s", *f
,
492 goto packunpack_error
;
495 if (ce
->unpack(h
, p
, structure
, ce
, pointers
) == -1) {
496 LLOG_WARNX("error while unpacking %c", *f
);
497 goto packunpack_error
;
500 structure
+= ce
->size
;
504 LLOG_WARNX("size of structure does not match its "
505 "declaration (%d vs %d)", size
, csize
);
506 goto packunpack_error
;
508 if (!SLIST_EMPTY(&aligns
)) {
509 LLOG_WARNX("format is badly balanced ('%s')", format
);
510 goto packunpack_error
;
515 for (align
= SLIST_FIRST(&aligns
);
517 align
= align_next
) {
518 align_next
= SLIST_NEXT(align
, next
);
519 SLIST_REMOVE_HEAD(&aligns
, next
);
527 ctl_msg_pack_structure(char *format
, void *structure
, unsigned int size
,
528 struct hmsg
*h
, void **p
)
530 return ctl_msg_packunpack_structure(format
, structure
, size
, h
, p
, NULL
, 1);
534 ctl_msg_unpack_structure(char *format
, void *structure
, unsigned int size
,
535 struct hmsg
*h
, void **p
)
537 struct gc_l pointers
;
539 TAILQ_INIT(&pointers
);
540 if ((rc
= ctl_msg_packunpack_structure(format
, structure
, size
,
541 h
, p
, &pointers
, 0)) == -1) {
542 LLOG_WARNX("unable to unpack structure, freeing");
543 ctl_free_pointers(&pointers
, 0);
546 ctl_free_pointers(&pointers
, 1);
551 ctl_msg_pack_list(char *format
, void *list
, unsigned int size
, struct hmsg
*h
, void **p
)
553 struct fakelist_m
*member
;
554 struct fakelist_l
*flist
= (struct fakelist_l
*)list
;
555 TAILQ_FOREACH(member
, flist
, next
) {
556 if (ctl_msg_pack_structure(format
, member
, size
, h
, p
) == -1) {
557 LLOG_WARNX("error while packing list, aborting");
565 ctl_msg_unpack_list(char *format
, void *list
, unsigned int size
, struct hmsg
*h
, void **p
)
567 struct fakelist_m
*member
, *member_next
;
568 struct gc_l pointers
;
569 struct fakelist_l
*flist
= (struct fakelist_l
*)list
;
571 TAILQ_INIT(&pointers
);
572 while (*p
- (void *)h
- sizeof(struct hmsg_hdr
) < h
->hdr
.len
) {
573 if ((member
= calloc(1, size
)) == NULL
) {
574 LLOG_WARN("unable to allocate memory for structure");
577 if (ctl_msg_packunpack_structure(format
, member
, size
,
578 h
, p
, &pointers
, 0) == -1) {
579 LLOG_WARNX("unable to unpack list, aborting");
581 /* Free each list member */
582 for (member
= TAILQ_FIRST(flist
);
584 member
= member_next
) {
585 member_next
= TAILQ_NEXT(member
, next
);
586 TAILQ_REMOVE(flist
, member
, next
);
589 ctl_free_pointers(&pointers
, 0);
592 TAILQ_INSERT_TAIL(flist
, member
, next
);
594 ctl_free_pointers(&pointers
, 1);