6ef713fb728602e338aaa6317d9a43c4bf9094e1
[olsrd.git] / lib / quagga / src / client.c
1 /*
2  * The olsr.org Optimized Link-State Routing daemon (olsrd)
3  *
4  * (c) by the OLSR project
5  *
6  * See our Git repository to find out who worked on this file
7  * and thus is a copyright holder on it.
8  *
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * * Redistributions of source code must retain the above copyright
16  *   notice, this list of conditions and the following disclaimer.
17  * * Redistributions in binary form must reproduce the above copyright
18  *   notice, this list of conditions and the following disclaimer in
19  *   the documentation and/or other materials provided with the
20  *   distribution.
21  * * Neither the name of olsr.org, olsrd nor the names of its
22  *   contributors may be used to endorse or promote products derived
23  *   from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  *
38  * Visit http://www.olsr.org for more information.
39  *
40  * If you find this software useful feel free to make a donation
41  * to the project. For more information see the website or contact
42  * the copyright holders.
43  *
44  */
45
46 /* -------------------------------------------------------------------------
47  * File               : client.c
48  * Description        : zebra client functions
49  * ------------------------------------------------------------------------- */
50
51 #define HAVE_SOCKLEN_T
52
53 #include <sys/un.h>
54 #include <unistd.h>
55 #include <fcntl.h>
56 #include "defs.h"
57 #include "olsr.h"
58 #include "log.h"
59 #include "routing_table.h"
60
61 #include "common.h"
62 #include "quagga.h"
63 #include "packet.h"
64 #include "client.h"
65
66 static void *my_realloc(void *, size_t, const char *);
67 static void zclient_connect(void);
68
69 static void *
70 my_realloc(void *buf, size_t s, const char *c)
71 {
72
73   buf = realloc(buf, s);
74   if (!buf) {
75     char buf2[1024];
76     snprintf(buf2, sizeof(buf2), "QUAGGA: Out of memory (%s): %s", c, strerror(errno));
77     olsr_exit(buf2, EXIT_FAILURE);
78   }
79
80   return buf;
81 }
82
83 static void
84 zclient_connect(void)
85 {
86   int ret;
87
88   union {
89     struct sockaddr_in sin;
90     struct sockaddr_un sun;
91   } sockaddr;
92
93   if (close(zebra.sock) < 0)
94     olsr_exit("QUAGGA: Could not close socket", EXIT_FAILURE);
95
96   zebra.sock = socket(zebra.port ? AF_INET : AF_UNIX, SOCK_STREAM, 0);
97
98   if (zebra.sock < 0)
99     olsr_exit("QUAGGA: Could not create socket", EXIT_FAILURE);
100
101   memset(&sockaddr, 0, sizeof sockaddr);
102
103   if (zebra.port) {
104     sockaddr.sin.sin_family = AF_INET;
105     sockaddr.sin.sin_port = htons(zebra.port);
106     sockaddr.sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
107     ret = connect(zebra.sock, (struct sockaddr *)&sockaddr.sin, sizeof sockaddr.sin);
108   } else {
109     sockaddr.sun.sun_family = AF_UNIX;
110     strscpy(sockaddr.sun.sun_path, zebra.sockpath, sizeof(sockaddr.sun.sun_path));
111     ret = connect(zebra.sock, (struct sockaddr *)&sockaddr.sun, sizeof sockaddr.sun);
112   }
113
114   if (ret < 0)
115     zebra.status &= ~STATUS_CONNECTED;
116   else
117     zebra.status |= STATUS_CONNECTED;
118
119 }
120
121 void
122 zclient_reconnect(void)
123 {
124   struct rt_entry *tmp;
125
126   zclient_connect();
127   if (!(zebra.status & STATUS_CONNECTED))
128     return;                     // try again next time
129
130   zebra_hello(ZEBRA_HELLO);
131   if (zebra.options & OPTION_EXPORT) {
132     OLSR_FOR_ALL_RT_ENTRIES(tmp) {
133       zebra_addroute(tmp);
134     }
135     OLSR_FOR_ALL_RT_ENTRIES_END(tmp);
136   }
137   zebra_redistribute(ZEBRA_REDISTRIBUTE_ADD);
138
139 }
140
141 int
142 zclient_write(unsigned char *options)
143 {
144   unsigned char *pnt;
145   uint16_t len;
146   int ret;
147
148   if (!(zebra.status & STATUS_CONNECTED))
149     return 0;
150
151   pnt = options;
152   memcpy(&len, pnt, sizeof len);
153
154   len = ntohs(len);
155
156   do {
157     ret = write(zebra.sock, pnt, len);
158     if (ret < 0) {
159       if ((errno == EINTR) || (errno == EAGAIN)) {
160         errno = 0;
161         ret = 0;
162         continue;
163       } else {
164         OLSR_PRINTF(1, "(QUAGGA) Disconnected from zebra.\n");
165         zebra.status &= ~STATUS_CONNECTED;
166         /* TODO: Remove HNAs added from redistribution */
167         free(options);
168         return -1;
169       }
170     }
171     pnt = pnt + ret;
172   }
173   while ((len -= ret));
174   free(options);
175
176   return 0;
177 }
178
179 unsigned char *
180 zclient_read(ssize_t * size)
181 {
182   unsigned char *buf;
183   ssize_t bytes, bufsize;
184   uint16_t length, offset;
185   int sockstatus;
186
187   /* initialize variables */
188   buf = NULL;
189   offset = 0;
190   *size = 0;
191   bufsize = 0;
192
193   /* save socket status and set non-blocking for read */
194   sockstatus = fcntl(zebra.sock, F_GETFL);
195   (void)fcntl(zebra.sock, F_SETFL, sockstatus|O_NONBLOCK);
196
197   /* read whole packages */
198   do {
199
200     /* (re)allocate buffer */
201     if (*size == bufsize) {
202       ssize_t start = bufsize;
203       bufsize += BUFSIZE;
204       buf = my_realloc(buf, bufsize, "grow read buffer");
205       memset(&buf[start], 0, BUFSIZE);
206     }
207
208     /* read from socket */
209     bytes = read(zebra.sock, buf + *size, bufsize - *size);
210     /* handle broken packet */
211     if (!bytes) {
212       /* restore socket status */
213       (void)fcntl(zebra.sock, F_SETFL, sockstatus);
214
215       free(buf);
216       return NULL;
217     }
218     /* handle no data available */
219     if (bytes < 0) {
220       /* handle disconnect */
221       if (errno != EAGAIN) {    // oops - we got disconnected
222         OLSR_PRINTF(1, "(QUAGGA) Disconnected from zebra\n");
223         zebra.status &= ~STATUS_CONNECTED;
224         /* TODO: Remove HNAs added from redistribution */
225       }
226
227       /* restore socket status */
228       (void)fcntl(zebra.sock, F_SETFL, sockstatus);
229
230       free(buf);
231       return NULL;
232     }
233
234     *size += bytes;
235
236     /* detect zebra packet fragmentation */
237     do {
238       memcpy(&length, buf + offset, sizeof(length));
239       length = ntohs(length);
240       offset += length;
241     }
242     while (*size >= (ssize_t) (offset + sizeof(length)));
243     /* set blocking socket on fragmented packet */
244     if (*size != offset)
245       (void)fcntl(zebra.sock, F_SETFL, sockstatus);
246
247   }
248   while (*size != offset);
249
250   /* restore socket status */
251   (void)fcntl(zebra.sock, F_SETFL, sockstatus);
252
253   return buf;
254 }
255
256 /*
257  * Local Variables:
258  * c-basic-offset: 2
259  * indent-tabs-mode: nil
260  * End:
261  */