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