]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/lib/atom.c
Separate daemon and client code. Provide a client library.
[thirdparty/lldpd.git] / src / lib / atom.c
1 /* -*- mode: c; c-file-style: "openbsd" -*- */
2 /*
3 * Copyright (c) 2012 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 <stdio.h>
19 #include <string.h>
20 #include "lldpctl.h"
21 #include "private.h"
22 #include "../marshal.h"
23 #include "../ctl.h"
24 #include "../lldpd-structs.h"
25
26 lldpctl_conn_t*
27 lldpctl_atom_get_connection(lldpctl_atom_t *atom)
28 {
29 if (atom)
30 return atom->conn;
31 return NULL;
32 }
33
34 void
35 lldpctl_atom_inc_ref(lldpctl_atom_t *atom)
36 {
37 atom->count++;
38 }
39
40 void
41 lldpctl_atom_dec_ref(lldpctl_atom_t *atom)
42 {
43 struct atom_buffer *buffer, *buffer_next;
44 if (atom && (--atom->count == 0)) {
45 if (atom->free)
46 atom->free(atom);
47
48 /* Remove special allocated buffers */
49 for (buffer = TAILQ_FIRST(&atom->buffers);
50 buffer;
51 buffer = buffer_next) {
52 buffer_next = TAILQ_NEXT(buffer, next);
53 free(buffer);
54 }
55
56 free(atom);
57 }
58 }
59
60 lldpctl_atom_t*
61 lldpctl_atom_get(lldpctl_atom_t *atom, lldpctl_key_t key)
62 {
63 if (atom == NULL) return NULL;
64 RESET_ERROR(atom->conn);
65
66 if (atom->get == NULL) {
67 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
68 return NULL;
69 }
70 return atom->get(atom, key);
71 }
72
73 lldpctl_atom_t*
74 lldpctl_atom_set(lldpctl_atom_t *atom, lldpctl_key_t key,
75 lldpctl_atom_t *value)
76 {
77 if (atom == NULL) return NULL;
78 RESET_ERROR(atom->conn);
79
80 if (atom->set == NULL) {
81 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
82 return NULL;
83 }
84 return atom->set(atom, key, value);
85 }
86
87 const char*
88 lldpctl_atom_get_str(lldpctl_atom_t *atom, lldpctl_key_t key)
89 {
90 char *strresult = NULL;
91 const uint8_t *bufresult = NULL;
92 long int intresult = -1;
93 int n1;
94 size_t n2;
95
96 if (atom == NULL) return NULL;
97 RESET_ERROR(atom->conn);
98
99 if (atom->get_str != NULL) {
100 strresult = (char *)atom->get_str(atom, key);
101 if (strresult) return strresult;
102 if (lldpctl_last_error(atom->conn) != LLDPCTL_ERR_NOT_EXIST)
103 return NULL;
104 }
105
106 RESET_ERROR(atom->conn);
107 if (atom->get_int != NULL) {
108 intresult = atom->get_int(atom, key);
109 if (lldpctl_last_error(atom->conn) != LLDPCTL_ERR_NOT_EXIST) {
110 strresult = _lldpctl_alloc_in_atom(atom, 21);
111 if (!strresult) return NULL;
112 n1 = snprintf(strresult, 21, "%ld", intresult);
113 if (n1 > -1 && n1 < 21)
114 return strresult;
115 SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM); /* Not really true... */
116 return NULL;
117 }
118 }
119
120 RESET_ERROR(atom->conn);
121 if (atom->get_buffer != NULL) {
122 bufresult = atom->get_buffer(atom, key, &n2);
123 if (bufresult)
124 return _lldpctl_dump_in_atom(atom, bufresult, n2, ' ', 0);
125 if (lldpctl_last_error(atom->conn) != LLDPCTL_ERR_NOT_EXIST)
126 return NULL;
127 }
128
129 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
130 return NULL;
131 }
132
133 lldpctl_atom_t*
134 lldpctl_atom_set_str(lldpctl_atom_t *atom, lldpctl_key_t key,
135 const char *value)
136 {
137 lldpctl_atom_t *result = NULL;
138 char *end;
139 long int converted;
140 int isint;
141 int bad = 0;
142
143 if (atom == NULL) return NULL;
144 RESET_ERROR(atom->conn);
145
146 if (atom->set_str != NULL) {
147 result = atom->set_str(atom, key, value);
148 if (result) return result;
149 if (lldpctl_last_error(atom->conn) != LLDPCTL_ERR_NOT_EXIST &&
150 lldpctl_last_error(atom->conn) != LLDPCTL_ERR_BAD_VALUE)
151 return NULL;
152 bad = bad || (lldpctl_last_error(atom->conn) == LLDPCTL_ERR_BAD_VALUE);
153 }
154
155 converted = strtol(value, &end, 0);
156 isint = (end != value && *end == '\0');
157
158 RESET_ERROR(atom->conn);
159 if (atom->set_int != NULL && isint) {
160 result = atom->set_int(atom, key, converted);
161 if (result) return result;
162 if (lldpctl_last_error(atom->conn) != LLDPCTL_ERR_NOT_EXIST &&
163 lldpctl_last_error(atom->conn) != LLDPCTL_ERR_BAD_VALUE)
164 return NULL;
165 bad = bad || (lldpctl_last_error(atom->conn) == LLDPCTL_ERR_BAD_VALUE);
166 }
167
168 RESET_ERROR(atom->conn);
169 if (atom->set_buffer != NULL) {
170 result = atom->set_buffer(atom, key, (u_int8_t*)value, strlen(value));
171 if (result) return result;
172 if (lldpctl_last_error(atom->conn) != LLDPCTL_ERR_NOT_EXIST &&
173 lldpctl_last_error(atom->conn) != LLDPCTL_ERR_BAD_VALUE)
174 return NULL;
175 bad = bad || (lldpctl_last_error(atom->conn) == LLDPCTL_ERR_BAD_VALUE);
176 }
177
178 SET_ERROR(atom->conn, bad?LLDPCTL_ERR_BAD_VALUE:LLDPCTL_ERR_NOT_EXIST);
179 return NULL;
180 }
181
182 const u_int8_t*
183 lldpctl_atom_get_buffer(lldpctl_atom_t *atom, lldpctl_key_t key,
184 size_t *length)
185 {
186 if (atom == NULL) return NULL;
187 RESET_ERROR(atom->conn);
188
189 if (atom->get_buffer == NULL) {
190 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
191 return NULL;
192 }
193 return atom->get_buffer(atom, key, length);
194 }
195
196 lldpctl_atom_t*
197 lldpctl_atom_set_buffer(lldpctl_atom_t *atom, lldpctl_key_t key,
198 const u_int8_t* value, size_t length)
199 {
200 if (atom == NULL) return NULL;
201 RESET_ERROR(atom->conn);
202
203 if (atom->set_buffer == NULL) {
204 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
205 return NULL;
206 }
207 return atom->set_buffer(atom, key, value, length);
208 }
209
210 long int
211 lldpctl_atom_get_int(lldpctl_atom_t *atom, lldpctl_key_t key)
212 {
213 if (atom == NULL) return LLDPCTL_ERR_NOT_EXIST;
214 RESET_ERROR(atom->conn);
215
216 if (atom->get_int == NULL)
217 return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
218 return atom->get_int(atom, key);
219 }
220
221 lldpctl_atom_t*
222 lldpctl_atom_set_int(lldpctl_atom_t *atom, lldpctl_key_t key,
223 long int value)
224 {
225 if (atom == NULL) return NULL;
226 RESET_ERROR(atom->conn);
227
228 if (atom->set_int == NULL) {
229 SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
230 return NULL;
231 }
232 return atom->set_int(atom, key, value);
233 }
234
235 lldpctl_atom_iter_t*
236 lldpctl_atom_iter(lldpctl_atom_t *atom)
237 {
238 if (atom == NULL) return NULL;
239 RESET_ERROR(atom->conn);
240
241 if (!atom->iter) {
242 SET_ERROR(atom->conn, LLDPCTL_ERR_CANNOT_ITERATE);
243 return NULL;
244 }
245 return atom->iter(atom);
246 }
247
248 lldpctl_atom_iter_t*
249 lldpctl_atom_iter_next(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
250 {
251 if (atom == NULL) return NULL;
252 RESET_ERROR(atom->conn);
253
254 if (!atom->next) {
255 SET_ERROR(atom->conn, LLDPCTL_ERR_CANNOT_ITERATE);
256 return NULL;
257 }
258 return atom->next(atom, iter);
259 }
260
261 lldpctl_atom_t*
262 lldpctl_atom_iter_value(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter)
263 {
264 if (atom == NULL) return NULL;
265 RESET_ERROR(atom->conn);
266
267 if (!atom->value) {
268 SET_ERROR(atom->conn, LLDPCTL_ERR_CANNOT_ITERATE);
269 return NULL;
270 }
271 return atom->value(atom, iter);
272 }
273
274 lldpctl_atom_t*
275 lldpctl_atom_create(lldpctl_atom_t *atom)
276 {
277 if (atom == NULL) return NULL;
278 RESET_ERROR(atom->conn);
279
280 if (!atom->create) {
281 SET_ERROR(atom->conn, LLDPCTL_ERR_CANNOT_CREATE);
282 return NULL;
283 }
284 return atom->create(atom);
285 }
286
287 /**
288 * Get somethin with IO.
289 *
290 * @param conn The connection to lldpd.
291 * @param state_send State to be when "sending"
292 * @param state_recv State to be when "receiving"
293 * @param type Type of message to send (and receive)
294 * @param to_send Data to send.
295 * @param mi_send Marshalling info for data to send.
296 * @param to_recv Data to receive.
297 * @param mi_recv Marshalling info for data to recive.
298 * @return 0 in case of success, a negative integer in case of failure.
299 */
300 int
301 _lldpctl_do_something(lldpctl_conn_t *conn,
302 int state_send, int state_recv, void *state_data,
303 enum hmsg_type type,
304 void *to_send, struct marshal_info *mi_send,
305 void **to_recv, struct marshal_info *mi_recv)
306 {
307 ssize_t rc;
308
309 if (conn->state == CONN_STATE_IDLE) {
310 /* We need to build the message to send, then send
311 * it. */
312 if (ctl_msg_send_unserialized(&conn->output_buffer, &conn->output_buffer_len,
313 type, to_send, mi_send) != 0)
314 return SET_ERROR(conn, LLDPCTL_ERR_SERIALIZATION);
315 conn->state = state_send;
316 conn->state_data = state_data;
317 }
318 if (conn->state == state_send && conn->state_data == state_data) {
319 /* We need to send the currently built message */
320 rc = lldpctl_send(conn);
321 if (rc < 0)
322 return SET_ERROR(conn, rc);
323 conn->state = state_recv;
324 }
325 if (conn->state == state_recv && conn->state_data == state_data) {
326 /* We need to receive the answer */
327 while ((rc = ctl_msg_recv_unserialized(&conn->input_buffer, &conn->input_buffer_len,
328 type,
329 to_recv, mi_recv)) > 0) {
330 /* We need more bytes */
331 rc = _lldpctl_needs(conn, rc);
332 if (rc < 0)
333 return SET_ERROR(conn, rc);
334 }
335 if (rc < 0)
336 return SET_ERROR(conn, LLDPCTL_ERR_SERIALIZATION);
337 /* rc == 0 */
338 conn->state = CONN_STATE_IDLE;
339 conn->state_data = NULL;
340 return 0;
341 } else
342 return SET_ERROR(conn, LLDPCTL_ERR_INVALID_STATE);
343 }
344
345 lldpctl_atom_t*
346 lldpctl_get_interfaces(lldpctl_conn_t *conn)
347 {
348 struct lldpd_interface_list *ifs;
349 int rc;
350
351 RESET_ERROR(conn);
352
353 rc = _lldpctl_do_something(conn,
354 CONN_STATE_GET_INTERFACES_SEND, CONN_STATE_GET_INTERFACES_RECV, NULL,
355 GET_INTERFACES,
356 NULL, NULL,
357 (void **)&ifs, &MARSHAL_INFO(lldpd_interface_list));
358 if (rc == 0)
359 return _lldpctl_new_atom(conn, atom_interfaces_list, ifs);
360 return NULL;
361 }
362
363 lldpctl_atom_t*
364 lldpctl_get_port(lldpctl_atom_t *atom)
365 {
366 int rc;
367 lldpctl_conn_t *conn = atom->conn;
368 struct lldpd_hardware *hardware;
369 struct _lldpctl_atom_interface_t *iface =
370 (struct _lldpctl_atom_interface_t *)atom;
371
372 RESET_ERROR(conn);
373
374 if (atom->type != atom_interface) {
375 SET_ERROR(conn, LLDPCTL_ERR_INCORRECT_ATOM_TYPE);
376 return NULL;
377 }
378 rc = _lldpctl_do_something(conn,
379 CONN_STATE_GET_PORT_SEND, CONN_STATE_GET_PORT_RECV, iface->name,
380 GET_INTERFACE, (void*)iface->name, &MARSHAL_INFO(string),
381 (void**)&hardware, &MARSHAL_INFO(lldpd_hardware));
382 if (rc == 0)
383 return _lldpctl_new_atom(conn, atom_port,
384 hardware, &hardware->h_lport, NULL);
385 return NULL;
386 }