Coverage Report

Created: 2026-02-26 06:48

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