]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/ctl.c
freebsd: make it compile and work on real FreeBSD systems
[thirdparty/lldpd.git] / src / ctl.c
1 /* -*- mode: c; c-file-style: "openbsd" -*- */
2 /*
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
4 *
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.
8 *
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.
16 */
17
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <fcntl.h>
21 #include <errno.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <sys/un.h>
25 #include <string.h>
26
27 #include "ctl.h"
28 #include "marshal.h"
29 #include "log.h"
30 #include "compat/compat.h"
31
32 #define UNIX_PATH_MAX 108
33
34 /**
35 * Create a new listening Unix socket for control protocol.
36 *
37 * @param name The name of the Unix socket.
38 * @return The socket when successful, -1 otherwise.
39 */
40 int
41 ctl_create(char *name)
42 {
43 int s;
44 struct sockaddr_un su;
45 int rc;
46
47 log_debug("control", "create control socket %s", name);
48
49 if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
50 return -1;
51 su.sun_family = AF_UNIX;
52 strlcpy(su.sun_path, name, UNIX_PATH_MAX);
53 if (bind(s, (struct sockaddr *)&su, sizeof(struct sockaddr_un)) == -1) {
54 rc = errno; close(s); errno = rc;
55 return -1;
56 }
57
58 log_debug("control", "listen to control socket %s", name);
59 if (listen(s, 5) == -1) {
60 rc = errno; close(s); errno = rc;
61 log_debug("control", "cannot listen to control socket %s", name);
62 return -1;
63 }
64 return s;
65 }
66
67 /**
68 * Connect to the control Unix socket.
69 *
70 * @param name The name of the Unix socket.
71 * @return The socket when successful, -1 otherwise.
72 */
73 int
74 ctl_connect(char *name)
75 {
76 int s;
77 struct sockaddr_un su;
78 int rc;
79
80 log_debug("control", "connect to control socket %s", name);
81
82 if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
83 return -1;
84 su.sun_family = AF_UNIX;
85 strlcpy(su.sun_path, name, UNIX_PATH_MAX);
86 if (connect(s, (struct sockaddr *)&su, sizeof(struct sockaddr_un)) == -1) {
87 rc = errno;
88 log_warn("control", "unable to connect to socket %s", name);
89 errno = rc; return -1;
90 }
91 return s;
92 }
93
94 /**
95 * Remove the control Unix socket.
96 *
97 * @param name The name of the Unix socket.
98 */
99 void
100 ctl_cleanup(char *name)
101 {
102 log_debug("control", "cleanup control socket");
103 if (unlink(name) == -1)
104 log_warn("control", "unable to unlink %s", name);
105 }
106
107 /**
108 * Serialize and "send" a structure through the control protocol.
109 *
110 * This function does not really send the message but outputs it to a buffer.
111 *
112 * @param output_buffer A pointer to a buffer to which the message will be
113 * appended. Can be @c NULL. In this case, the buffer will
114 * be allocated.
115 * @param[in,out] output_len The length of the provided buffer. Will be updated
116 * with the new length
117 * @param type The type of message we want to send.
118 * @param t The structure to be serialized and sent.
119 * @param mi The appropriate marshal structure for serialization.
120 * @return -1 in case of failure, 0 in case of success.
121 *
122 * Make sure this function logic matches the server-side one: @c levent_ctl_recv().
123 */
124 int
125 ctl_msg_send_unserialized(uint8_t **output_buffer, size_t *output_len,
126 enum hmsg_type type,
127 void *t, struct marshal_info *mi)
128 {
129 struct hmsg_header hdr;
130 size_t len = 0, newlen;
131 void *buffer = NULL;
132
133 log_debug("control", "send a message through control socket");
134 if (t) {
135 len = marshal_serialize_(mi, t, &buffer, 0, NULL, 0);
136 if (len <= 0) {
137 log_warnx("control", "unable to serialize data");
138 return -1;
139 }
140 }
141
142 newlen = len + sizeof(struct hmsg_header);
143
144 if (*output_buffer == NULL) {
145 *output_len = 0;
146 if ((*output_buffer = malloc(newlen)) == NULL) {
147 log_warn("control", "no memory available");
148 free(buffer);
149 return -1;
150 }
151 } else {
152 void *new = realloc(*output_buffer, *output_len + newlen);
153 if (new == NULL) {
154 log_warn("control", "no memory available");
155 free(buffer);
156 return -1;
157 }
158 *output_buffer = new;
159 }
160 memset(&hdr, 0, sizeof(struct hmsg_header));
161 hdr.type = type;
162 hdr.len = len;
163 memcpy(*output_buffer + *output_len, &hdr, sizeof(struct hmsg_header));
164 if (t)
165 memcpy(*output_buffer + *output_len + sizeof(struct hmsg_header), buffer, len);
166 *output_len += newlen;
167 free(buffer);
168 return 0;
169 }
170
171 /**
172 * "Receive" and unserialize a structure through the control protocol.
173 *
174 * Like @c ctl_msg_send_unserialized(), this function uses buffer to receive the
175 * incoming message.
176 *
177 * @param[in,out] input_buffer The buffer with the incoming message. Will be
178 * updated once the message has been unserialized to
179 * point to the remaining of the message or will be
180 * freed if all the buffer has been consumed. Can be
181 * @c NULL.
182 * @param[in,out] input_len The length of the provided buffer. Will be updated
183 * to the length of remaining data once the message
184 * has been unserialized.
185 * @param expected_type The expected message type.
186 * @param[out] t Will contain a pointer to the unserialized structure.
187 * Can be @c NULL if we don't want to store the
188 * answer.
189 * @param mi The appropriate marshal structure for unserialization.
190 *
191 * @return -1 in case of error, 0 in case of success and the number of bytes we
192 * request to complete unserialization.
193 *
194 * When requesting a notification, the input buffer is left untouched if we
195 * don't get one and we fail silently.
196 */
197 size_t
198 ctl_msg_recv_unserialized(uint8_t **input_buffer, size_t *input_len,
199 enum hmsg_type expected_type,
200 void **t, struct marshal_info *mi)
201 {
202 struct hmsg_header hdr;
203 int rc = -1;
204
205 if (*input_buffer == NULL ||
206 *input_len < sizeof(struct hmsg_header)) {
207 /* Not enough data. */
208 return sizeof(struct hmsg_header) - *input_len;
209 }
210
211 log_debug("control", "receive a message through control socket");
212 memcpy(&hdr, *input_buffer, sizeof(struct hmsg_header));
213 if (hdr.len > HMSG_MAX_SIZE) {
214 log_warnx("control", "message received is too large");
215 /* We discard the whole buffer */
216 free(*input_buffer);
217 *input_buffer = NULL;
218 *input_len = 0;
219 return -1;
220 }
221 if (*input_len < sizeof(struct hmsg_header) + hdr.len) {
222 /* Not enough data. */
223 return sizeof(struct hmsg_header) + hdr.len - *input_len;
224 }
225 if (hdr.type != expected_type) {
226 if (expected_type == NOTIFICATION) return -1;
227 log_warnx("control", "incorrect received message type (expected: %d, received: %d)",
228 expected_type, hdr.type);
229 goto end;
230 }
231
232 if (t && !hdr.len) {
233 log_warnx("control", "no payload available in answer");
234 goto end;
235 }
236 if (t) {
237 /* We have data to unserialize. */
238 if (marshal_unserialize_(mi, *input_buffer + sizeof(struct hmsg_header),
239 hdr.len, t, NULL, 0, 0) <= 0) {
240 log_warnx("control", "unable to deserialize received data");
241 goto end;
242 }
243 }
244
245 rc = 0;
246 end:
247 /* Discard input buffer */
248 *input_len -= sizeof(struct hmsg_header) + hdr.len;
249 if (*input_len == 0) {
250 free(*input_buffer);
251 *input_buffer = NULL;
252 } else
253 memmove(*input_buffer,
254 *input_buffer + sizeof(struct hmsg_header) + hdr.len,
255 *input_len);
256 return rc;
257 }