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