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