]> git.proxmox.com Git - mirror_frr.git/blob - ospfclient/ospf_apiclient.c
ospfclient: Free up leaked resources in error path
[mirror_frr.git] / ospfclient / ospf_apiclient.c
1 /*
2 * Client side of OSPF API.
3 * Copyright (C) 2001, 2002, 2003 Ralph Keller
4 *
5 * This file is part of GNU Zebra.
6 *
7 * GNU Zebra is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation; either version 2, or (at your
10 * option) any later version.
11 *
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; see the file COPYING; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include <zebra.h>
23
24 #include <lib/version.h>
25 #include "getopt.h"
26 #include "thread.h"
27 #include "prefix.h"
28 #include "linklist.h"
29 #include "if.h"
30 #include "vector.h"
31 #include "vty.h"
32 #include "command.h"
33 #include "filter.h"
34 #include "stream.h"
35 #include "log.h"
36 #include "memory.h"
37
38 /* work around gcc bug 69981, disable MTYPEs in libospf */
39 #define _QUAGGA_OSPF_MEMORY_H
40
41 #include "ospfd/ospfd.h"
42 #include "ospfd/ospf_interface.h"
43 #include "ospfd/ospf_asbr.h"
44 #include "ospfd/ospf_lsa.h"
45 #include "ospfd/ospf_opaque.h"
46 #include "ospfd/ospf_lsdb.h"
47 #include "ospfd/ospf_neighbor.h"
48 #include "ospfd/ospf_dump.h"
49 #include "ospfd/ospf_zebra.h"
50 #include "ospfd/ospf_api.h"
51
52 #include "ospf_apiclient.h"
53
54 /* *sigh* ... can't find a better way to hammer this into automake */
55 #include "ospfd/ospf_dump_api.c"
56 #include "ospfd/ospf_api.c"
57
58 DEFINE_MGROUP(OSPFCLIENT, "libospfapiclient")
59 DEFINE_MTYPE_STATIC(OSPFCLIENT, OSPF_APICLIENT, "OSPF-API client")
60
61 /* Backlog for listen */
62 #define BACKLOG 5
63
64 /* -----------------------------------------------------------
65 * Forward declarations
66 * -----------------------------------------------------------
67 */
68
69 void ospf_apiclient_handle_reply (struct ospf_apiclient *oclient,
70 struct msg *msg);
71 void ospf_apiclient_handle_update_notify (struct ospf_apiclient *oclient,
72 struct msg *msg);
73 void ospf_apiclient_handle_delete_notify (struct ospf_apiclient *oclient,
74 struct msg *msg);
75
76 /* -----------------------------------------------------------
77 * Initialization
78 * -----------------------------------------------------------
79 */
80
81 static unsigned short
82 ospf_apiclient_getport (void)
83 {
84 struct servent *sp = getservbyname ("ospfapi", "tcp");
85
86 return sp ? ntohs (sp->s_port) : OSPF_API_SYNC_PORT;
87 }
88
89 /* -----------------------------------------------------------
90 * Followings are functions for connection management
91 * -----------------------------------------------------------
92 */
93
94 struct ospf_apiclient *
95 ospf_apiclient_connect (char *host, int syncport)
96 {
97 struct sockaddr_in myaddr_sync;
98 struct sockaddr_in myaddr_async;
99 struct sockaddr_in peeraddr;
100 struct hostent *hp;
101 struct ospf_apiclient *new;
102 int size = 0;
103 unsigned int peeraddrlen;
104 int async_server_sock;
105 int fd1, fd2;
106 int ret;
107 int on = 1;
108
109 /* There are two connections between the client and the server.
110 First the client opens a connection for synchronous requests/replies
111 to the server. The server will accept this connection and
112 as a reaction open a reverse connection channel for
113 asynchronous messages. */
114
115 async_server_sock = socket (AF_INET, SOCK_STREAM, 0);
116 if (async_server_sock < 0)
117 {
118 fprintf (stderr,
119 "ospf_apiclient_connect: creating async socket failed\n");
120 return NULL;
121 }
122
123 /* Prepare socket for asynchronous messages */
124 /* Initialize async address structure */
125 memset (&myaddr_async, 0, sizeof (struct sockaddr_in));
126 myaddr_async.sin_family = AF_INET;
127 myaddr_async.sin_addr.s_addr = htonl (INADDR_ANY);
128 myaddr_async.sin_port = htons (syncport+1);
129 size = sizeof (struct sockaddr_in);
130 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
131 myaddr_async.sin_len = size;
132 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
133
134 /* This is a server socket, reuse addr and port */
135 ret = setsockopt (async_server_sock, SOL_SOCKET,
136 SO_REUSEADDR, (void *) &on, sizeof (on));
137 if (ret < 0)
138 {
139 fprintf (stderr, "ospf_apiclient_connect: SO_REUSEADDR failed\n");
140 close (async_server_sock);
141 return NULL;
142 }
143
144 #ifdef SO_REUSEPORT
145 ret = setsockopt (async_server_sock, SOL_SOCKET, SO_REUSEPORT,
146 (void *) &on, sizeof (on));
147 if (ret < 0)
148 {
149 fprintf (stderr, "ospf_apiclient_connect: SO_REUSEPORT failed\n");
150 close (async_server_sock);
151 return NULL;
152 }
153 #endif /* SO_REUSEPORT */
154
155 /* Bind socket to address structure */
156 ret = bind (async_server_sock, (struct sockaddr *) &myaddr_async, size);
157 if (ret < 0)
158 {
159 fprintf (stderr, "ospf_apiclient_connect: bind async socket failed\n");
160 close (async_server_sock);
161 return NULL;
162 }
163
164 /* Wait for reverse channel connection establishment from server */
165 ret = listen (async_server_sock, BACKLOG);
166 if (ret < 0)
167 {
168 fprintf (stderr, "ospf_apiclient_connect: listen: %s\n", safe_strerror (errno));
169 close (async_server_sock);
170 return NULL;
171 }
172
173 /* Make connection for synchronous requests and connect to server */
174 /* Resolve address of server */
175 hp = gethostbyname (host);
176 if (!hp)
177 {
178 fprintf (stderr, "ospf_apiclient_connect: no such host %s\n", host);
179 close (async_server_sock);
180 return NULL;
181 }
182
183 fd1 = socket (AF_INET, SOCK_STREAM, 0);
184 if (fd1 < 0)
185 {
186 close (async_server_sock);
187 fprintf (stderr,
188 "ospf_apiclient_connect: creating sync socket failed\n");
189 return NULL;
190 }
191
192
193 /* Reuse addr and port */
194 ret = setsockopt (fd1, SOL_SOCKET,
195 SO_REUSEADDR, (void *) &on, sizeof (on));
196 if (ret < 0)
197 {
198 fprintf (stderr, "ospf_apiclient_connect: SO_REUSEADDR failed\n");
199 close (fd1);
200 close (async_server_sock);
201 return NULL;
202 }
203
204 #ifdef SO_REUSEPORT
205 ret = setsockopt (fd1, SOL_SOCKET, SO_REUSEPORT,
206 (void *) &on, sizeof (on));
207 if (ret < 0)
208 {
209 fprintf (stderr, "ospf_apiclient_connect: SO_REUSEPORT failed\n");
210 close (fd1);
211 close (async_server_sock);
212 return NULL;
213 }
214 #endif /* SO_REUSEPORT */
215
216
217 /* Bind sync socket to address structure. This is needed since we
218 want the sync port number on a fixed port number. The reverse
219 async channel will be at this port+1 */
220
221 memset (&myaddr_sync, 0, sizeof (struct sockaddr_in));
222 myaddr_sync.sin_family = AF_INET;
223 myaddr_sync.sin_port = htons (syncport);
224 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
225 myaddr_sync.sin_len = sizeof (struct sockaddr_in);
226 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
227
228 ret = bind (fd1, (struct sockaddr *) &myaddr_sync, size);
229 if (ret < 0)
230 {
231 fprintf (stderr, "ospf_apiclient_connect: bind sync socket failed\n");
232 close (fd1);
233 close (async_server_sock);
234 return NULL;
235 }
236
237 /* Prepare address structure for connect */
238 memcpy (&myaddr_sync.sin_addr, hp->h_addr, hp->h_length);
239 myaddr_sync.sin_family = AF_INET;
240 myaddr_sync.sin_port = htons(ospf_apiclient_getport ());
241 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
242 myaddr_sync.sin_len = sizeof (struct sockaddr_in);
243 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
244
245 /* Now establish synchronous channel with OSPF daemon */
246 ret = connect (fd1, (struct sockaddr *) &myaddr_sync,
247 sizeof (struct sockaddr_in));
248 if (ret < 0)
249 {
250 fprintf (stderr, "ospf_apiclient_connect: sync connect failed\n");
251 close (async_server_sock);
252 close (fd1);
253 return NULL;
254 }
255
256 /* Accept reverse connection */
257 peeraddrlen = sizeof (struct sockaddr_in);
258 memset (&peeraddr, 0, peeraddrlen);
259
260 fd2 =
261 accept (async_server_sock, (struct sockaddr *) &peeraddr, &peeraddrlen);
262 if (fd2 < 0)
263 {
264 fprintf (stderr, "ospf_apiclient_connect: accept async failed\n");
265 close (async_server_sock);
266 close (fd1);
267 close (fd2);
268 return NULL;
269 }
270
271 /* Server socket is not needed anymore since we are not accepting more
272 connections */
273 close (async_server_sock);
274
275 /* Create new client-side instance */
276 new = XCALLOC (MTYPE_OSPF_APICLIENT, sizeof (struct ospf_apiclient));
277
278 /* Initialize socket descriptors for sync and async channels */
279 new->fd_sync = fd1;
280 new->fd_async = fd2;
281
282 return new;
283 }
284
285 int
286 ospf_apiclient_close (struct ospf_apiclient *oclient)
287 {
288
289 if (oclient->fd_sync >= 0)
290 {
291 close (oclient->fd_sync);
292 }
293
294 if (oclient->fd_async >= 0)
295 {
296 close (oclient->fd_async);
297 }
298
299 /* Free client structure */
300 XFREE (MTYPE_OSPF_APICLIENT, oclient);
301 return 0;
302 }
303
304 /* -----------------------------------------------------------
305 * Followings are functions to send a request to OSPFd
306 * -----------------------------------------------------------
307 */
308
309 /* Send synchronous request, wait for reply */
310 static int
311 ospf_apiclient_send_request (struct ospf_apiclient *oclient, struct msg *msg)
312 {
313 u_int32_t reqseq;
314 struct msg_reply *msgreply;
315 int rc;
316
317 /* NB: Given "msg" is freed inside this function. */
318
319 /* Remember the sequence number of the request */
320 reqseq = ntohl (msg->hdr.msgseq);
321
322 /* Write message to OSPFd */
323 rc = msg_write (oclient->fd_sync, msg);
324 msg_free (msg);
325
326 if (rc < 0)
327 {
328 return -1;
329 }
330
331 /* Wait for reply *//* NB: New "msg" is allocated by "msg_read()". */
332 msg = msg_read (oclient->fd_sync);
333 if (!msg)
334 return -1;
335
336 assert (msg->hdr.msgtype == MSG_REPLY);
337 assert (ntohl (msg->hdr.msgseq) == reqseq);
338
339 msgreply = (struct msg_reply *) STREAM_DATA (msg->s);
340 rc = msgreply->errcode;
341 msg_free (msg);
342
343 return rc;
344 }
345
346
347 /* -----------------------------------------------------------
348 * Helper functions
349 * -----------------------------------------------------------
350 */
351
352 static u_int32_t
353 ospf_apiclient_get_seqnr (void)
354 {
355 static u_int32_t seqnr = MIN_SEQ;
356 u_int32_t tmp;
357
358 tmp = seqnr;
359 /* Increment sequence number */
360 if (seqnr < MAX_SEQ)
361 {
362 seqnr++;
363 }
364 else
365 {
366 seqnr = MIN_SEQ;
367 }
368 return tmp;
369 }
370
371 /* -----------------------------------------------------------
372 * API to access OSPF daemon by client applications.
373 * -----------------------------------------------------------
374 */
375
376 /*
377 * Synchronous request to register opaque type.
378 */
379 int
380 ospf_apiclient_register_opaque_type (struct ospf_apiclient *cl,
381 u_char ltype, u_char otype)
382 {
383 struct msg *msg;
384 int rc;
385
386 /* just put 1 as a sequence number. */
387 msg = new_msg_register_opaque_type (ospf_apiclient_get_seqnr (),
388 ltype, otype);
389 if (!msg)
390 {
391 fprintf (stderr, "new_msg_register_opaque_type failed\n");
392 return -1;
393 }
394
395 rc = ospf_apiclient_send_request (cl, msg);
396 return rc;
397 }
398
399 /*
400 * Synchronous request to synchronize with OSPF's LSDB.
401 * Two steps required: register_event in order to get
402 * dynamic updates and LSDB_Sync.
403 */
404 int
405 ospf_apiclient_sync_lsdb (struct ospf_apiclient *oclient)
406 {
407 struct msg *msg;
408 int rc;
409 struct lsa_filter_type filter;
410
411 filter.typemask = 0xFFFF; /* all LSAs */
412 filter.origin = ANY_ORIGIN;
413 filter.num_areas = 0; /* all Areas. */
414
415 msg = new_msg_register_event (ospf_apiclient_get_seqnr (), &filter);
416 if (!msg)
417 {
418 fprintf (stderr, "new_msg_register_event failed\n");
419 return -1;
420 }
421 rc = ospf_apiclient_send_request (oclient, msg);
422
423 if (rc != 0)
424 goto out;
425
426 msg = new_msg_sync_lsdb (ospf_apiclient_get_seqnr (), &filter);
427 if (!msg)
428 {
429 fprintf (stderr, "new_msg_sync_lsdb failed\n");
430 return -1;
431 }
432 rc = ospf_apiclient_send_request (oclient, msg);
433
434 out:
435 return rc;
436 }
437
438 /*
439 * Synchronous request to originate or update an LSA.
440 */
441
442 int
443 ospf_apiclient_lsa_originate (struct ospf_apiclient *oclient,
444 struct in_addr ifaddr,
445 struct in_addr area_id,
446 u_char lsa_type,
447 u_char opaque_type, u_int32_t opaque_id,
448 void *opaquedata, int opaquelen)
449 {
450 struct msg *msg;
451 int rc;
452 u_char buf[OSPF_MAX_LSA_SIZE];
453 struct lsa_header *lsah;
454 u_int32_t tmp;
455
456
457 /* We can only originate opaque LSAs */
458 if (!IS_OPAQUE_LSA (lsa_type))
459 {
460 fprintf (stderr, "Cannot originate non-opaque LSA type %d\n", lsa_type);
461 return OSPF_API_ILLEGALLSATYPE;
462 }
463
464 /* Make a new LSA from parameters */
465 lsah = (struct lsa_header *) buf;
466 lsah->ls_age = 0;
467 lsah->options = 0;
468 lsah->type = lsa_type;
469
470 tmp = SET_OPAQUE_LSID (opaque_type, opaque_id);
471 lsah->id.s_addr = htonl (tmp);
472 lsah->adv_router.s_addr = 0;
473 lsah->ls_seqnum = 0;
474 lsah->checksum = 0;
475 lsah->length = htons (sizeof (struct lsa_header) + opaquelen);
476
477 memcpy (((u_char *) lsah) + sizeof (struct lsa_header), opaquedata,
478 opaquelen);
479
480 msg = new_msg_originate_request (ospf_apiclient_get_seqnr (),
481 ifaddr, area_id, lsah);
482 if (!msg)
483 {
484 fprintf (stderr, "new_msg_originate_request failed\n");
485 return OSPF_API_NOMEMORY;
486 }
487
488 rc = ospf_apiclient_send_request (oclient, msg);
489 return rc;
490 }
491
492 int
493 ospf_apiclient_lsa_delete (struct ospf_apiclient *oclient,
494 struct in_addr area_id, u_char lsa_type,
495 u_char opaque_type, u_int32_t opaque_id)
496 {
497 struct msg *msg;
498 int rc;
499
500 /* Only opaque LSA can be deleted */
501 if (!IS_OPAQUE_LSA (lsa_type))
502 {
503 fprintf (stderr, "Cannot delete non-opaque LSA type %d\n", lsa_type);
504 return OSPF_API_ILLEGALLSATYPE;
505 }
506
507 /* opaque_id is in host byte order and will be converted
508 * to network byte order by new_msg_delete_request */
509 msg = new_msg_delete_request (ospf_apiclient_get_seqnr (),
510 area_id, lsa_type, opaque_type, opaque_id);
511
512 rc = ospf_apiclient_send_request (oclient, msg);
513 return rc;
514 }
515
516 /* -----------------------------------------------------------
517 * Followings are handlers for messages from OSPF daemon
518 * -----------------------------------------------------------
519 */
520
521 static void
522 ospf_apiclient_handle_ready (struct ospf_apiclient *oclient, struct msg *msg)
523 {
524 struct msg_ready_notify *r;
525 r = (struct msg_ready_notify *) STREAM_DATA (msg->s);
526
527 /* Invoke registered callback function. */
528 if (oclient->ready_notify)
529 {
530 (oclient->ready_notify) (r->lsa_type, r->opaque_type, r->addr);
531 }
532 }
533
534 static void
535 ospf_apiclient_handle_new_if (struct ospf_apiclient *oclient, struct msg *msg)
536 {
537 struct msg_new_if *n;
538 n = (struct msg_new_if *) STREAM_DATA (msg->s);
539
540 /* Invoke registered callback function. */
541 if (oclient->new_if)
542 {
543 (oclient->new_if) (n->ifaddr, n->area_id);
544 }
545 }
546
547 static void
548 ospf_apiclient_handle_del_if (struct ospf_apiclient *oclient, struct msg *msg)
549 {
550 struct msg_del_if *d;
551 d = (struct msg_del_if *) STREAM_DATA (msg->s);
552
553 /* Invoke registered callback function. */
554 if (oclient->del_if)
555 {
556 (oclient->del_if) (d->ifaddr);
557 }
558 }
559
560 static void
561 ospf_apiclient_handle_ism_change (struct ospf_apiclient *oclient,
562 struct msg *msg)
563 {
564 struct msg_ism_change *m;
565 m = (struct msg_ism_change *) STREAM_DATA (msg->s);
566
567 /* Invoke registered callback function. */
568 if (oclient->ism_change)
569 {
570 (oclient->ism_change) (m->ifaddr, m->area_id, m->status);
571 }
572
573 }
574
575 static void
576 ospf_apiclient_handle_nsm_change (struct ospf_apiclient *oclient,
577 struct msg *msg)
578 {
579 struct msg_nsm_change *m;
580 m = (struct msg_nsm_change *) STREAM_DATA (msg->s);
581
582 /* Invoke registered callback function. */
583 if (oclient->nsm_change)
584 {
585 (oclient->nsm_change) (m->ifaddr, m->nbraddr, m->router_id, m->status);
586 }
587 }
588
589 static void
590 ospf_apiclient_handle_lsa_update (struct ospf_apiclient *oclient,
591 struct msg *msg)
592 {
593 struct msg_lsa_change_notify *cn;
594 struct lsa_header *lsa;
595 int lsalen;
596
597 cn = (struct msg_lsa_change_notify *) STREAM_DATA (msg->s);
598
599 /* Extract LSA from message */
600 lsalen = ntohs (cn->data.length);
601 lsa = XMALLOC (MTYPE_OSPF_APICLIENT, lsalen);
602 if (!lsa)
603 {
604 fprintf (stderr, "LSA update: Cannot allocate memory for LSA\n");
605 return;
606 }
607 memcpy (lsa, &(cn->data), lsalen);
608
609 /* Invoke registered update callback function */
610 if (oclient->update_notify)
611 {
612 (oclient->update_notify) (cn->ifaddr, cn->area_id,
613 cn->is_self_originated, lsa);
614 }
615
616 /* free memory allocated by ospf apiclient library */
617 XFREE (MTYPE_OSPF_APICLIENT, lsa);
618 }
619
620 static void
621 ospf_apiclient_handle_lsa_delete (struct ospf_apiclient *oclient,
622 struct msg *msg)
623 {
624 struct msg_lsa_change_notify *cn;
625 struct lsa_header *lsa;
626 int lsalen;
627
628 cn = (struct msg_lsa_change_notify *) STREAM_DATA (msg->s);
629
630 /* Extract LSA from message */
631 lsalen = ntohs (cn->data.length);
632 lsa = XMALLOC (MTYPE_OSPF_APICLIENT, lsalen);
633 if (!lsa)
634 {
635 fprintf (stderr, "LSA delete: Cannot allocate memory for LSA\n");
636 return;
637 }
638 memcpy (lsa, &(cn->data), lsalen);
639
640 /* Invoke registered update callback function */
641 if (oclient->delete_notify)
642 {
643 (oclient->delete_notify) (cn->ifaddr, cn->area_id,
644 cn->is_self_originated, lsa);
645 }
646
647 /* free memory allocated by ospf apiclient library */
648 XFREE (MTYPE_OSPF_APICLIENT, lsa);
649 }
650
651 static void
652 ospf_apiclient_msghandle (struct ospf_apiclient *oclient, struct msg *msg)
653 {
654 /* Call message handler function. */
655 switch (msg->hdr.msgtype)
656 {
657 case MSG_READY_NOTIFY:
658 ospf_apiclient_handle_ready (oclient, msg);
659 break;
660 case MSG_NEW_IF:
661 ospf_apiclient_handle_new_if (oclient, msg);
662 break;
663 case MSG_DEL_IF:
664 ospf_apiclient_handle_del_if (oclient, msg);
665 break;
666 case MSG_ISM_CHANGE:
667 ospf_apiclient_handle_ism_change (oclient, msg);
668 break;
669 case MSG_NSM_CHANGE:
670 ospf_apiclient_handle_nsm_change (oclient, msg);
671 break;
672 case MSG_LSA_UPDATE_NOTIFY:
673 ospf_apiclient_handle_lsa_update (oclient, msg);
674 break;
675 case MSG_LSA_DELETE_NOTIFY:
676 ospf_apiclient_handle_lsa_delete (oclient, msg);
677 break;
678 default:
679 fprintf (stderr, "ospf_apiclient_read: Unknown message type: %d\n",
680 msg->hdr.msgtype);
681 break;
682 }
683 }
684
685 /* -----------------------------------------------------------
686 * Callback handler registration
687 * -----------------------------------------------------------
688 */
689
690 void
691 ospf_apiclient_register_callback (struct ospf_apiclient *oclient,
692 void (*ready_notify) (u_char lsa_type,
693 u_char opaque_type,
694 struct in_addr addr),
695 void (*new_if) (struct in_addr ifaddr,
696 struct in_addr area_id),
697 void (*del_if) (struct in_addr ifaddr),
698 void (*ism_change) (struct in_addr ifaddr,
699 struct in_addr area_id,
700 u_char status),
701 void (*nsm_change) (struct in_addr ifaddr,
702 struct in_addr nbraddr,
703 struct in_addr
704 router_id,
705 u_char status),
706 void (*update_notify) (struct in_addr
707 ifaddr,
708 struct in_addr
709 area_id,
710 u_char self_origin,
711 struct lsa_header *
712 lsa),
713 void (*delete_notify) (struct in_addr
714 ifaddr,
715 struct in_addr
716 area_id,
717 u_char self_origin,
718 struct lsa_header *
719 lsa))
720 {
721 assert (oclient);
722 assert (update_notify);
723
724 /* Register callback function */
725 oclient->ready_notify = ready_notify;
726 oclient->new_if = new_if;
727 oclient->del_if = del_if;
728 oclient->ism_change = ism_change;
729 oclient->nsm_change = nsm_change;
730 oclient->update_notify = update_notify;
731 oclient->delete_notify = delete_notify;
732 }
733
734 /* -----------------------------------------------------------
735 * Asynchronous message handling
736 * -----------------------------------------------------------
737 */
738
739 int
740 ospf_apiclient_handle_async (struct ospf_apiclient *oclient)
741 {
742 struct msg *msg;
743
744 /* Get a message */
745 msg = msg_read (oclient->fd_async);
746
747 if (!msg)
748 {
749 /* Connection broke down */
750 return -1;
751 }
752
753 /* Handle message */
754 ospf_apiclient_msghandle (oclient, msg);
755
756 /* Don't forget to free this message */
757 msg_free (msg);
758
759 return 0;
760 }