]>
Commit | Line | Data |
---|---|---|
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 | 38 | int |
0262adbb | 39 | ctl_create(const 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 | 71 | int |
0262adbb | 72 | ctl_connect(const char *name) |
43c02e7b VB |
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; | |
fdabbf8e | 83 | strlcpy(su.sun_path, name, sizeof(su.sun_path)); |
43c02e7b VB |
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); |
676b4970 | 87 | close(s); |
43c02e7b VB |
88 | errno = rc; return -1; |
89 | } | |
90 | return s; | |
91 | } | |
92 | ||
4b292b55 VB |
93 | /** |
94 | * Remove the control Unix socket. | |
95 | * | |
96 | * @param name The name of the Unix socket. | |
97 | */ | |
98 | void | |
0262adbb | 99 | ctl_cleanup(const char *name) |
4b292b55 | 100 | { |
6f8925be | 101 | log_debug("control", "cleanup control socket"); |
4b292b55 | 102 | if (unlink(name) == -1) |
6f8925be | 103 | log_warn("control", "unable to unlink %s", name); |
4b292b55 VB |
104 | } |
105 | ||
4b292b55 VB |
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. | |
b1eceab6 | 114 | * @param[in,out] output_len The length of the provided buffer. Will be updated |
4b292b55 VB |
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. | |
e0478a46 VB |
120 | * |
121 | * Make sure this function logic matches the server-side one: @c levent_ctl_recv(). | |
4b292b55 | 122 | */ |
43c02e7b | 123 | int |
4b292b55 | 124 | ctl_msg_send_unserialized(uint8_t **output_buffer, size_t *output_len, |
f6d20631 | 125 | enum hmsg_type type, |
4b292b55 | 126 | void *t, struct marshal_info *mi) |
f6d20631 | 127 | { |
281a5cd4 | 128 | ssize_t len = 0, newlen; |
4b292b55 VB |
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 | } |
b0cb07f7 VB |
158 | |
159 | struct hmsg_header hdr = { | |
160 | .type = type, | |
161 | .len = len | |
162 | }; | |
4b292b55 VB |
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 | * | |
b1eceab6 | 177 | * @param[in,out] input_buffer The buffer with the incoming message. Will be |
4b292b55 VB |
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. | |
b1eceab6 | 182 | * @param[in,out] input_len The length of the provided buffer. Will be updated |
4b292b55 VB |
183 | * to the length of remaining data once the message |
184 | * has been unserialized. | |
185 | * @param expected_type The expected message type. | |
b1eceab6 | 186 | * @param[out] t Will contain a pointer to the unserialized structure. |
4b292b55 VB |
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. | |
4e90a9e0 VB |
193 | * |
194 | * When requesting a notification, the input buffer is left untouched if we | |
195 | * don't get one and we fail silently. | |
4b292b55 VB |
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 | { | |
072f743c | 202 | struct hmsg_header hdr; |
4b292b55 VB |
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; | |
f6d20631 | 209 | } |
6f8925be VB |
210 | |
211 | log_debug("control", "receive a message through control socket"); | |
072f743c VB |
212 | memcpy(&hdr, *input_buffer, sizeof(struct hmsg_header)); |
213 | if (hdr.len > HMSG_MAX_SIZE) { | |
6f8925be | 214 | log_warnx("control", "message received is too large"); |
4b292b55 VB |
215 | /* We discard the whole buffer */ |
216 | free(*input_buffer); | |
217 | *input_buffer = NULL; | |
218 | *input_len = 0; | |
219 | return -1; | |
220 | } | |
072f743c | 221 | if (*input_len < sizeof(struct hmsg_header) + hdr.len) { |
4b292b55 | 222 | /* Not enough data. */ |
072f743c | 223 | return sizeof(struct hmsg_header) + hdr.len - *input_len; |
4b292b55 | 224 | } |
072f743c | 225 | if (hdr.type != expected_type) { |
4e90a9e0 | 226 | if (expected_type == NOTIFICATION) return -1; |
6f8925be | 227 | log_warnx("control", "incorrect received message type (expected: %d, received: %d)", |
072f743c | 228 | expected_type, hdr.type); |
4b292b55 VB |
229 | goto end; |
230 | } | |
231 | ||
072f743c | 232 | if (t && !hdr.len) { |
6f8925be | 233 | log_warnx("control", "no payload available in answer"); |
4b292b55 | 234 | goto end; |
f6d20631 | 235 | } |
4b292b55 VB |
236 | if (t) { |
237 | /* We have data to unserialize. */ | |
238 | if (marshal_unserialize_(mi, *input_buffer + sizeof(struct hmsg_header), | |
072f743c | 239 | hdr.len, t, NULL, 0, 0) <= 0) { |
6f8925be | 240 | log_warnx("control", "unable to deserialize received data"); |
4b292b55 VB |
241 | goto end; |
242 | } | |
f6d20631 | 243 | } |
43c02e7b | 244 | |
4b292b55 VB |
245 | rc = 0; |
246 | end: | |
247 | /* Discard input buffer */ | |
072f743c | 248 | *input_len -= sizeof(struct hmsg_header) + hdr.len; |
4b292b55 VB |
249 | if (*input_len == 0) { |
250 | free(*input_buffer); | |
251 | *input_buffer = NULL; | |
252 | } else | |
0f957f3a | 253 | memmove(*input_buffer, |
072f743c | 254 | *input_buffer + sizeof(struct hmsg_header) + hdr.len, |
4b292b55 VB |
255 | *input_len); |
256 | return rc; | |
43c02e7b | 257 | } |