]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/ctl.c
doc: polish documentation of liblldpctl
[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
26 #include "ctl.h"
27 #include "marshal.h"
28 #include "log.h"
29 #include "compat/compat.h"
30
31 #define UNIX_PATH_MAX 108
32
33 /**
34 * Create a new listening Unix socket for control protocol.
35 *
36 * @param name The name of the Unix socket.
37 * @return The socket when successful, -1 otherwise.
38 */
39 int
40 ctl_create(char *name)
41 {
42 int s;
43 struct sockaddr_un su;
44 int rc;
45
46 if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
47 return -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;
52 return -1;
53 }
54 if (listen(s, 5) == -1) {
55 rc = errno; close(s); errno = rc;
56 return -1;
57 }
58 return s;
59 }
60
61 /**
62 * Connect to the control Unix socket.
63 *
64 * @param name The name of the Unix socket.
65 * @return The socket when successful, -1 otherwise.
66 */
67 int
68 ctl_connect(char *name)
69 {
70 int s;
71 struct sockaddr_un su;
72 int rc;
73
74 if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
75 return -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) {
79 rc = errno;
80 LLOG_WARN("unable to connect to socket %s", name);
81 errno = rc; return -1;
82 }
83 return s;
84 }
85
86 /**
87 * Remove the control Unix socket.
88 *
89 * @param name The name of the Unix socket.
90 */
91 void
92 ctl_cleanup(char *name)
93 {
94 if (unlink(name) == -1)
95 LLOG_WARN("unable to unlink %s", name);
96 }
97
98 /**
99 * Serialize and "send" a structure through the control protocol.
100 *
101 * This function does not really send the message but outputs it to a buffer.
102 *
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
105 * be allocated.
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.
112 *
113 * Make sure this function logic matches the server-side one: @c levent_ctl_recv().
114 */
115 int
116 ctl_msg_send_unserialized(uint8_t **output_buffer, size_t *output_len,
117 enum hmsg_type type,
118 void *t, struct marshal_info *mi)
119 {
120 struct hmsg_header hdr;
121 size_t len = 0, newlen;
122 void *buffer = NULL;
123
124 if (t) {
125 len = marshal_serialize_(mi, t, &buffer, 0, NULL, 0);
126 if (len <= 0) {
127 LLOG_WARNX("unable to serialize data");
128 return -1;
129 }
130 }
131
132 newlen = len + sizeof(struct hmsg_header);
133
134 if (*output_buffer == NULL) {
135 *output_len = 0;
136 if ((*output_buffer = malloc(newlen)) == NULL) {
137 LLOG_WARN("no memory available");
138 free(buffer);
139 return -1;
140 }
141 } else {
142 void *new = realloc(*output_buffer, *output_len + newlen);
143 if (new == NULL) {
144 LLOG_WARN("no memory available");
145 free(buffer);
146 return -1;
147 }
148 *output_buffer = new;
149 }
150 memset(&hdr, 0, sizeof(struct hmsg_header));
151 hdr.type = type;
152 hdr.len = len;
153 memcpy(*output_buffer + *output_len, &hdr, sizeof(struct hmsg_header));
154 if (t)
155 memcpy(*output_buffer + *output_len + sizeof(struct hmsg_header), buffer, len);
156 *output_len += newlen;
157 free(buffer);
158 return 0;
159 }
160
161 /**
162 * "Receive" and unserialize a structure through the control protocol.
163 *
164 * Like @c ctl_msg_send_unserialized(), this function uses buffer to receive the
165 * incoming message.
166 *
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
171 * @c NULL.
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
178 * answer.
179 * @param mi The appropriate marshal structure for unserialization.
180 *
181 * @return -1 in case of error, 0 in case of success and the number of bytes we
182 * request to complete unserialization.
183 *
184 * When requesting a notification, the input buffer is left untouched if we
185 * don't get one and we fail silently.
186 */
187 size_t
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)
191 {
192 struct hmsg_header *hdr;
193 int rc = -1;
194
195 if (*input_buffer == NULL ||
196 *input_len < sizeof(struct hmsg_header)) {
197 /* Not enough data. */
198 return sizeof(struct hmsg_header) - *input_len;
199 }
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 */
204 free(*input_buffer);
205 *input_buffer = NULL;
206 *input_len = 0;
207 return -1;
208 }
209 if (*input_len < sizeof(struct hmsg_header) + hdr->len) {
210 /* Not enough data. */
211 return sizeof(struct hmsg_header) + hdr->len - *input_len;
212 }
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);
217 goto end;
218 }
219
220 if (t && !hdr->len) {
221 LLOG_WARNX("no payload available in answer");
222 goto end;
223 }
224 if (t) {
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");
229 goto end;
230 }
231 }
232
233 rc = 0;
234 end:
235 /* Discard input buffer */
236 *input_len -= sizeof(struct hmsg_header) + hdr->len;
237 if (*input_len == 0) {
238 free(*input_buffer);
239 *input_buffer = NULL;
240 } else
241 memmove(*input_buffer,
242 *input_buffer + sizeof(struct hmsg_header) + hdr->len,
243 *input_len);
244 return rc;
245 }