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