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