]> git.proxmox.com Git - mirror_frr.git/blob - ospfclient/ospf_apiclient.c
Merge branch 'frr/pull/546' ("bgpd: resolve issue with sending vpn labels")
[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 fprintf (stderr,
187 "ospf_apiclient_connect: creating sync socket failed\n");
188 return NULL;
189 }
190
191
192 /* Reuse addr and port */
193 ret = setsockopt (fd1, SOL_SOCKET,
194 SO_REUSEADDR, (void *) &on, sizeof (on));
195 if (ret < 0)
196 {
197 fprintf (stderr, "ospf_apiclient_connect: SO_REUSEADDR failed\n");
198 close (fd1);
199 return NULL;
200 }
201
202 #ifdef SO_REUSEPORT
203 ret = setsockopt (fd1, SOL_SOCKET, SO_REUSEPORT,
204 (void *) &on, sizeof (on));
205 if (ret < 0)
206 {
207 fprintf (stderr, "ospf_apiclient_connect: SO_REUSEPORT failed\n");
208 close (fd1);
209 return NULL;
210 }
211 #endif /* SO_REUSEPORT */
212
213
214 /* Bind sync socket to address structure. This is needed since we
215 want the sync port number on a fixed port number. The reverse
216 async channel will be at this port+1 */
217
218 memset (&myaddr_sync, 0, sizeof (struct sockaddr_in));
219 myaddr_sync.sin_family = AF_INET;
220 myaddr_sync.sin_port = htons (syncport);
221 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
222 myaddr_sync.sin_len = sizeof (struct sockaddr_in);
223 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
224
225 ret = bind (fd1, (struct sockaddr *) &myaddr_sync, size);
226 if (ret < 0)
227 {
228 fprintf (stderr, "ospf_apiclient_connect: bind sync socket failed\n");
229 close (fd1);
230 return NULL;
231 }
232
233 /* Prepare address structure for connect */
234 memcpy (&myaddr_sync.sin_addr, hp->h_addr, hp->h_length);
235 myaddr_sync.sin_family = AF_INET;
236 myaddr_sync.sin_port = htons(ospf_apiclient_getport ());
237 #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
238 myaddr_sync.sin_len = sizeof (struct sockaddr_in);
239 #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
240
241 /* Now establish synchronous channel with OSPF daemon */
242 ret = connect (fd1, (struct sockaddr *) &myaddr_sync,
243 sizeof (struct sockaddr_in));
244 if (ret < 0)
245 {
246 fprintf (stderr, "ospf_apiclient_connect: sync connect failed\n");
247 close (async_server_sock);
248 close (fd1);
249 return NULL;
250 }
251
252 /* Accept reverse connection */
253 peeraddrlen = sizeof (struct sockaddr_in);
254 memset (&peeraddr, 0, peeraddrlen);
255
256 fd2 =
257 accept (async_server_sock, (struct sockaddr *) &peeraddr, &peeraddrlen);
258 if (fd2 < 0)
259 {
260 fprintf (stderr, "ospf_apiclient_connect: accept async failed\n");
261 close (async_server_sock);
262 close (fd1);
263 return NULL;
264 }
265
266 /* Server socket is not needed anymore since we are not accepting more
267 connections */
268 close (async_server_sock);
269
270 /* Create new client-side instance */
271 new = XCALLOC (MTYPE_OSPF_APICLIENT, sizeof (struct ospf_apiclient));
272
273 /* Initialize socket descriptors for sync and async channels */
274 new->fd_sync = fd1;
275 new->fd_async = fd2;
276
277 return new;
278 }
279
280 int
281 ospf_apiclient_close (struct ospf_apiclient *oclient)
282 {
283
284 if (oclient->fd_sync >= 0)
285 {
286 close (oclient->fd_sync);
287 }
288
289 if (oclient->fd_async >= 0)
290 {
291 close (oclient->fd_async);
292 }
293
294 /* Free client structure */
295 XFREE (MTYPE_OSPF_APICLIENT, oclient);
296 return 0;
297 }
298
299 /* -----------------------------------------------------------
300 * Followings are functions to send a request to OSPFd
301 * -----------------------------------------------------------
302 */
303
304 /* Send synchronous request, wait for reply */
305 static int
306 ospf_apiclient_send_request (struct ospf_apiclient *oclient, struct msg *msg)
307 {
308 u_int32_t reqseq;
309 struct msg_reply *msgreply;
310 int rc;
311
312 /* NB: Given "msg" is freed inside this function. */
313
314 /* Remember the sequence number of the request */
315 reqseq = ntohl (msg->hdr.msgseq);
316
317 /* Write message to OSPFd */
318 rc = msg_write (oclient->fd_sync, msg);
319 msg_free (msg);
320
321 if (rc < 0)
322 {
323 return -1;
324 }
325
326 /* Wait for reply *//* NB: New "msg" is allocated by "msg_read()". */
327 msg = msg_read (oclient->fd_sync);
328 if (!msg)
329 return -1;
330
331 assert (msg->hdr.msgtype == MSG_REPLY);
332 assert (ntohl (msg->hdr.msgseq) == reqseq);
333
334 msgreply = (struct msg_reply *) STREAM_DATA (msg->s);
335 rc = msgreply->errcode;
336 msg_free (msg);
337
338 return rc;
339 }
340
341
342 /* -----------------------------------------------------------
343 * Helper functions
344 * -----------------------------------------------------------
345 */
346
347 static u_int32_t
348 ospf_apiclient_get_seqnr (void)
349 {
350 static u_int32_t seqnr = MIN_SEQ;
351 u_int32_t tmp;
352
353 tmp = seqnr;
354 /* Increment sequence number */
355 if (seqnr < MAX_SEQ)
356 {
357 seqnr++;
358 }
359 else
360 {
361 seqnr = MIN_SEQ;
362 }
363 return tmp;
364 }
365
366 /* -----------------------------------------------------------
367 * API to access OSPF daemon by client applications.
368 * -----------------------------------------------------------
369 */
370
371 /*
372 * Synchronous request to register opaque type.
373 */
374 int
375 ospf_apiclient_register_opaque_type (struct ospf_apiclient *cl,
376 u_char ltype, u_char otype)
377 {
378 struct msg *msg;
379 int rc;
380
381 /* just put 1 as a sequence number. */
382 msg = new_msg_register_opaque_type (ospf_apiclient_get_seqnr (),
383 ltype, otype);
384 if (!msg)
385 {
386 fprintf (stderr, "new_msg_register_opaque_type failed\n");
387 return -1;
388 }
389
390 rc = ospf_apiclient_send_request (cl, msg);
391 return rc;
392 }
393
394 /*
395 * Synchronous request to synchronize with OSPF's LSDB.
396 * Two steps required: register_event in order to get
397 * dynamic updates and LSDB_Sync.
398 */
399 int
400 ospf_apiclient_sync_lsdb (struct ospf_apiclient *oclient)
401 {
402 struct msg *msg;
403 int rc;
404 struct lsa_filter_type filter;
405
406 filter.typemask = 0xFFFF; /* all LSAs */
407 filter.origin = ANY_ORIGIN;
408 filter.num_areas = 0; /* all Areas. */
409
410 msg = new_msg_register_event (ospf_apiclient_get_seqnr (), &filter);
411 if (!msg)
412 {
413 fprintf (stderr, "new_msg_register_event failed\n");
414 return -1;
415 }
416 rc = ospf_apiclient_send_request (oclient, msg);
417
418 if (rc != 0)
419 goto out;
420
421 msg = new_msg_sync_lsdb (ospf_apiclient_get_seqnr (), &filter);
422 if (!msg)
423 {
424 fprintf (stderr, "new_msg_sync_lsdb failed\n");
425 return -1;
426 }
427 rc = ospf_apiclient_send_request (oclient, msg);
428
429 out:
430 return rc;
431 }
432
433 /*
434 * Synchronous request to originate or update an LSA.
435 */
436
437 int
438 ospf_apiclient_lsa_originate (struct ospf_apiclient *oclient,
439 struct in_addr ifaddr,
440 struct in_addr area_id,
441 u_char lsa_type,
442 u_char opaque_type, u_int32_t opaque_id,
443 void *opaquedata, int opaquelen)
444 {
445 struct msg *msg;
446 int rc;
447 u_char buf[OSPF_MAX_LSA_SIZE];
448 struct lsa_header *lsah;
449 u_int32_t tmp;
450
451
452 /* We can only originate opaque LSAs */
453 if (!IS_OPAQUE_LSA (lsa_type))
454 {
455 fprintf (stderr, "Cannot originate non-opaque LSA type %d\n", lsa_type);
456 return OSPF_API_ILLEGALLSATYPE;
457 }
458
459 /* Make a new LSA from parameters */
460 lsah = (struct lsa_header *) buf;
461 lsah->ls_age = 0;
462 lsah->options = 0;
463 lsah->type = lsa_type;
464
465 tmp = SET_OPAQUE_LSID (opaque_type, opaque_id);
466 lsah->id.s_addr = htonl (tmp);
467 lsah->adv_router.s_addr = 0;
468 lsah->ls_seqnum = 0;
469 lsah->checksum = 0;
470 lsah->length = htons (sizeof (struct lsa_header) + opaquelen);
471
472 memcpy (((u_char *) lsah) + sizeof (struct lsa_header), opaquedata,
473 opaquelen);
474
475 msg = new_msg_originate_request (ospf_apiclient_get_seqnr (),
476 ifaddr, area_id, lsah);
477 if (!msg)
478 {
479 fprintf (stderr, "new_msg_originate_request failed\n");
480 return OSPF_API_NOMEMORY;
481 }
482
483 rc = ospf_apiclient_send_request (oclient, msg);
484 return rc;
485 }
486
487 int
488 ospf_apiclient_lsa_delete (struct ospf_apiclient *oclient,
489 struct in_addr area_id, u_char lsa_type,
490 u_char opaque_type, u_int32_t opaque_id)
491 {
492 struct msg *msg;
493 int rc;
494
495 /* Only opaque LSA can be deleted */
496 if (!IS_OPAQUE_LSA (lsa_type))
497 {
498 fprintf (stderr, "Cannot delete non-opaque LSA type %d\n", lsa_type);
499 return OSPF_API_ILLEGALLSATYPE;
500 }
501
502 /* opaque_id is in host byte order and will be converted
503 * to network byte order by new_msg_delete_request */
504 msg = new_msg_delete_request (ospf_apiclient_get_seqnr (),
505 area_id, lsa_type, opaque_type, opaque_id);
506
507 rc = ospf_apiclient_send_request (oclient, msg);
508 return rc;
509 }
510
511 /* -----------------------------------------------------------
512 * Followings are handlers for messages from OSPF daemon
513 * -----------------------------------------------------------
514 */
515
516 static void
517 ospf_apiclient_handle_ready (struct ospf_apiclient *oclient, struct msg *msg)
518 {
519 struct msg_ready_notify *r;
520 r = (struct msg_ready_notify *) STREAM_DATA (msg->s);
521
522 /* Invoke registered callback function. */
523 if (oclient->ready_notify)
524 {
525 (oclient->ready_notify) (r->lsa_type, r->opaque_type, r->addr);
526 }
527 }
528
529 static void
530 ospf_apiclient_handle_new_if (struct ospf_apiclient *oclient, struct msg *msg)
531 {
532 struct msg_new_if *n;
533 n = (struct msg_new_if *) STREAM_DATA (msg->s);
534
535 /* Invoke registered callback function. */
536 if (oclient->new_if)
537 {
538 (oclient->new_if) (n->ifaddr, n->area_id);
539 }
540 }
541
542 static void
543 ospf_apiclient_handle_del_if (struct ospf_apiclient *oclient, struct msg *msg)
544 {
545 struct msg_del_if *d;
546 d = (struct msg_del_if *) STREAM_DATA (msg->s);
547
548 /* Invoke registered callback function. */
549 if (oclient->del_if)
550 {
551 (oclient->del_if) (d->ifaddr);
552 }
553 }
554
555 static void
556 ospf_apiclient_handle_ism_change (struct ospf_apiclient *oclient,
557 struct msg *msg)
558 {
559 struct msg_ism_change *m;
560 m = (struct msg_ism_change *) STREAM_DATA (msg->s);
561
562 /* Invoke registered callback function. */
563 if (oclient->ism_change)
564 {
565 (oclient->ism_change) (m->ifaddr, m->area_id, m->status);
566 }
567
568 }
569
570 static void
571 ospf_apiclient_handle_nsm_change (struct ospf_apiclient *oclient,
572 struct msg *msg)
573 {
574 struct msg_nsm_change *m;
575 m = (struct msg_nsm_change *) STREAM_DATA (msg->s);
576
577 /* Invoke registered callback function. */
578 if (oclient->nsm_change)
579 {
580 (oclient->nsm_change) (m->ifaddr, m->nbraddr, m->router_id, m->status);
581 }
582 }
583
584 static void
585 ospf_apiclient_handle_lsa_update (struct ospf_apiclient *oclient,
586 struct msg *msg)
587 {
588 struct msg_lsa_change_notify *cn;
589 struct lsa_header *lsa;
590 int lsalen;
591
592 cn = (struct msg_lsa_change_notify *) STREAM_DATA (msg->s);
593
594 /* Extract LSA from message */
595 lsalen = ntohs (cn->data.length);
596 lsa = XMALLOC (MTYPE_OSPF_APICLIENT, lsalen);
597 if (!lsa)
598 {
599 fprintf (stderr, "LSA update: Cannot allocate memory for LSA\n");
600 return;
601 }
602 memcpy (lsa, &(cn->data), lsalen);
603
604 /* Invoke registered update callback function */
605 if (oclient->update_notify)
606 {
607 (oclient->update_notify) (cn->ifaddr, cn->area_id,
608 cn->is_self_originated, lsa);
609 }
610
611 /* free memory allocated by ospf apiclient library */
612 XFREE (MTYPE_OSPF_APICLIENT, lsa);
613 }
614
615 static void
616 ospf_apiclient_handle_lsa_delete (struct ospf_apiclient *oclient,
617 struct msg *msg)
618 {
619 struct msg_lsa_change_notify *cn;
620 struct lsa_header *lsa;
621 int lsalen;
622
623 cn = (struct msg_lsa_change_notify *) STREAM_DATA (msg->s);
624
625 /* Extract LSA from message */
626 lsalen = ntohs (cn->data.length);
627 lsa = XMALLOC (MTYPE_OSPF_APICLIENT, lsalen);
628 if (!lsa)
629 {
630 fprintf (stderr, "LSA delete: Cannot allocate memory for LSA\n");
631 return;
632 }
633 memcpy (lsa, &(cn->data), lsalen);
634
635 /* Invoke registered update callback function */
636 if (oclient->delete_notify)
637 {
638 (oclient->delete_notify) (cn->ifaddr, cn->area_id,
639 cn->is_self_originated, lsa);
640 }
641
642 /* free memory allocated by ospf apiclient library */
643 XFREE (MTYPE_OSPF_APICLIENT, lsa);
644 }
645
646 static void
647 ospf_apiclient_msghandle (struct ospf_apiclient *oclient, struct msg *msg)
648 {
649 /* Call message handler function. */
650 switch (msg->hdr.msgtype)
651 {
652 case MSG_READY_NOTIFY:
653 ospf_apiclient_handle_ready (oclient, msg);
654 break;
655 case MSG_NEW_IF:
656 ospf_apiclient_handle_new_if (oclient, msg);
657 break;
658 case MSG_DEL_IF:
659 ospf_apiclient_handle_del_if (oclient, msg);
660 break;
661 case MSG_ISM_CHANGE:
662 ospf_apiclient_handle_ism_change (oclient, msg);
663 break;
664 case MSG_NSM_CHANGE:
665 ospf_apiclient_handle_nsm_change (oclient, msg);
666 break;
667 case MSG_LSA_UPDATE_NOTIFY:
668 ospf_apiclient_handle_lsa_update (oclient, msg);
669 break;
670 case MSG_LSA_DELETE_NOTIFY:
671 ospf_apiclient_handle_lsa_delete (oclient, msg);
672 break;
673 default:
674 fprintf (stderr, "ospf_apiclient_read: Unknown message type: %d\n",
675 msg->hdr.msgtype);
676 break;
677 }
678 }
679
680 /* -----------------------------------------------------------
681 * Callback handler registration
682 * -----------------------------------------------------------
683 */
684
685 void
686 ospf_apiclient_register_callback (struct ospf_apiclient *oclient,
687 void (*ready_notify) (u_char lsa_type,
688 u_char opaque_type,
689 struct in_addr addr),
690 void (*new_if) (struct in_addr ifaddr,
691 struct in_addr area_id),
692 void (*del_if) (struct in_addr ifaddr),
693 void (*ism_change) (struct in_addr ifaddr,
694 struct in_addr area_id,
695 u_char status),
696 void (*nsm_change) (struct in_addr ifaddr,
697 struct in_addr nbraddr,
698 struct in_addr
699 router_id,
700 u_char status),
701 void (*update_notify) (struct in_addr
702 ifaddr,
703 struct in_addr
704 area_id,
705 u_char self_origin,
706 struct lsa_header *
707 lsa),
708 void (*delete_notify) (struct in_addr
709 ifaddr,
710 struct in_addr
711 area_id,
712 u_char self_origin,
713 struct lsa_header *
714 lsa))
715 {
716 assert (oclient);
717 assert (update_notify);
718
719 /* Register callback function */
720 oclient->ready_notify = ready_notify;
721 oclient->new_if = new_if;
722 oclient->del_if = del_if;
723 oclient->ism_change = ism_change;
724 oclient->nsm_change = nsm_change;
725 oclient->update_notify = update_notify;
726 oclient->delete_notify = delete_notify;
727 }
728
729 /* -----------------------------------------------------------
730 * Asynchronous message handling
731 * -----------------------------------------------------------
732 */
733
734 int
735 ospf_apiclient_handle_async (struct ospf_apiclient *oclient)
736 {
737 struct msg *msg;
738
739 /* Get a message */
740 msg = msg_read (oclient->fd_async);
741
742 if (!msg)
743 {
744 /* Connection broke down */
745 return -1;
746 }
747
748 /* Handle message */
749 ospf_apiclient_msghandle (oclient, msg);
750
751 /* Don't forget to free this message */
752 msg_free (msg);
753
754 return 0;
755 }