]>
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_msg_init(struct hmsg
*t
, enum hmsg_type type
)
69 memset(t
, 0, MAX_HMSGSIZE
);
72 t
->hdr
.pid
= getpid();
76 ctl_msg_send(int fd
, struct hmsg
*t
)
78 return write(fd
, t
, t
->hdr
.len
+ sizeof(struct hmsg_hdr
));
82 ctl_msg_recv(int fd
, struct hmsg
*t
)
85 if ((n
= read(fd
, t
, MAX_HMSGSIZE
)) == -1) {
88 if (n
< sizeof(struct hmsg_hdr
)) {
89 LLOG_WARNX("message received too short");
93 if (n
!= sizeof(struct hmsg_hdr
) + t
->hdr
.len
) {
94 LLOG_WARNX("message from %d seems to be truncated (or too large)",
103 ctl_cleanup(char *name
)
105 if (unlink(name
) == -1)
106 LLOG_WARN("unable to unlink %s", name
);
109 /* Packing/unpacking */
111 /* This structure is used to track memory allocation when unpacking */
113 TAILQ_ENTRY(gc
) next
;
116 TAILQ_HEAD(gc_l
, gc
);
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
;
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 *))
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
*);
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 */
142 ctl_alloc_pointer(struct gc_l
*pointers
, void *pointer
)
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");
151 gpointer
->pointer
= pointer
;
152 TAILQ_INSERT_TAIL(pointers
, gpointer
, next
);
158 ctl_free_pointers(struct gc_l
*pointers
, int listonly
)
160 struct gc
*pointer
, *pointer_next
;
161 for (pointer
= TAILQ_FIRST(pointers
);
163 pointer
= pointer_next
) {
164 pointer_next
= TAILQ_NEXT(pointer
, next
);
165 TAILQ_REMOVE(pointers
, pointer
, next
);
167 free(pointer
->pointer
);
173 pack_copy(struct hmsg
*h
, void **p
, void *s
,
174 const struct formatdef
*ct
)
176 if (h
->hdr
.len
+ ct
->size
> MAX_HMSGSIZE
- sizeof(struct hmsg_hdr
)) {
177 LLOG_WARNX("message became too large");
180 memcpy(*p
, s
, ct
->size
);
182 h
->hdr
.len
+= ct
->size
;
187 unpack_copy(struct hmsg
*h
, void **p
, void *s
,
188 const struct formatdef
*ct
, struct gc_l
*pointers
)
190 memcpy(s
, *p
, ct
->size
);
196 pack_string(struct hmsg
*h
, void **p
, void *s
,
197 const struct formatdef
*ct
)
200 if ((*(char**)s
) == NULL
)
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");
209 memcpy(*p
, &len
, sizeof(int));
213 memcpy(*p
, *(char **)s
, len
);
222 unpack_string(struct hmsg
*h
, void **p
, void *s
,
223 const struct formatdef
*ct
, struct gc_l
*pointers
)
227 memcpy(&len
, *p
, sizeof(int));
232 if ((string
= (char *)calloc(1, len
+ 1)) == NULL
) {
233 LLOG_WARNX("unable to allocate new string");
236 if (ctl_alloc_pointer(pointers
, string
) == -1) {
240 memcpy(string
, *p
, len
);
243 memcpy(s
, &string
, sizeof(char *));
244 return sizeof(char*);
248 pack_chars(struct hmsg
*h
, void **p
, void *s
,
249 const struct formatdef
*ct
)
253 string
= *(char **)s
;
255 memcpy(&string_len
, s
, sizeof(int));
257 if (h
->hdr
.len
+ string_len
+ sizeof(int) > MAX_HMSGSIZE
-
258 sizeof(struct hmsg_hdr
)) {
259 LLOG_WARNX("message became too large");
262 memcpy(*p
, &string_len
, sizeof(int));
264 memcpy(*p
, string
, string_len
);
266 h
->hdr
.len
+= sizeof(int) + string_len
;
267 return sizeof(int) + string_len
;
271 unpack_chars(struct hmsg
*h
, void **p
, void *s
,
272 const struct formatdef
*ct
, struct gc_l
*pointers
)
275 struct __attribute__ ((__packed__
)) {
280 memcpy(&len
, *p
, sizeof(int));
282 if ((string
= (char *)malloc(len
)) == NULL
) {
283 LLOG_WARN("unable to allocate new string");
286 if (ctl_alloc_pointer(pointers
, string
) == -1) {
290 memcpy(string
, *p
, len
);
292 reals
.string
= string
;
294 memcpy(s
, &reals
, sizeof(reals
));
295 return sizeof(char*);
299 pack_zero(struct hmsg
*h
, void **p
, void *s
,
300 const struct formatdef
*ct
)
302 if (h
->hdr
.len
+ ct
->size
> MAX_HMSGSIZE
- sizeof(struct hmsg_hdr
)) {
303 LLOG_WARNX("message became too large");
306 memset(*p
, 0, ct
->size
);
308 h
->hdr
.len
+= ct
->size
;
312 static struct formatdef conv_table
[] = {
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
}
336 /* Lists can be packed only if the "next" member is the first one of the
337 * structure! No check is done for this. */
339 TAILQ_ENTRY(fakelist_m
) next
;
342 TAILQ_HEAD(fakelist_l
, fakelist_m
);
344 static int ctl_msg_get_alignment(char *format
)
347 int maxalign
= 0, align
;
349 struct formatdef
*ce
;
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
++) {
360 } else if (*f
== '(') {
364 for (ce
= conv_table
;
365 (ce
->format
!= 0) && (ce
->format
!= *f
);
367 align
= ce
->alignment
;
370 maxalign
= (maxalign
>align
)?maxalign
:align
;
373 LLOG_WARNX("unbalanced parenthesis in format '%s'",
378 /* Define a stack of align values */
380 SLIST_ENTRY(stack_align
) next
;
385 ctl_msg_packunpack_structure(char *format
, void *structure
, unsigned int size
,
386 struct hmsg
*h
, void **p
, struct gc_l
*pointers
, int pack
)
389 struct formatdef
*ce
= NULL
;
390 unsigned int csize
= 0;
392 struct stack_align
*align
, *align_next
;
394 SLIST_HEAD(, stack_align
) 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
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
;
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
);
423 for (ce
= conv_table
;
424 (ce
->format
!= 0) && (ce
->format
!= *f
);
426 if (ce
->format
!= *f
) {
427 LLOG_WARNX("unknown format char %c", *f
);
428 goto packunpack_error
;
430 talign
= ce
->alignment
;
433 /* Align the structure member */
435 offset
= (uintptr_t)structure
% talign
;
437 structure
+= talign
- offset
;
438 csize
+= talign
- offset
;
444 /* Check that the size is still ok */
447 LLOG_WARNX("size of structure is too small for given "
448 "format (%d vs %d)", size
, csize
);
449 goto packunpack_error
;
454 if (ce
->pack(h
, p
, structure
, ce
) == -1) {
455 LLOG_WARNX("error while packing %c in %s", *f
,
457 goto packunpack_error
;
460 if (ce
->unpack(h
, p
, structure
, ce
, pointers
) == -1) {
461 LLOG_WARNX("error while unpacking %c", *f
);
462 goto packunpack_error
;
465 structure
+= ce
->size
;
469 LLOG_WARNX("size of structure does not match its "
470 "declaration (%d vs %d)", size
, csize
);
471 goto packunpack_error
;
473 if (!SLIST_EMPTY(&aligns
)) {
474 LLOG_WARNX("format is badly balanced ('%s')", format
);
475 goto packunpack_error
;
480 for (align
= SLIST_FIRST(&aligns
);
482 align
= align_next
) {
483 align_next
= SLIST_NEXT(align
, next
);
484 SLIST_REMOVE_HEAD(&aligns
, next
);
492 ctl_msg_pack_structure(char *format
, void *structure
, unsigned int size
,
493 struct hmsg
*h
, void **p
)
495 return ctl_msg_packunpack_structure(format
, structure
, size
, h
, p
, NULL
, 1);
499 ctl_msg_unpack_structure(char *format
, void *structure
, unsigned int size
,
500 struct hmsg
*h
, void **p
)
502 struct gc_l pointers
;
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);
511 ctl_free_pointers(&pointers
, 1);
516 ctl_msg_pack_list(char *format
, void *list
, unsigned int size
, struct hmsg
*h
, void **p
)
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");
530 ctl_msg_unpack_list(char *format
, void *list
, unsigned int size
, struct hmsg
*h
, void **p
)
532 struct fakelist_m
*member
, *member_next
;
533 struct gc_l pointers
;
534 struct fakelist_l
*flist
= (struct fakelist_l
*)list
;
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");
542 if (ctl_msg_packunpack_structure(format
, member
, size
,
543 h
, p
, &pointers
, 0) == -1) {
544 LLOG_WARNX("unable to unpack list, aborting");
546 /* Free each list member */
547 for (member
= TAILQ_FIRST(flist
);
549 member
= member_next
) {
550 member_next
= TAILQ_NEXT(member
, next
);
551 TAILQ_REMOVE(flist
, member
, next
);
554 ctl_free_pointers(&pointers
, 0);
557 TAILQ_INSERT_TAIL(flist
, member
, next
);
559 ctl_free_pointers(&pointers
, 1);