]>
git.ipfire.org Git - thirdparty/lldpd.git/blob - src/ctl.c
1 /* -*- mode: c; c-file-style: "openbsd" -*- */
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 #include <sys/types.h>
23 #include <sys/socket.h>
29 #include "compat/compat.h"
31 #define UNIX_PATH_MAX 108
34 * Create a new listening Unix socket for control protocol.
36 * @param name The name of the Unix socket.
37 * @return The socket when successful, -1 otherwise.
40 ctl_create(char *name
)
43 struct sockaddr_un su
;
46 if ((s
= socket(PF_UNIX
, SOCK_STREAM
, 0)) == -1)
48 su
.sun_family
= AF_UNIX
;
49 strlcpy(su
.sun_path
, name
, UNIX_PATH_MAX
);
50 if (bind(s
, (struct sockaddr
*)&su
, sizeof(struct sockaddr_un
)) == -1) {
51 rc
= errno
; close(s
); errno
= rc
;
54 if (listen(s
, 5) == -1) {
55 rc
= errno
; close(s
); errno
= rc
;
62 * Connect to the control Unix socket.
64 * @param name The name of the Unix socket.
65 * @return The socket when successful, -1 otherwise.
68 ctl_connect(char *name
)
71 struct sockaddr_un su
;
74 if ((s
= socket(PF_UNIX
, SOCK_STREAM
, 0)) == -1)
76 su
.sun_family
= AF_UNIX
;
77 strlcpy(su
.sun_path
, name
, UNIX_PATH_MAX
);
78 if (connect(s
, (struct sockaddr
*)&su
, sizeof(struct sockaddr_un
)) == -1) {
80 LLOG_WARN("unable to connect to socket %s", name
);
81 errno
= rc
; return -1;
87 * Remove the control Unix socket.
89 * @param name The name of the Unix socket.
92 ctl_cleanup(char *name
)
94 if (unlink(name
) == -1)
95 LLOG_WARN("unable to unlink %s", name
);
99 * Serialize and "send" a structure through the control protocol.
101 * This function does not really send the message but outputs it to a buffer.
103 * @param output_buffer A pointer to a buffer to which the message will be
104 * appended. Can be @c NULL. In this case, the buffer will
106 * @param[in,out] output_len The length of the provided buffer. Will be updated
107 * with the new length
108 * @param type The type of message we want to send.
109 * @param t The structure to be serialized and sent.
110 * @param mi The appropriate marshal structure for serialization.
111 * @return -1 in case of failure, 0 in case of success.
113 * Make sure this function logic matches the server-side one: @c levent_ctl_recv().
116 ctl_msg_send_unserialized(uint8_t **output_buffer
, size_t *output_len
,
118 void *t
, struct marshal_info
*mi
)
120 struct hmsg_header hdr
;
121 size_t len
= 0, newlen
;
125 len
= marshal_serialize_(mi
, t
, &buffer
, 0, NULL
, 0);
127 LLOG_WARNX("unable to serialize data");
132 newlen
= len
+ sizeof(struct hmsg_header
);
134 if (*output_buffer
== NULL
) {
136 if ((*output_buffer
= malloc(newlen
)) == NULL
) {
137 LLOG_WARN("no memory available");
142 void *new = realloc(*output_buffer
, *output_len
+ newlen
);
144 LLOG_WARN("no memory available");
148 *output_buffer
= new;
150 memset(&hdr
, 0, sizeof(struct hmsg_header
));
153 memcpy(*output_buffer
+ *output_len
, &hdr
, sizeof(struct hmsg_header
));
155 memcpy(*output_buffer
+ *output_len
+ sizeof(struct hmsg_header
), buffer
, len
);
156 *output_len
+= newlen
;
162 * "Receive" and unserialize a structure through the control protocol.
164 * Like @c ctl_msg_send_unserialized(), this function uses buffer to receive the
167 * @param[in,out] input_buffer The buffer with the incoming message. Will be
168 * updated once the message has been unserialized to
169 * point to the remaining of the message or will be
170 * freed if all the buffer has been consumed. Can be
172 * @param[in,out] input_len The length of the provided buffer. Will be updated
173 * to the length of remaining data once the message
174 * has been unserialized.
175 * @param expected_type The expected message type.
176 * @param[out] t Will contain a pointer to the unserialized structure.
177 * Can be @c NULL if we don't want to store the
179 * @param mi The appropriate marshal structure for unserialization.
181 * @return -1 in case of error, 0 in case of success and the number of bytes we
182 * request to complete unserialization.
184 * When requesting a notification, the input buffer is left untouched if we
185 * don't get one and we fail silently.
188 ctl_msg_recv_unserialized(uint8_t **input_buffer
, size_t *input_len
,
189 enum hmsg_type expected_type
,
190 void **t
, struct marshal_info
*mi
)
192 struct hmsg_header
*hdr
;
195 if (*input_buffer
== NULL
||
196 *input_len
< sizeof(struct hmsg_header
)) {
197 /* Not enough data. */
198 return sizeof(struct hmsg_header
) - *input_len
;
200 hdr
= (struct hmsg_header
*)*input_buffer
;
201 if (hdr
->len
> HMSG_MAX_SIZE
) {
202 LLOG_WARNX("message received is too large");
203 /* We discard the whole buffer */
205 *input_buffer
= NULL
;
209 if (*input_len
< sizeof(struct hmsg_header
) + hdr
->len
) {
210 /* Not enough data. */
211 return sizeof(struct hmsg_header
) + hdr
->len
- *input_len
;
213 if (hdr
->type
!= expected_type
) {
214 if (expected_type
== NOTIFICATION
) return -1;
215 LLOG_WARNX("incorrect received message type (expected: %d, received: %d)",
216 expected_type
, hdr
->type
);
220 if (t
&& !hdr
->len
) {
221 LLOG_WARNX("no payload available in answer");
225 /* We have data to unserialize. */
226 if (marshal_unserialize_(mi
, *input_buffer
+ sizeof(struct hmsg_header
),
227 hdr
->len
, t
, NULL
, 0, 0) <= 0) {
228 LLOG_WARNX("unable to deserialize received data");
235 /* Discard input buffer */
236 *input_len
-= sizeof(struct hmsg_header
) + hdr
->len
;
237 if (*input_len
== 0) {
239 *input_buffer
= NULL
;
241 memmove(*input_buffer
,
242 *input_buffer
+ sizeof(struct hmsg_header
) + hdr
->len
,